--- /dev/null
+From bb47ca1b09f9e86b283d1d407f1d06c06298cf8d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 27 Apr 2025 15:41:51 -0400
+Subject: __legitimize_mnt(): check for MNT_SYNC_UMOUNT should be under
+ mount_lock
+
+From: Al Viro <viro@zeniv.linux.org.uk>
+
+[ Upstream commit 250cf3693060a5f803c5f1ddc082bb06b16112a9 ]
+
+... or we risk stealing final mntput from sync umount - raising mnt_count
+after umount(2) has verified that victim is not busy, but before it
+has set MNT_SYNC_UMOUNT; in that case __legitimize_mnt() doesn't see
+that it's safe to quietly undo mnt_count increment and leaves dropping
+the reference to caller, where it'll be a full-blown mntput().
+
+Check under mount_lock is needed; leaving the current one done before
+taking that makes no sense - it's nowhere near common enough to bother
+with.
+
+Reviewed-by: Christian Brauner <brauner@kernel.org>
+Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/namespace.c | 6 +-----
+ 1 file changed, 1 insertion(+), 5 deletions(-)
+
+diff --git a/fs/namespace.c b/fs/namespace.c
+index 5b84e29613fe4..1d950974d67ee 100644
+--- a/fs/namespace.c
++++ b/fs/namespace.c
+@@ -781,12 +781,8 @@ int __legitimize_mnt(struct vfsmount *bastard, unsigned seq)
+ smp_mb(); // see mntput_no_expire() and do_umount()
+ if (likely(!read_seqretry(&mount_lock, seq)))
+ return 0;
+- if (bastard->mnt_flags & MNT_SYNC_UMOUNT) {
+- mnt_add_count(mnt, -1);
+- return 1;
+- }
+ lock_mount_hash();
+- if (unlikely(bastard->mnt_flags & MNT_DOOMED)) {
++ if (unlikely(bastard->mnt_flags & (MNT_SYNC_UMOUNT | MNT_DOOMED))) {
+ mnt_add_count(mnt, -1);
+ unlock_mount_hash();
+ return 1;
+--
+2.39.5
+
--- /dev/null
+From ae7c837e427b3d8b084c423693b0ece0575c78fc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Feb 2025 08:18:10 -0800
+Subject: accel/amdxdna: Check interrupt register before mailbox_rx_worker
+ exits
+
+From: Lizhi Hou <lizhi.hou@amd.com>
+
+[ Upstream commit cd740b873f8f6f5f4558723241ba9c09eb36d0ba ]
+
+There is a timeout failure been found during stress tests. If the firmware
+generates a mailbox response right after driver clears the mailbox channel
+interrupt register, the hardware will not generate an interrupt for the
+response. This causes the unexpected mailbox command timeout.
+
+To handle this failure, driver checks the interrupt register before
+exiting mailbox_rx_worker(). If there is a new response, driver goes back
+to process it.
+
+Signed-off-by: Lizhi Hou <lizhi.hou@amd.com>
+Reviewed-by: Jacek Lawrynowicz <jacek.lawrynowicz@linux.intel.com>
+Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250226161810.4188334-1-lizhi.hou@amd.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/accel/amdxdna/amdxdna_mailbox.c | 17 +++++++++++++----
+ 1 file changed, 13 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/accel/amdxdna/amdxdna_mailbox.c b/drivers/accel/amdxdna/amdxdna_mailbox.c
+index e5301fac13971..2879e4149c937 100644
+--- a/drivers/accel/amdxdna/amdxdna_mailbox.c
++++ b/drivers/accel/amdxdna/amdxdna_mailbox.c
+@@ -349,8 +349,6 @@ static irqreturn_t mailbox_irq_handler(int irq, void *p)
+ trace_mbox_irq_handle(MAILBOX_NAME, irq);
+ /* Schedule a rx_work to call the callback functions */
+ queue_work(mb_chann->work_q, &mb_chann->rx_work);
+- /* Clear IOHUB register */
+- mailbox_reg_write(mb_chann, mb_chann->iohub_int_addr, 0);
+
+ return IRQ_HANDLED;
+ }
+@@ -367,6 +365,9 @@ static void mailbox_rx_worker(struct work_struct *rx_work)
+ return;
+ }
+
++again:
++ mailbox_reg_write(mb_chann, mb_chann->iohub_int_addr, 0);
++
+ while (1) {
+ /*
+ * If return is 0, keep consuming next message, until there is
+@@ -380,10 +381,18 @@ static void mailbox_rx_worker(struct work_struct *rx_work)
+ if (unlikely(ret)) {
+ MB_ERR(mb_chann, "Unexpected ret %d, disable irq", ret);
+ WRITE_ONCE(mb_chann->bad_state, true);
+- disable_irq(mb_chann->msix_irq);
+- break;
++ return;
+ }
+ }
++
++ /*
++ * The hardware will not generate interrupt if firmware creates a new
++ * response right after driver clears interrupt register. Check
++ * the interrupt register to make sure there is not any new response
++ * before exiting.
++ */
++ if (mailbox_reg_read(mb_chann, mb_chann->iohub_int_addr))
++ goto again;
+ }
+
+ int xdna_mailbox_send_msg(struct mailbox_channel *mb_chann,
+--
+2.39.5
+
--- /dev/null
+From 0b21199630538e476b7cba82f81a93af065a3677 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 24 Jan 2025 09:35:36 -0800
+Subject: accel/amdxdna: Refactor hardware context destroy routine
+
+From: Lizhi Hou <lizhi.hou@amd.com>
+
+[ Upstream commit 4fd6ca90fc7f509977585d39885f21b2911123f3 ]
+
+It is required by firmware to wait up to 2 seconds for pending commands
+before sending the destroy hardware context command. After 2 seconds
+wait, if there are still pending commands, driver needs to cancel them.
+
+So the context destroy steps need to be:
+ 1. Stop drm scheduler. (drm_sched_entity_destroy)
+ 2. Wait up to 2 seconds for pending commands.
+ 3. Destroy hardware context and cancel the rest pending requests.
+ 4. Wait all jobs associated with the hwctx are freed.
+ 5. Free job resources.
+
+Signed-off-by: Lizhi Hou <lizhi.hou@amd.com>
+Reviewed-by: Jeffrey Hugo <quic_jhugo@quicinc.com>
+Signed-off-by: Jeffrey Hugo <quic_jhugo@quicinc.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250124173536.148676-1-lizhi.hou@amd.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/accel/amdxdna/aie2_ctx.c | 29 ++++++++++++++++-------------
+ drivers/accel/amdxdna/amdxdna_ctx.c | 2 ++
+ drivers/accel/amdxdna/amdxdna_ctx.h | 3 +++
+ 3 files changed, 21 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/accel/amdxdna/aie2_ctx.c b/drivers/accel/amdxdna/aie2_ctx.c
+index 5f43db02b2404..92c768b0c9a03 100644
+--- a/drivers/accel/amdxdna/aie2_ctx.c
++++ b/drivers/accel/amdxdna/aie2_ctx.c
+@@ -34,6 +34,8 @@ static void aie2_job_release(struct kref *ref)
+
+ job = container_of(ref, struct amdxdna_sched_job, refcnt);
+ amdxdna_sched_job_cleanup(job);
++ atomic64_inc(&job->hwctx->job_free_cnt);
++ wake_up(&job->hwctx->priv->job_free_wq);
+ if (job->out_fence)
+ dma_fence_put(job->out_fence);
+ kfree(job);
+@@ -134,7 +136,8 @@ static void aie2_hwctx_wait_for_idle(struct amdxdna_hwctx *hwctx)
+ if (!fence)
+ return;
+
+- dma_fence_wait(fence, false);
++ /* Wait up to 2 seconds for fw to finish all pending requests */
++ dma_fence_wait_timeout(fence, false, msecs_to_jiffies(2000));
+ dma_fence_put(fence);
+ }
+
+@@ -616,6 +619,7 @@ int aie2_hwctx_init(struct amdxdna_hwctx *hwctx)
+ hwctx->status = HWCTX_STAT_INIT;
+ ndev = xdna->dev_handle;
+ ndev->hwctx_num++;
++ init_waitqueue_head(&priv->job_free_wq);
+
+ XDNA_DBG(xdna, "hwctx %s init completed", hwctx->name);
+
+@@ -652,25 +656,23 @@ void aie2_hwctx_fini(struct amdxdna_hwctx *hwctx)
+ xdna = hwctx->client->xdna;
+ ndev = xdna->dev_handle;
+ ndev->hwctx_num--;
+- drm_sched_wqueue_stop(&hwctx->priv->sched);
+
+- /* Now, scheduler will not send command to device. */
++ XDNA_DBG(xdna, "%s sequence number %lld", hwctx->name, hwctx->priv->seq);
++ drm_sched_entity_destroy(&hwctx->priv->entity);
++
++ aie2_hwctx_wait_for_idle(hwctx);
++
++ /* Request fw to destroy hwctx and cancel the rest pending requests */
+ aie2_release_resource(hwctx);
+
+- /*
+- * All submitted commands are aborted.
+- * Restart scheduler queues to cleanup jobs. The amdxdna_sched_job_run()
+- * will return NODEV if it is called.
+- */
+- drm_sched_wqueue_start(&hwctx->priv->sched);
++ /* Wait for all submitted jobs to be completed or canceled */
++ wait_event(hwctx->priv->job_free_wq,
++ atomic64_read(&hwctx->job_submit_cnt) ==
++ atomic64_read(&hwctx->job_free_cnt));
+
+- aie2_hwctx_wait_for_idle(hwctx);
+- drm_sched_entity_destroy(&hwctx->priv->entity);
+ drm_sched_fini(&hwctx->priv->sched);
+ aie2_ctx_syncobj_destroy(hwctx);
+
+- XDNA_DBG(xdna, "%s sequence number %lld", hwctx->name, hwctx->priv->seq);
+-
+ for (idx = 0; idx < ARRAY_SIZE(hwctx->priv->cmd_buf); idx++)
+ drm_gem_object_put(to_gobj(hwctx->priv->cmd_buf[idx]));
+ amdxdna_gem_unpin(hwctx->priv->heap);
+@@ -879,6 +881,7 @@ int aie2_cmd_submit(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job,
+ drm_gem_unlock_reservations(job->bos, job->bo_cnt, &acquire_ctx);
+
+ aie2_job_put(job);
++ atomic64_inc(&hwctx->job_submit_cnt);
+
+ return 0;
+
+diff --git a/drivers/accel/amdxdna/amdxdna_ctx.c b/drivers/accel/amdxdna/amdxdna_ctx.c
+index d11b1c83d9c3b..43442b9e273b3 100644
+--- a/drivers/accel/amdxdna/amdxdna_ctx.c
++++ b/drivers/accel/amdxdna/amdxdna_ctx.c
+@@ -220,6 +220,8 @@ int amdxdna_drm_create_hwctx_ioctl(struct drm_device *dev, void *data, struct dr
+ args->syncobj_handle = hwctx->syncobj_hdl;
+ mutex_unlock(&xdna->dev_lock);
+
++ atomic64_set(&hwctx->job_submit_cnt, 0);
++ atomic64_set(&hwctx->job_free_cnt, 0);
+ XDNA_DBG(xdna, "PID %d create HW context %d, ret %d", client->pid, args->handle, ret);
+ drm_dev_exit(idx);
+ return 0;
+diff --git a/drivers/accel/amdxdna/amdxdna_ctx.h b/drivers/accel/amdxdna/amdxdna_ctx.h
+index 80b0304193ec3..f0a4a8586d858 100644
+--- a/drivers/accel/amdxdna/amdxdna_ctx.h
++++ b/drivers/accel/amdxdna/amdxdna_ctx.h
+@@ -87,6 +87,9 @@ struct amdxdna_hwctx {
+ struct amdxdna_qos_info qos;
+ struct amdxdna_hwctx_param_config_cu *cus;
+ u32 syncobj_hdl;
++
++ atomic64_t job_submit_cnt;
++ atomic64_t job_free_cnt ____cacheline_aligned_in_smp;
+ };
+
+ #define drm_job_to_xdna_job(j) \
+--
+2.39.5
+
--- /dev/null
+From 1304a765615a2dff12582f48b9a380b46f4b19e7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 17 Jan 2025 10:09:41 -0700
+Subject: accel/qaic: Mask out SR-IOV PCI resources
+
+From: Youssef Samir <quic_yabdulra@quicinc.com>
+
+[ Upstream commit 8685520474bfc0fe4be83c3cbfe3fb3e1ca1514a ]
+
+During the initialization of the qaic device, pci_select_bars() is
+used to fetch a bitmask of the BARs exposed by the device. On devices
+that have Virtual Functions capabilities, the bitmask includes SR-IOV
+BARs.
+
+Use a mask to filter out SR-IOV BARs if they exist.
+
+Signed-off-by: Youssef Samir <quic_yabdulra@quicinc.com>
+Reviewed-by: Jeffrey Hugo <quic_jhugo@quicinc.com>
+Signed-off-by: Jeffrey Hugo <quic_jhugo@quicinc.com>
+Reviewed-by: Lizhi Hou <lizhi.hou@amd.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250117170943.2643280-6-quic_jhugo@quicinc.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/accel/qaic/qaic_drv.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/accel/qaic/qaic_drv.c b/drivers/accel/qaic/qaic_drv.c
+index 81819b9ef8d4f..32f0e81d3e304 100644
+--- a/drivers/accel/qaic/qaic_drv.c
++++ b/drivers/accel/qaic/qaic_drv.c
+@@ -431,7 +431,7 @@ static int init_pci(struct qaic_device *qdev, struct pci_dev *pdev)
+ int bars;
+ int ret;
+
+- bars = pci_select_bars(pdev, IORESOURCE_MEM);
++ bars = pci_select_bars(pdev, IORESOURCE_MEM) & 0x3f;
+
+ /* make sure the device has the expected BARs */
+ if (bars != (BIT(0) | BIT(2) | BIT(4))) {
+--
+2.39.5
+
--- /dev/null
+From b154e21854951532ae9fa74194b0104a4acc8eed Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 12 Feb 2025 14:34:08 +0800
+Subject: ACPI: HED: Always initialize before evged
+
+From: Xiaofei Tan <tanxiaofei@huawei.com>
+
+[ Upstream commit cccf6ee090c8c133072d5d5b52ae25f3bc907a16 ]
+
+When the HED driver is built-in, it initializes after evged because they
+both are at the same initcall level, so the initialization ordering
+depends on the Makefile order. However, this prevents RAS records
+coming in between the evged driver initialization and the HED driver
+initialization from being handled.
+
+If the number of such RAS records is above the APEI HEST error source
+number, the HEST resources may be exhausted, and that may affect
+subsequent RAS error reporting.
+
+To fix this issue, change the initcall level of HED to subsys_initcall
+and prevent the driver from being built as a module by changing ACPI_HED
+in Kconfig from "tristate" to "bool".
+
+Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com>
+Link: https://patch.msgid.link/20250212063408.927666-1-tanxiaofei@huawei.com
+[ rjw: Changelog edits ]
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/acpi/Kconfig | 2 +-
+ drivers/acpi/hed.c | 7 ++++++-
+ 2 files changed, 7 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
+index d81b55f5068c4..7f10aa38269d2 100644
+--- a/drivers/acpi/Kconfig
++++ b/drivers/acpi/Kconfig
+@@ -452,7 +452,7 @@ config ACPI_SBS
+ the modules will be called sbs and sbshc.
+
+ config ACPI_HED
+- tristate "Hardware Error Device"
++ bool "Hardware Error Device"
+ help
+ This driver supports the Hardware Error Device (PNP0C33),
+ which is used to report some hardware errors notified via
+diff --git a/drivers/acpi/hed.c b/drivers/acpi/hed.c
+index 7652515a6be1e..3499f86c411e3 100644
+--- a/drivers/acpi/hed.c
++++ b/drivers/acpi/hed.c
+@@ -80,7 +80,12 @@ static struct acpi_driver acpi_hed_driver = {
+ .remove = acpi_hed_remove,
+ },
+ };
+-module_acpi_driver(acpi_hed_driver);
++
++static int __init acpi_hed_driver_init(void)
++{
++ return acpi_bus_register_driver(&acpi_hed_driver);
++}
++subsys_initcall(acpi_hed_driver_init);
+
+ MODULE_AUTHOR("Huang Ying");
+ MODULE_DESCRIPTION("ACPI Hardware Error Device Driver");
+--
+2.39.5
+
--- /dev/null
+From fa541dc05f19df98d52c8a54514358948887d8a7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 17 Mar 2025 10:55:07 +0000
+Subject: ACPI: PNP: Add Intel OC Watchdog IDs to non-PNP device list
+
+From: Diogo Ivo <diogo.ivo@siemens.com>
+
+[ Upstream commit f06777cf2bbc21dd8c71d6e3906934e56b4e18e4 ]
+
+Intel Over-Clocking Watchdogs are described in ACPI tables by both the
+generic PNP0C02 _CID and their ACPI _HID. The presence of the _CID then
+causes the PNP scan handler to attach to the watchdog, preventing the
+actual watchdog driver from binding. Address this by adding the ACPI
+_HIDs to the list of non-PNP devices, so that the PNP scan handler is
+bypassed.
+
+Note that these watchdogs can be described by multiple _HIDs for what
+seems to be identical hardware. This commit is not a complete list of
+all the possible watchdog ACPI _HIDs.
+
+Signed-off-by: Diogo Ivo <diogo.ivo@siemens.com>
+Link: https://patch.msgid.link/20250317-ivo-intel_oc_wdt-v3-2-32c396f4eefd@siemens.com
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/acpi/acpi_pnp.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/acpi/acpi_pnp.c b/drivers/acpi/acpi_pnp.c
+index 01abf26764b00..3f5a1840f5733 100644
+--- a/drivers/acpi/acpi_pnp.c
++++ b/drivers/acpi/acpi_pnp.c
+@@ -355,8 +355,10 @@ static bool acpi_pnp_match(const char *idstr, const struct acpi_device_id **matc
+ * device represented by it.
+ */
+ static const struct acpi_device_id acpi_nonpnp_device_ids[] = {
++ {"INT3F0D"},
+ {"INTC1080"},
+ {"INTC1081"},
++ {"INTC1099"},
+ {""},
+ };
+
+--
+2.39.5
+
--- /dev/null
+From 42e496546d7c77c218854fd914f7789a116889c9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 27 Apr 2025 10:10:34 +0200
+Subject: ALSA: hda/realtek: Add quirk for HP Spectre x360 15-df1xxx
+
+From: Takashi Iwai <tiwai@suse.de>
+
+[ Upstream commit be0c40da888840fe91b45474cb70779e6cbaf7ca ]
+
+HP Spectre x360 15-df1xxx with SSID 13c:863e requires similar
+workarounds that were applied to another HP Spectre x360 models;
+it has a mute LED only, no micmute LEDs, and needs the speaker GPIO
+seup.
+
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=220054
+Link: https://patch.msgid.link/20250427081035.11567-1-tiwai@suse.de
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/pci/hda/patch_realtek.c | 42 +++++++++++++++++++++++++++++++++++
+ 1 file changed, 42 insertions(+)
+
+diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
+index 025c80fa68b05..244fb8f9989b4 100644
+--- a/sound/pci/hda/patch_realtek.c
++++ b/sound/pci/hda/patch_realtek.c
+@@ -6963,6 +6963,41 @@ static void alc285_fixup_hp_spectre_x360_eb1(struct hda_codec *codec,
+ }
+ }
+
++/* GPIO1 = amplifier on/off */
++static void alc285_fixup_hp_spectre_x360_df1(struct hda_codec *codec,
++ const struct hda_fixup *fix,
++ int action)
++{
++ struct alc_spec *spec = codec->spec;
++ static const hda_nid_t conn[] = { 0x02 };
++ static const struct hda_pintbl pincfgs[] = {
++ { 0x14, 0x90170110 }, /* front/high speakers */
++ { 0x17, 0x90170130 }, /* back/bass speakers */
++ { }
++ };
++
++ // enable mute led
++ alc285_fixup_hp_mute_led_coefbit(codec, fix, action);
++
++ switch (action) {
++ case HDA_FIXUP_ACT_PRE_PROBE:
++ /* needed for amp of back speakers */
++ spec->gpio_mask |= 0x01;
++ spec->gpio_dir |= 0x01;
++ snd_hda_apply_pincfgs(codec, pincfgs);
++ /* share DAC to have unified volume control */
++ snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn), conn);
++ snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
++ break;
++ case HDA_FIXUP_ACT_INIT:
++ /* need to toggle GPIO to enable the amp of back speakers */
++ alc_update_gpio_data(codec, 0x01, true);
++ msleep(100);
++ alc_update_gpio_data(codec, 0x01, false);
++ break;
++ }
++}
++
+ static void alc285_fixup_hp_spectre_x360(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+ {
+@@ -7743,6 +7778,7 @@ enum {
+ ALC280_FIXUP_HP_9480M,
+ ALC245_FIXUP_HP_X360_AMP,
+ ALC285_FIXUP_HP_SPECTRE_X360_EB1,
++ ALC285_FIXUP_HP_SPECTRE_X360_DF1,
+ ALC285_FIXUP_HP_ENVY_X360,
+ ALC288_FIXUP_DELL_HEADSET_MODE,
+ ALC288_FIXUP_DELL1_MIC_NO_PRESENCE,
+@@ -9818,6 +9854,10 @@ static const struct hda_fixup alc269_fixups[] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc285_fixup_hp_spectre_x360_eb1
+ },
++ [ALC285_FIXUP_HP_SPECTRE_X360_DF1] = {
++ .type = HDA_FIXUP_FUNC,
++ .v.func = alc285_fixup_hp_spectre_x360_df1
++ },
+ [ALC285_FIXUP_HP_ENVY_X360] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc285_fixup_hp_envy_x360,
+@@ -10541,6 +10581,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x103c, 0x86c1, "HP Laptop 15-da3001TU", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
+ SND_PCI_QUIRK(0x103c, 0x86c7, "HP Envy AiO 32", ALC274_FIXUP_HP_ENVY_GPIO),
+ SND_PCI_QUIRK(0x103c, 0x86e7, "HP Spectre x360 15-eb0xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1),
++ SND_PCI_QUIRK(0x103c, 0x863e, "HP Spectre x360 15-df1xxx", ALC285_FIXUP_HP_SPECTRE_X360_DF1),
+ SND_PCI_QUIRK(0x103c, 0x86e8, "HP Spectre x360 15-eb0xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1),
+ SND_PCI_QUIRK(0x103c, 0x86f9, "HP Spectre x360 13-aw0xxx", ALC285_FIXUP_HP_SPECTRE_X360_MUTE_LED),
+ SND_PCI_QUIRK(0x103c, 0x8716, "HP Elite Dragonfly G2 Notebook PC", ALC285_FIXUP_HP_GPIO_AMP_INIT),
+@@ -11457,6 +11498,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
+ {.id = ALC295_FIXUP_HP_OMEN, .name = "alc295-hp-omen"},
+ {.id = ALC285_FIXUP_HP_SPECTRE_X360, .name = "alc285-hp-spectre-x360"},
+ {.id = ALC285_FIXUP_HP_SPECTRE_X360_EB1, .name = "alc285-hp-spectre-x360-eb1"},
++ {.id = ALC285_FIXUP_HP_SPECTRE_X360_DF1, .name = "alc285-hp-spectre-x360-df1"},
+ {.id = ALC285_FIXUP_HP_ENVY_X360, .name = "alc285-hp-envy-x360"},
+ {.id = ALC287_FIXUP_IDEAPAD_BASS_SPK_AMP, .name = "alc287-ideapad-bass-spk-amp"},
+ {.id = ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN, .name = "alc287-yoga9-bass-spk-pin"},
+--
+2.39.5
+
--- /dev/null
+From 976f14b1c5d78c5420accbbc025a0cb9c1a37b9e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 16 Feb 2025 22:31:03 +0100
+Subject: ALSA: hda/realtek: Enable PC beep passthrough for HP EliteBook 855 G7
+
+From: Maciej S. Szmigiero <mail@maciej.szmigiero.name>
+
+[ Upstream commit aa85822c611aef7cd4dc17d27121d43e21bb82f0 ]
+
+PC speaker works well on this platform in BIOS and in Linux until sound
+card drivers are loaded. Then it stops working.
+
+There seems to be a beep generator node at 0x1a in this CODEC
+(ALC269_TYPE_ALC215) but it seems to be only connected to capture mixers
+at nodes 0x22 and 0x23.
+If I unmute the mixer input for 0x1a at node 0x23 and start recording
+from its "ALC285 Analog" capture device I can clearly hear beeps in that
+recording.
+
+So the beep generator is indeed working properly, however I wasn't able to
+figure out any way to connect it to speakers.
+
+However, the bits in the "Passthrough Control" register (0x36) seems to
+work at least partially: by zeroing "B" and "h" and setting "S" I can at
+least make the PIT PC speaker output appear either in this laptop speakers
+or headphones (depending on whether they are connected or not).
+
+There are some caveats, however:
+* If the CODEC gets runtime-suspended the beeps stop so it needs HDA beep
+device for keeping it awake during beeping.
+
+* If the beep generator node is generating any beep the PC beep passthrough
+seems to be temporarily inhibited, so the HDA beep device has to be
+prevented from using the actual beep generator node - but the beep device
+is still necessary due to the previous point.
+
+* In contrast with other platforms here beep amplification has to be
+disabled otherwise the beeps output are WAY louder than they were on pure
+BIOS setup.
+
+Unless someone (from Realtek probably) knows how to make the beep generator
+node output appear in speakers / headphones using PC beep passthrough seems
+to be the only way to make PC speaker beeping actually work on this
+platform.
+
+Signed-off-by: Maciej S. Szmigiero <mail@maciej.szmigiero.name>
+Acked-by: kailang@realtek.com
+Link: https://patch.msgid.link/7461f695b4daed80f2fc4b1463ead47f04f9ad05.1739741254.git.mail@maciej.szmigiero.name
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/sound/hda_codec.h | 1 +
+ sound/pci/hda/hda_beep.c | 15 +++++++++------
+ sound/pci/hda/patch_realtek.c | 34 +++++++++++++++++++++++++++++++++-
+ 3 files changed, 43 insertions(+), 7 deletions(-)
+
+diff --git a/include/sound/hda_codec.h b/include/sound/hda_codec.h
+index 575e55aa08ca9..c1fe6290d04dc 100644
+--- a/include/sound/hda_codec.h
++++ b/include/sound/hda_codec.h
+@@ -195,6 +195,7 @@ struct hda_codec {
+ /* beep device */
+ struct hda_beep *beep;
+ unsigned int beep_mode;
++ bool beep_just_power_on;
+
+ /* widget capabilities cache */
+ u32 *wcaps;
+diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c
+index e51d475725576..13a7d92e8d8d0 100644
+--- a/sound/pci/hda/hda_beep.c
++++ b/sound/pci/hda/hda_beep.c
+@@ -31,8 +31,9 @@ static void generate_tone(struct hda_beep *beep, int tone)
+ beep->power_hook(beep, true);
+ beep->playing = 1;
+ }
+- snd_hda_codec_write(codec, beep->nid, 0,
+- AC_VERB_SET_BEEP_CONTROL, tone);
++ if (!codec->beep_just_power_on)
++ snd_hda_codec_write(codec, beep->nid, 0,
++ AC_VERB_SET_BEEP_CONTROL, tone);
+ if (!tone && beep->playing) {
+ beep->playing = 0;
+ if (beep->power_hook)
+@@ -212,10 +213,12 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
+ struct hda_beep *beep;
+ int err;
+
+- if (!snd_hda_get_bool_hint(codec, "beep"))
+- return 0; /* disabled explicitly by hints */
+- if (codec->beep_mode == HDA_BEEP_MODE_OFF)
+- return 0; /* disabled by module option */
++ if (!codec->beep_just_power_on) {
++ if (!snd_hda_get_bool_hint(codec, "beep"))
++ return 0; /* disabled explicitly by hints */
++ if (codec->beep_mode == HDA_BEEP_MODE_OFF)
++ return 0; /* disabled by module option */
++ }
+
+ beep = kzalloc(sizeof(*beep), GFP_KERNEL);
+ if (beep == NULL)
+diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
+index 2ff02fb6f7e94..025c80fa68b05 100644
+--- a/sound/pci/hda/patch_realtek.c
++++ b/sound/pci/hda/patch_realtek.c
+@@ -28,6 +28,7 @@
+ #include <sound/hda_codec.h>
+ #include "hda_local.h"
+ #include "hda_auto_parser.h"
++#include "hda_beep.h"
+ #include "hda_jack.h"
+ #include "hda_generic.h"
+ #include "hda_component.h"
+@@ -7034,6 +7035,30 @@ static void alc285_fixup_hp_envy_x360(struct hda_codec *codec,
+ }
+ }
+
++static void alc285_fixup_hp_beep(struct hda_codec *codec,
++ const struct hda_fixup *fix, int action)
++{
++ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
++ codec->beep_just_power_on = true;
++ } else if (action == HDA_FIXUP_ACT_INIT) {
++#ifdef CONFIG_SND_HDA_INPUT_BEEP
++ /*
++ * Just enable loopback to internal speaker and headphone jack.
++ * Disable amplification to get about the same beep volume as
++ * was on pure BIOS setup before loading the driver.
++ */
++ alc_update_coef_idx(codec, 0x36, 0x7070, BIT(13));
++
++ snd_hda_enable_beep_device(codec, 1);
++
++#if !IS_ENABLED(CONFIG_INPUT_PCSPKR)
++ dev_warn_once(hda_codec_dev(codec),
++ "enable CONFIG_INPUT_PCSPKR to get PC beeps\n");
++#endif
++#endif
++ }
++}
++
+ /* for hda_fixup_thinkpad_acpi() */
+ #include "thinkpad_helper.c"
+
+@@ -7819,6 +7844,7 @@ enum {
+ ALC285_FIXUP_HP_GPIO_LED,
+ ALC285_FIXUP_HP_MUTE_LED,
+ ALC285_FIXUP_HP_SPECTRE_X360_MUTE_LED,
++ ALC285_FIXUP_HP_BEEP_MICMUTE_LED,
+ ALC236_FIXUP_HP_MUTE_LED_COEFBIT2,
+ ALC236_FIXUP_HP_GPIO_LED,
+ ALC236_FIXUP_HP_MUTE_LED,
+@@ -9415,6 +9441,12 @@ static const struct hda_fixup alc269_fixups[] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc285_fixup_hp_spectre_x360_mute_led,
+ },
++ [ALC285_FIXUP_HP_BEEP_MICMUTE_LED] = {
++ .type = HDA_FIXUP_FUNC,
++ .v.func = alc285_fixup_hp_beep,
++ .chained = true,
++ .chain_id = ALC285_FIXUP_HP_MUTE_LED,
++ },
+ [ALC236_FIXUP_HP_MUTE_LED_COEFBIT2] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc236_fixup_hp_mute_led_coefbit2,
+@@ -10519,7 +10551,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x103c, 0x8730, "HP ProBook 445 G7", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+ SND_PCI_QUIRK(0x103c, 0x8735, "HP ProBook 435 G7", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+ SND_PCI_QUIRK(0x103c, 0x8736, "HP", ALC285_FIXUP_HP_GPIO_AMP_INIT),
+- SND_PCI_QUIRK(0x103c, 0x8760, "HP", ALC285_FIXUP_HP_MUTE_LED),
++ SND_PCI_QUIRK(0x103c, 0x8760, "HP EliteBook 8{4,5}5 G7", ALC285_FIXUP_HP_BEEP_MICMUTE_LED),
+ SND_PCI_QUIRK(0x103c, 0x876e, "HP ENVY x360 Convertible 13-ay0xxx", ALC245_FIXUP_HP_X360_MUTE_LEDS),
+ SND_PCI_QUIRK(0x103c, 0x877a, "HP", ALC285_FIXUP_HP_MUTE_LED),
+ SND_PCI_QUIRK(0x103c, 0x877d, "HP", ALC236_FIXUP_HP_MUTE_LED),
+--
+2.39.5
+
--- /dev/null
+From f939c5a3711f931faa89dcb4c1326b1221958811 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 7 Mar 2025 09:42:42 +0100
+Subject: ALSA: seq: Improve data consistency at polling
+
+From: Takashi Iwai <tiwai@suse.de>
+
+[ Upstream commit e3cd33ab17c33bd8f1a9df66ec83a15dd8f7afbb ]
+
+snd_seq_poll() calls snd_seq_write_pool_allocated() that reads out a
+field in client->pool object, while it can be updated concurrently via
+ioctls, as reported by syzbot. The data race itself is harmless, as
+it's merely a poll() call, and the state is volatile. OTOH, the read
+out of poll object info from the caller side is fragile, and we can
+leave it better in snd_seq_pool_poll_wait() alone.
+
+A similar pattern is seen in snd_seq_kernel_client_write_poll(), too,
+which is called from the OSS sequencer.
+
+This patch drops the pool checks from the caller side and add the
+pool->lock in snd_seq_pool_poll_wait() for better data consistency.
+
+Reported-by: syzbot+2d373c9936c00d7e120c@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/67c88903.050a0220.15b4b9.0028.GAE@google.com
+Link: https://patch.msgid.link/20250307084246.29271-1-tiwai@suse.de
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/core/seq/seq_clientmgr.c | 5 +----
+ sound/core/seq/seq_memory.c | 1 +
+ 2 files changed, 2 insertions(+), 4 deletions(-)
+
+diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
+index 0ae01b85bb18c..198683a69a534 100644
+--- a/sound/core/seq/seq_clientmgr.c
++++ b/sound/core/seq/seq_clientmgr.c
+@@ -1164,8 +1164,7 @@ static __poll_t snd_seq_poll(struct file *file, poll_table * wait)
+ if (snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_OUTPUT) {
+
+ /* check if data is available in the pool */
+- if (!snd_seq_write_pool_allocated(client) ||
+- snd_seq_pool_poll_wait(client->pool, file, wait))
++ if (snd_seq_pool_poll_wait(client->pool, file, wait))
+ mask |= EPOLLOUT | EPOLLWRNORM;
+ }
+
+@@ -2600,8 +2599,6 @@ int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table
+ if (client == NULL)
+ return -ENXIO;
+
+- if (! snd_seq_write_pool_allocated(client))
+- return 1;
+ if (snd_seq_pool_poll_wait(client->pool, file, wait))
+ return 1;
+ return 0;
+diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c
+index 20155e3e87c6a..ccde0ca3d2082 100644
+--- a/sound/core/seq/seq_memory.c
++++ b/sound/core/seq/seq_memory.c
+@@ -427,6 +427,7 @@ int snd_seq_pool_poll_wait(struct snd_seq_pool *pool, struct file *file,
+ poll_table *wait)
+ {
+ poll_wait(file, &pool->output_sleep, wait);
++ guard(spinlock_irq)(&pool->lock);
+ return snd_seq_output_ok(pool);
+ }
+
+--
+2.39.5
+
--- /dev/null
+From 321bf1f4ca71b4680e91ad29ecf9c42cb95c1a8e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 29 Apr 2025 20:36:15 +0200
+Subject: ALSA: usb-audio: Fix duplicated name in MIDI substream names
+
+From: Takashi Iwai <tiwai@suse.de>
+
+[ Upstream commit 0759e77a6d9bd34a874da73721ce4a7dc6665023 ]
+
+The MIDI substream name string is constructed from the combination of
+the card shortname (which is taken from USB iProduct) and the USB
+iJack. The problem is that some devices put the product name to the
+iJack field, too. For example, aplaymidi -l output on the Lanchkey MK
+49 are like:
+
+ % aplaymidi -l
+ Port Client name Port name
+ 44:0 Launchkey MK4 49 Launchkey MK4 49 Launchkey MK4
+ 44:1 Launchkey MK4 49 Launchkey MK4 49 Launchkey MK4
+
+where the actual iJack name can't be seen because it's truncated due
+to the doubly words.
+
+For resolving those situations, this patch compares the iJack string
+with the card shortname, and drops if both start with the same words.
+Then the result becomes like:
+
+ % aplaymidi -l
+ Port Client name Port name
+ 40:0 Launchkey MK4 49 Launchkey MK4 49 MIDI In
+ 40:1 Launchkey MK4 49 Launchkey MK4 49 DAW In
+
+A caveat is that there are some pre-defined names for certain
+devices in the driver code, and this workaround shouldn't be applied
+to them. Similarly, when the iJack isn't specified, we should skip
+this check, too. The patch added those checks in addition to the
+string comparison.
+
+Suggested-by: Paul Davis <paul@linuxaudiosystems.com>
+Tested-by: Paul Davis <paul@linuxaudiosystems.com>
+Link: https://lore.kernel.org/CAFa_cKmEDQWcJatbYWi6A58Zg4Ma9_6Nr3k5LhqwyxC-P_kXtw@mail.gmail.com
+Link: https://patch.msgid.link/20250429183626.20773-1-tiwai@suse.de
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/usb/midi.c | 16 ++++++++++++----
+ 1 file changed, 12 insertions(+), 4 deletions(-)
+
+diff --git a/sound/usb/midi.c b/sound/usb/midi.c
+index 826ac870f2469..a792ada18863a 100644
+--- a/sound/usb/midi.c
++++ b/sound/usb/midi.c
+@@ -1885,10 +1885,18 @@ static void snd_usbmidi_init_substream(struct snd_usb_midi *umidi,
+ }
+
+ port_info = find_port_info(umidi, number);
+- name_format = port_info ? port_info->name :
+- (jack_name != default_jack_name ? "%s %s" : "%s %s %d");
+- snprintf(substream->name, sizeof(substream->name),
+- name_format, umidi->card->shortname, jack_name, number + 1);
++ if (port_info || jack_name == default_jack_name ||
++ strncmp(umidi->card->shortname, jack_name, strlen(umidi->card->shortname)) != 0) {
++ name_format = port_info ? port_info->name :
++ (jack_name != default_jack_name ? "%s %s" : "%s %s %d");
++ snprintf(substream->name, sizeof(substream->name),
++ name_format, umidi->card->shortname, jack_name, number + 1);
++ } else {
++ /* The manufacturer included the iProduct name in the jack
++ * name, do not use both
++ */
++ strscpy(substream->name, jack_name);
++ }
+
+ *rsubstream = substream;
+ }
+--
+2.39.5
+
--- /dev/null
+From 55973aa1d3bebc3cb2c5adb8cd8e3aef37f83279 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Jan 2025 11:40:12 +0800
+Subject: amdgpu/soc15: enable asic reset for dGPU in case of suspend abort
+
+From: Jiang Liu <gerry@linux.alibaba.com>
+
+[ Upstream commit 38e8ca3e4b6de1c6e49d0140264cfc8d314a5f70 ]
+
+When GPU suspend is aborted, do the same for dGPU as APU to reset
+soc15 asic. Otherwise it may cause following errors:
+[ 547.229463] amdgpu 0001:81:00.0: [drm:amdgpu_ring_test_helper [amdgpu]] *ERROR* ring kiq_0.2.1.0 test failed (-110)
+
+[ 555.126827] amdgpu 0000:0a:00.0: [drm:amdgpu_ring_test_helper [amdgpu]] *ERROR* ring kiq_0.2.1.0 test failed (-110)
+[ 555.126901] [drm:amdgpu_gfx_enable_kcq [amdgpu]] *ERROR* KCQ enable failed
+[ 555.126957] [drm:amdgpu_device_ip_resume_phase2 [amdgpu]] *ERROR* resume of IP block <gfx_v9_4_3> failed -110
+[ 555.126959] amdgpu 0000:0a:00.0: amdgpu: amdgpu_device_ip_resume failed (-110).
+[ 555.126965] PM: dpm_run_callback(): pci_pm_resume+0x0/0xe0 returns -110
+[ 555.126966] PM: Device 0000:0a:00.0 failed to resume async: error -110
+
+This fix has been tested on Mi308X.
+
+Signed-off-by: Jiang Liu <gerry@linux.alibaba.com>
+Tested-by: Shuo Liu <shuox.liu@linux.alibaba.com>
+Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>
+Link: https://lore.kernel.org/r/2462b4b12eb9d025e82525178d568cbaa4c223ff.1736739303.git.gerry@linux.alibaba.com
+Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/soc15.c | 8 +++-----
+ 1 file changed, 3 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.c b/drivers/gpu/drm/amd/amdgpu/soc15.c
+index e98fb3fa36a88..6e09613de8cd2 100644
+--- a/drivers/gpu/drm/amd/amdgpu/soc15.c
++++ b/drivers/gpu/drm/amd/amdgpu/soc15.c
+@@ -604,12 +604,10 @@ soc15_asic_reset_method(struct amdgpu_device *adev)
+ static bool soc15_need_reset_on_resume(struct amdgpu_device *adev)
+ {
+ /* Will reset for the following suspend abort cases.
+- * 1) Only reset on APU side, dGPU hasn't checked yet.
+- * 2) S3 suspend aborted in the normal S3 suspend or
+- * performing pm core test.
++ * 1) S3 suspend aborted in the normal S3 suspend
++ * 2) S3 suspend aborted in performing pm core test.
+ */
+- if (adev->flags & AMD_IS_APU && adev->in_s3 &&
+- !pm_resume_via_firmware())
++ if (adev->in_s3 && !pm_resume_via_firmware())
+ return true;
+ else
+ return false;
+--
+2.39.5
+
--- /dev/null
+From bd01cca842f95c4909745299c3358845ad02f5bc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 21 Jan 2025 18:46:20 +0530
+Subject: arch/powerpc/perf: Check the instruction type before creating sample
+ with perf_mem_data_src
+
+From: Athira Rajeev <atrajeev@linux.vnet.ibm.com>
+
+[ Upstream commit 2ffb26afa64261139e608bf087a0c1fe24d76d4d ]
+
+perf mem report aborts as below sometimes (during some corner
+case) in powerpc:
+
+ # ./perf mem report 1>out
+ *** stack smashing detected ***: terminated
+ Aborted (core dumped)
+
+The backtrace is as below:
+ __pthread_kill_implementation ()
+ raise ()
+ abort ()
+ __libc_message
+ __fortify_fail
+ __stack_chk_fail
+ hist_entry.lvl_snprintf
+ __sort__hpp_entry
+ __hist_entry__snprintf
+ hists.fprintf
+ cmd_report
+ cmd_mem
+
+Snippet of code which triggers the issue
+from tools/perf/util/sort.c
+
+ static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
+ size_t size, unsigned int width)
+ {
+ char out[64];
+
+ perf_mem__lvl_scnprintf(out, sizeof(out), he->mem_info);
+ return repsep_snprintf(bf, size, "%-*s", width, out);
+ }
+
+The value of "out" is filled from perf_mem_data_src value.
+Debugging this further showed that for some corner cases, the
+value of "data_src" was pointing to wrong value. This resulted
+in bigger size of string and causing stack check fail.
+
+The perf mem data source values are captured in the sample via
+isa207_get_mem_data_src function. The initial check is to fetch
+the type of sampled instruction. If the type of instruction is
+not valid (not a load/store instruction), the function returns.
+
+Since 'commit e16fd7f2cb1a ("perf: Use sample_flags for data_src")',
+data_src field is not initialized by the perf_sample_data_init()
+function. If the PMU driver doesn't set the data_src value to zero if
+type is not valid, this will result in uninitailised value for data_src.
+The uninitailised value of data_src resulted in stack check fail
+followed by abort for "perf mem report".
+
+When requesting for data source information in the sample, the
+instruction type is expected to be load or store instruction.
+In ISA v3.0, due to hardware limitation, there are corner cases
+where the instruction type other than load or store is observed.
+In ISA v3.0 and before values "0" and "7" are considered reserved.
+In ISA v3.1, value "7" has been used to indicate "larx/stcx".
+Drop the sample if instruction type has reserved values for this
+field with a ISA version check. Initialize data_src to zero in
+isa207_get_mem_data_src if the instruction type is not load/store.
+
+Reported-by: Disha Goel <disgoel@linux.vnet.ibm.com>
+Signed-off-by: Athira Rajeev <atrajeev@linux.vnet.ibm.com>
+Signed-off-by: Madhavan Srinivasan <maddy@linux.ibm.com>
+Link: https://patch.msgid.link/20250121131621.39054-1-atrajeev@linux.vnet.ibm.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/powerpc/perf/core-book3s.c | 20 ++++++++++++++++++++
+ arch/powerpc/perf/isa207-common.c | 4 +++-
+ 2 files changed, 23 insertions(+), 1 deletion(-)
+
+diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c
+index f4e03aaabb4c3..b906d28f74fd4 100644
+--- a/arch/powerpc/perf/core-book3s.c
++++ b/arch/powerpc/perf/core-book3s.c
+@@ -2226,6 +2226,10 @@ static struct pmu power_pmu = {
+ #define PERF_SAMPLE_ADDR_TYPE (PERF_SAMPLE_ADDR | \
+ PERF_SAMPLE_PHYS_ADDR | \
+ PERF_SAMPLE_DATA_PAGE_SIZE)
++
++#define SIER_TYPE_SHIFT 15
++#define SIER_TYPE_MASK (0x7ull << SIER_TYPE_SHIFT)
++
+ /*
+ * A counter has overflowed; update its count and record
+ * things if requested. Note that interrupts are hard-disabled
+@@ -2294,6 +2298,22 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
+ is_kernel_addr(mfspr(SPRN_SIAR)))
+ record = 0;
+
++ /*
++ * SIER[46-48] presents instruction type of the sampled instruction.
++ * In ISA v3.0 and before values "0" and "7" are considered reserved.
++ * In ISA v3.1, value "7" has been used to indicate "larx/stcx".
++ * Drop the sample if "type" has reserved values for this field with a
++ * ISA version check.
++ */
++ if (event->attr.sample_type & PERF_SAMPLE_DATA_SRC &&
++ ppmu->get_mem_data_src) {
++ val = (regs->dar & SIER_TYPE_MASK) >> SIER_TYPE_SHIFT;
++ if (val == 0 || (val == 7 && !cpu_has_feature(CPU_FTR_ARCH_31))) {
++ record = 0;
++ atomic64_inc(&event->lost_samples);
++ }
++ }
++
+ /*
+ * Finally record data if requested.
+ */
+diff --git a/arch/powerpc/perf/isa207-common.c b/arch/powerpc/perf/isa207-common.c
+index 56301b2bc8ae8..031a2b63c171d 100644
+--- a/arch/powerpc/perf/isa207-common.c
++++ b/arch/powerpc/perf/isa207-common.c
+@@ -321,8 +321,10 @@ void isa207_get_mem_data_src(union perf_mem_data_src *dsrc, u32 flags,
+
+ sier = mfspr(SPRN_SIER);
+ val = (sier & ISA207_SIER_TYPE_MASK) >> ISA207_SIER_TYPE_SHIFT;
+- if (val != 1 && val != 2 && !(val == 7 && cpu_has_feature(CPU_FTR_ARCH_31)))
++ if (val != 1 && val != 2 && !(val == 7 && cpu_has_feature(CPU_FTR_ARCH_31))) {
++ dsrc->val = 0;
+ return;
++ }
+
+ idx = (sier & ISA207_SIER_LDST_MASK) >> ISA207_SIER_LDST_SHIFT;
+ sub_idx = (sier & ISA207_SIER_DATA_SRC_MASK) >> ISA207_SIER_DATA_SRC_SHIFT;
+--
+2.39.5
+
--- /dev/null
+From b36a2d12020cd4bac69146bd8ade76bc581556de Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Feb 2025 08:51:56 -0700
+Subject: ARM: at91: pm: fix at91_suspend_finish for ZQ calibration
+
+From: Li Bin <bin.li@microchip.com>
+
+[ Upstream commit bc4722c3598d0e2c2dbf9609a3d3198993093e2b ]
+
+For sama7g5 and sama7d65 backup mode, we encountered a "ZQ calibrate error"
+during recalibrating the impedance in BootStrap.
+We found that the impedance value saved in at91_suspend_finish() before
+the DDR entered self-refresh mode did not match the resistor values. The
+ZDATA field in the DDR3PHY_ZQ0CR0 register uses a modified gray code to
+select the different impedance setting.
+But these gray code are incorrect, a workaournd from design team fixed the
+bug in the calibration logic. The ZDATA contains four independent impedance
+elements, but the algorithm combined the four elements into one. The elements
+were fixed using properly shifted offsets.
+
+Signed-off-by: Li Bin <bin.li@microchip.com>
+[nicolas.ferre@microchip.com: fix indentation and combine 2 patches]
+Signed-off-by: Nicolas Ferre <nicolas.ferre@microchip.com>
+Tested-by: Ryan Wanner <Ryan.Wanner@microchip.com>
+Tested-by: Durai Manickam KR <durai.manickamkr@microchip.com>
+Tested-by: Andrei Simion <andrei.simion@microchip.com>
+Signed-off-by: Ryan Wanner <Ryan.Wanner@microchip.com>
+Link: https://lore.kernel.org/r/28b33f9bcd0ca60ceba032969fe054d38f2b9577.1740671156.git.Ryan.Wanner@microchip.com
+Signed-off-by: Claudiu Beznea <claudiu.beznea@tuxon.dev>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm/mach-at91/pm.c | 21 +++++++++++----------
+ 1 file changed, 11 insertions(+), 10 deletions(-)
+
+diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
+index 05a1547642b60..6c3e6aa22606f 100644
+--- a/arch/arm/mach-at91/pm.c
++++ b/arch/arm/mach-at91/pm.c
+@@ -545,11 +545,12 @@ extern u32 at91_pm_suspend_in_sram_sz;
+
+ static int at91_suspend_finish(unsigned long val)
+ {
+- unsigned char modified_gray_code[] = {
+- 0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05, 0x0c, 0x0d,
+- 0x0e, 0x0f, 0x0a, 0x0b, 0x08, 0x09, 0x18, 0x19, 0x1a, 0x1b,
+- 0x1e, 0x1f, 0x1c, 0x1d, 0x14, 0x15, 0x16, 0x17, 0x12, 0x13,
+- 0x10, 0x11,
++ /* SYNOPSYS workaround to fix a bug in the calibration logic */
++ unsigned char modified_fix_code[] = {
++ 0x00, 0x01, 0x01, 0x06, 0x07, 0x0c, 0x06, 0x07, 0x0b, 0x18,
++ 0x0a, 0x0b, 0x0c, 0x0d, 0x0d, 0x0a, 0x13, 0x13, 0x12, 0x13,
++ 0x14, 0x15, 0x15, 0x12, 0x18, 0x19, 0x19, 0x1e, 0x1f, 0x14,
++ 0x1e, 0x1f,
+ };
+ unsigned int tmp, index;
+ int i;
+@@ -560,25 +561,25 @@ static int at91_suspend_finish(unsigned long val)
+ * restore the ZQ0SR0 with the value saved here. But the
+ * calibration is buggy and restoring some values from ZQ0SR0
+ * is forbidden and risky thus we need to provide processed
+- * values for these (modified gray code values).
++ * values for these.
+ */
+ tmp = readl(soc_pm.data.ramc_phy + DDR3PHY_ZQ0SR0);
+
+ /* Store pull-down output impedance select. */
+ index = (tmp >> DDR3PHY_ZQ0SR0_PDO_OFF) & 0x1f;
+- soc_pm.bu->ddr_phy_calibration[0] = modified_gray_code[index];
++ soc_pm.bu->ddr_phy_calibration[0] = modified_fix_code[index] << DDR3PHY_ZQ0SR0_PDO_OFF;
+
+ /* Store pull-up output impedance select. */
+ index = (tmp >> DDR3PHY_ZQ0SR0_PUO_OFF) & 0x1f;
+- soc_pm.bu->ddr_phy_calibration[0] |= modified_gray_code[index];
++ soc_pm.bu->ddr_phy_calibration[0] |= modified_fix_code[index] << DDR3PHY_ZQ0SR0_PUO_OFF;
+
+ /* Store pull-down on-die termination impedance select. */
+ index = (tmp >> DDR3PHY_ZQ0SR0_PDODT_OFF) & 0x1f;
+- soc_pm.bu->ddr_phy_calibration[0] |= modified_gray_code[index];
++ soc_pm.bu->ddr_phy_calibration[0] |= modified_fix_code[index] << DDR3PHY_ZQ0SR0_PDODT_OFF;
+
+ /* Store pull-up on-die termination impedance select. */
+ index = (tmp >> DDR3PHY_ZQ0SRO_PUODT_OFF) & 0x1f;
+- soc_pm.bu->ddr_phy_calibration[0] |= modified_gray_code[index];
++ soc_pm.bu->ddr_phy_calibration[0] |= modified_fix_code[index] << DDR3PHY_ZQ0SRO_PUODT_OFF;
+
+ /*
+ * The 1st 8 words of memory might get corrupted in the process
+--
+2.39.5
+
--- /dev/null
+From 7ef665c99d00c85722243b8f44f4fe335e6f8620 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Feb 2025 12:56:11 +0200
+Subject: ARM: tegra: Switch DSI-B clock parent to PLLD on Tegra114
+
+From: Svyatoslav Ryhel <clamor95@gmail.com>
+
+[ Upstream commit 2b3db788f2f614b875b257cdb079adadedc060f3 ]
+
+PLLD is usually used as parent clock for internal video devices, like
+DSI for example, while PLLD2 is used as parent for HDMI.
+
+Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
+Link: https://lore.kernel.org/r/20250226105615.61087-3-clamor95@gmail.com
+Signed-off-by: Thierry Reding <treding@nvidia.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm/boot/dts/nvidia/tegra114.dtsi | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/arch/arm/boot/dts/nvidia/tegra114.dtsi b/arch/arm/boot/dts/nvidia/tegra114.dtsi
+index 86f14e2fd29f3..6c057b5069514 100644
+--- a/arch/arm/boot/dts/nvidia/tegra114.dtsi
++++ b/arch/arm/boot/dts/nvidia/tegra114.dtsi
+@@ -139,7 +139,7 @@ dsib: dsi@54400000 {
+ reg = <0x54400000 0x00040000>;
+ clocks = <&tegra_car TEGRA114_CLK_DSIB>,
+ <&tegra_car TEGRA114_CLK_DSIBLP>,
+- <&tegra_car TEGRA114_CLK_PLL_D2_OUT0>;
++ <&tegra_car TEGRA114_CLK_PLL_D_OUT0>;
+ clock-names = "dsi", "lp", "parent";
+ resets = <&tegra_car 82>;
+ reset-names = "dsi";
+--
+2.39.5
+
--- /dev/null
+From 9cdb4b1a5cb8e5313ef1338375a59b722d152dc9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 25 Mar 2025 22:19:00 +0800
+Subject: arm64: Add support for HIP09 Spectre-BHB mitigation
+
+From: Jinqian Yang <yangjinqian1@huawei.com>
+
+[ Upstream commit e18c09b204e81702ea63b9f1a81ab003b72e3174 ]
+
+The HIP09 processor is vulnerable to the Spectre-BHB (Branch History
+Buffer) attack, which can be exploited to leak information through
+branch prediction side channels. This commit adds the MIDR of HIP09
+to the list for software mitigation.
+
+Signed-off-by: Jinqian Yang <yangjinqian1@huawei.com>
+Link: https://lore.kernel.org/r/20250325141900.2057314-1-yangjinqian1@huawei.com
+Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/include/asm/cputype.h | 2 ++
+ arch/arm64/kernel/proton-pack.c | 1 +
+ 2 files changed, 3 insertions(+)
+
+diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h
+index 8c6bd9da3b1ba..3381fdc081ad2 100644
+--- a/arch/arm64/include/asm/cputype.h
++++ b/arch/arm64/include/asm/cputype.h
+@@ -133,6 +133,7 @@
+ #define FUJITSU_CPU_PART_A64FX 0x001
+
+ #define HISI_CPU_PART_TSV110 0xD01
++#define HISI_CPU_PART_HIP09 0xD02
+
+ #define APPLE_CPU_PART_M1_ICESTORM 0x022
+ #define APPLE_CPU_PART_M1_FIRESTORM 0x023
+@@ -210,6 +211,7 @@
+ #define MIDR_NVIDIA_CARMEL MIDR_CPU_MODEL(ARM_CPU_IMP_NVIDIA, NVIDIA_CPU_PART_CARMEL)
+ #define MIDR_FUJITSU_A64FX MIDR_CPU_MODEL(ARM_CPU_IMP_FUJITSU, FUJITSU_CPU_PART_A64FX)
+ #define MIDR_HISI_TSV110 MIDR_CPU_MODEL(ARM_CPU_IMP_HISI, HISI_CPU_PART_TSV110)
++#define MIDR_HISI_HIP09 MIDR_CPU_MODEL(ARM_CPU_IMP_HISI, HISI_CPU_PART_HIP09)
+ #define MIDR_APPLE_M1_ICESTORM MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM)
+ #define MIDR_APPLE_M1_FIRESTORM MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_FIRESTORM)
+ #define MIDR_APPLE_M1_ICESTORM_PRO MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM_PRO)
+diff --git a/arch/arm64/kernel/proton-pack.c b/arch/arm64/kernel/proton-pack.c
+index 8ef3335ecff72..31eaf15d2079a 100644
+--- a/arch/arm64/kernel/proton-pack.c
++++ b/arch/arm64/kernel/proton-pack.c
+@@ -904,6 +904,7 @@ static u8 spectre_bhb_loop_affected(void)
+ MIDR_ALL_VERSIONS(MIDR_CORTEX_A77),
+ MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N1),
+ MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_4XX_GOLD),
++ MIDR_ALL_VERSIONS(MIDR_HISI_HIP09),
+ {},
+ };
+ static const struct midr_range spectre_bhb_k11_list[] = {
+--
+2.39.5
+
--- /dev/null
+From 86343684e505ca066859f4440c6511ba1a6e5a20 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 21 Feb 2025 10:12:26 +0530
+Subject: arm64/mm: Check pmd_table() in pmd_trans_huge()
+
+From: Ryan Roberts <ryan.roberts@arm.com>
+
+[ Upstream commit d1770e909898c108e8c7d30ca039053e8818a9c9 ]
+
+Check for pmd_table() in pmd_trans_huge() rather then just checking for the
+PMD_TABLE_BIT. But ensure all present-invalid entries are handled correctly
+by always setting PTE_VALID before checking with pmd_table().
+
+Cc: Will Deacon <will@kernel.org>
+Cc: Ard Biesheuvel <ardb@kernel.org>
+Cc: Ryan Roberts <ryan.roberts@arm.com>
+Cc: Mark Rutland <mark.rutland@arm.com>
+Cc: linux-arm-kernel@lists.infradead.org
+Cc: linux-kernel@vger.kernel.org
+Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
+Signed-off-by: Anshuman Khandual <anshuman.khandual@arm.com>
+Link: https://lore.kernel.org/r/20250221044227.1145393-8-anshuman.khandual@arm.com
+Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/include/asm/pgtable.h | 24 ++++++++++++------------
+ 1 file changed, 12 insertions(+), 12 deletions(-)
+
+diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
+index 0b2a2ad1b9e83..abf990ce175b1 100644
+--- a/arch/arm64/include/asm/pgtable.h
++++ b/arch/arm64/include/asm/pgtable.h
+@@ -548,18 +548,6 @@ static inline int pmd_protnone(pmd_t pmd)
+ #endif
+
+ #define pmd_present(pmd) pte_present(pmd_pte(pmd))
+-
+-/*
+- * THP definitions.
+- */
+-
+-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+-static inline int pmd_trans_huge(pmd_t pmd)
+-{
+- return pmd_val(pmd) && pmd_present(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT);
+-}
+-#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
+-
+ #define pmd_dirty(pmd) pte_dirty(pmd_pte(pmd))
+ #define pmd_young(pmd) pte_young(pmd_pte(pmd))
+ #define pmd_valid(pmd) pte_valid(pmd_pte(pmd))
+@@ -724,6 +712,18 @@ extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
+ #define pmd_leaf_size(pmd) (pmd_cont(pmd) ? CONT_PMD_SIZE : PMD_SIZE)
+ #define pte_leaf_size(pte) (pte_cont(pte) ? CONT_PTE_SIZE : PAGE_SIZE)
+
++#ifdef CONFIG_TRANSPARENT_HUGEPAGE
++static inline int pmd_trans_huge(pmd_t pmd)
++{
++ /*
++ * If pmd is present-invalid, pmd_table() won't detect it
++ * as a table, so force the valid bit for the comparison.
++ */
++ return pmd_val(pmd) && pmd_present(pmd) &&
++ !pmd_table(__pmd(pmd_val(pmd) | PTE_VALID));
++}
++#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
++
+ #if defined(CONFIG_ARM64_64K_PAGES) || CONFIG_PGTABLE_LEVELS < 3
+ static inline bool pud_sect(pud_t pud) { return false; }
+ static inline bool pud_table(pud_t pud) { return true; }
+--
+2.39.5
+
--- /dev/null
+From 572faea04689a0419a74406e1681dd08cfaf72de Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 21 Feb 2025 10:12:25 +0530
+Subject: arm64/mm: Check PUD_TYPE_TABLE in pud_bad()
+
+From: Ryan Roberts <ryan.roberts@arm.com>
+
+[ Upstream commit bfb1d2b9021c21891427acc86eb848ccedeb274e ]
+
+pud_bad() is currently defined in terms of pud_table(). Although for some
+configs, pud_table() is hard-coded to true i.e. when using 64K base pages
+or when page table levels are less than 3.
+
+pud_bad() is intended to check that the pud is configured correctly. Hence
+let's open-code the same check that the full version of pud_table() uses
+into pud_bad(). Then it always performs the check regardless of the config.
+
+Cc: Will Deacon <will@kernel.org>
+Cc: Ard Biesheuvel <ardb@kernel.org>
+Cc: Ryan Roberts <ryan.roberts@arm.com>
+Cc: Mark Rutland <mark.rutland@arm.com>
+Cc: linux-arm-kernel@lists.infradead.org
+Cc: linux-kernel@vger.kernel.org
+Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
+Signed-off-by: Anshuman Khandual <anshuman.khandual@arm.com>
+Link: https://lore.kernel.org/r/20250221044227.1145393-7-anshuman.khandual@arm.com
+Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/include/asm/pgtable.h | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
+index abf990ce175b1..665f90443f9e8 100644
+--- a/arch/arm64/include/asm/pgtable.h
++++ b/arch/arm64/include/asm/pgtable.h
+@@ -805,7 +805,8 @@ static inline unsigned long pmd_page_vaddr(pmd_t pmd)
+ pr_err("%s:%d: bad pmd %016llx.\n", __FILE__, __LINE__, pmd_val(e))
+
+ #define pud_none(pud) (!pud_val(pud))
+-#define pud_bad(pud) (!pud_table(pud))
++#define pud_bad(pud) ((pud_val(pud) & PUD_TYPE_MASK) != \
++ PUD_TYPE_TABLE)
+ #define pud_present(pud) pte_present(pud_pte(pud))
+ #ifndef __PAGETABLE_PMD_FOLDED
+ #define pud_leaf(pud) (pud_present(pud) && !pud_table(pud))
+--
+2.39.5
+
--- /dev/null
+From e43db54c5e685e5659cf567c6b10f782b0fed4b2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 24 Feb 2025 12:17:36 +0000
+Subject: arm64: tegra: p2597: Fix gpio for vdd-1v8-dis regulator
+
+From: Diogo Ivo <diogo.ivo@tecnico.ulisboa.pt>
+
+[ Upstream commit f34621f31e3be81456c903287f7e4c0609829e29 ]
+
+According to the board schematics the enable pin of this regulator is
+connected to gpio line #9 of the first instance of the TCA9539
+GPIO expander, so adjust it.
+
+Signed-off-by: Diogo Ivo <diogo.ivo@tecnico.ulisboa.pt>
+Link: https://lore.kernel.org/r/20250224-diogo-gpio_exp-v1-1-80fb84ac48c6@tecnico.ulisboa.pt
+Signed-off-by: Thierry Reding <treding@nvidia.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi b/arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi
+index 63b94a04308e8..38d49d612c0c1 100644
+--- a/arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi
++++ b/arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi
+@@ -1686,7 +1686,7 @@ vdd_1v8_dis: regulator-vdd-1v8-dis {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+- gpio = <&exp1 14 GPIO_ACTIVE_HIGH>;
++ gpio = <&exp1 9 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ vin-supply = <&vdd_1v8>;
+ };
+--
+2.39.5
+
--- /dev/null
+From b17ff675d485859f9ee6308ac3d1e86bd2bbc7cd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Jan 2025 15:19:03 +0000
+Subject: arm64: tegra: Resize aperture for the IGX PCIe C5 slot
+
+From: Jon Hunter <jonathanh@nvidia.com>
+
+[ Upstream commit 6d4bfe6d86af1ef52bdb4592c9afb2037f24f2c4 ]
+
+Some discrete graphics cards such as the NVIDIA RTX A6000 support
+resizable BARs. When connecting an A6000 card to the NVIDIA IGX Orin
+platform, resizing the BAR1 aperture to 8GB fails because the current
+device-tree configuration for the PCIe C5 slot cannot support this.
+Fix this by updating the device-tree 'reg' and 'ranges' properties for
+the PCIe C5 slot to support this.
+
+Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
+Link: https://lore.kernel.org/r/20250116151903.476047-1-jonathanh@nvidia.com
+Signed-off-by: Thierry Reding <treding@nvidia.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../boot/dts/nvidia/tegra234-p3740-0002+p3701-0008.dts | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/arch/arm64/boot/dts/nvidia/tegra234-p3740-0002+p3701-0008.dts b/arch/arm64/boot/dts/nvidia/tegra234-p3740-0002+p3701-0008.dts
+index 36e8880537460..9ce55b4d2de89 100644
+--- a/arch/arm64/boot/dts/nvidia/tegra234-p3740-0002+p3701-0008.dts
++++ b/arch/arm64/boot/dts/nvidia/tegra234-p3740-0002+p3701-0008.dts
+@@ -302,6 +302,16 @@ pcie@14160000 {
+ };
+
+ pcie@141a0000 {
++ reg = <0x00 0x141a0000 0x0 0x00020000 /* appl registers (128K) */
++ 0x00 0x3a000000 0x0 0x00040000 /* configuration space (256K) */
++ 0x00 0x3a040000 0x0 0x00040000 /* iATU_DMA reg space (256K) */
++ 0x00 0x3a080000 0x0 0x00040000 /* DBI reg space (256K) */
++ 0x2e 0x20000000 0x0 0x10000000>; /* ECAM (256MB) */
++
++ ranges = <0x81000000 0x00 0x3a100000 0x00 0x3a100000 0x0 0x00100000 /* downstream I/O (1MB) */
++ 0x82000000 0x00 0x40000000 0x2e 0x30000000 0x0 0x08000000 /* non-prefetchable memory (128MB) */
++ 0xc3000000 0x28 0x00000000 0x28 0x00000000 0x6 0x20000000>; /* prefetchable memory (25088MB) */
++
+ status = "okay";
+ vddio-pex-ctl-supply = <&vdd_1v8_ls>;
+ phys = <&p2u_nvhs_0>, <&p2u_nvhs_1>, <&p2u_nvhs_2>,
+--
+2.39.5
+
--- /dev/null
+From 32516cbba63b33e5730563bccc5a80bfc63b70ce Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 22 Nov 2024 01:57:12 -0800
+Subject: arm64: zynqmp: add clock-output-names property in clock nodes
+
+From: Naman Trivedi <naman.trivedimanojbhai@amd.com>
+
+[ Upstream commit 385a59e7f7fb3438466a0712cc14672c708bbd57 ]
+
+Add clock-output-names property to clock nodes, so that the resulting
+clock name do not change when clock node name is changed.
+Also, replace underscores with hyphens in the clock node names as per
+dt-schema rule.
+
+Signed-off-by: Naman Trivedi <naman.trivedimanojbhai@amd.com>
+Acked-by: Senthil Nathan Thangaraj <senthilnathan.thangaraj@amd.com>
+Link: https://lore.kernel.org/r/20241122095712.1166883-1-naman.trivedimanojbhai@amd.com
+Signed-off-by: Michal Simek <michal.simek@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/boot/dts/xilinx/zynqmp-clk-ccf.dtsi | 15 ++++++++++-----
+ 1 file changed, 10 insertions(+), 5 deletions(-)
+
+diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-clk-ccf.dtsi b/arch/arm64/boot/dts/xilinx/zynqmp-clk-ccf.dtsi
+index 60d1b1acf9a03..385fed8a852af 100644
+--- a/arch/arm64/boot/dts/xilinx/zynqmp-clk-ccf.dtsi
++++ b/arch/arm64/boot/dts/xilinx/zynqmp-clk-ccf.dtsi
+@@ -10,39 +10,44 @@
+
+ #include <dt-bindings/clock/xlnx-zynqmp-clk.h>
+ / {
+- pss_ref_clk: pss_ref_clk {
++ pss_ref_clk: pss-ref-clk {
+ bootph-all;
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <33333333>;
++ clock-output-names = "pss_ref_clk";
+ };
+
+- video_clk: video_clk {
++ video_clk: video-clk {
+ bootph-all;
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <27000000>;
++ clock-output-names = "video_clk";
+ };
+
+- pss_alt_ref_clk: pss_alt_ref_clk {
++ pss_alt_ref_clk: pss-alt-ref-clk {
+ bootph-all;
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <0>;
++ clock-output-names = "pss_alt_ref_clk";
+ };
+
+- gt_crx_ref_clk: gt_crx_ref_clk {
++ gt_crx_ref_clk: gt-crx-ref-clk {
+ bootph-all;
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <108000000>;
++ clock-output-names = "gt_crx_ref_clk";
+ };
+
+- aux_ref_clk: aux_ref_clk {
++ aux_ref_clk: aux-ref-clk {
+ bootph-all;
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <27000000>;
++ clock-output-names = "aux_ref_clk";
+ };
+ };
+
+--
+2.39.5
+
--- /dev/null
+From 491c74204b2114923fee42d9dff5430219521126 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Feb 2025 15:10:43 +0100
+Subject: ASoC: codecs: pcm3168a: Allow for 24-bit in provider mode
+
+From: Cezary Rojewski <cezary.rojewski@intel.com>
+
+[ Upstream commit 7d92a38d67e5d937b64b20aa4fd14451ee1772f3 ]
+
+As per codec device specification, 24-bit is allowed in provider mode.
+Update the code to reflect that.
+
+Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
+Link: https://patch.msgid.link/20250203141051.2361323-4-cezary.rojewski@intel.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/codecs/pcm3168a.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c
+index fac0617ab95b6..6cbb8d0535b02 100644
+--- a/sound/soc/codecs/pcm3168a.c
++++ b/sound/soc/codecs/pcm3168a.c
+@@ -493,9 +493,9 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
+ }
+ break;
+ case 24:
+- if (provider_mode || (format == SND_SOC_DAIFMT_DSP_A) ||
+- (format == SND_SOC_DAIFMT_DSP_B)) {
+- dev_err(component->dev, "24-bit slots not supported in provider mode, or consumer mode using DSP\n");
++ if (!provider_mode && ((format == SND_SOC_DAIFMT_DSP_A) ||
++ (format == SND_SOC_DAIFMT_DSP_B))) {
++ dev_err(component->dev, "24-bit slots not supported in consumer mode using DSP\n");
+ return -EINVAL;
+ }
+ break;
+--
+2.39.5
+
--- /dev/null
+From e5d46a77bce5d53e0b86e47b95f099851d1e8c6e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 12 Mar 2025 20:24:59 +0100
+Subject: ASoC: codecs: wsa883x: Correct VI sense channel mask
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+[ Upstream commit ed3b274abc4008efffebf1997968a3f2720a86d3 ]
+
+VI sense port on WSA883x speaker takes only one channel, so use 0x1 as
+channel mask. This fixes garbage being recorded by the speaker when
+testing the VI sense feedback path.
+
+Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Link: https://patch.msgid.link/20250312-asoc-wsa88xx-visense-v1-1-9ca705881122@linaro.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/codecs/wsa883x.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c
+index 47da5674d7c92..e31b7fb104e6c 100644
+--- a/sound/soc/codecs/wsa883x.c
++++ b/sound/soc/codecs/wsa883x.c
+@@ -529,7 +529,7 @@ static const struct sdw_port_config wsa883x_pconfig[WSA883X_MAX_SWR_PORTS] = {
+ },
+ [WSA883X_PORT_VISENSE] = {
+ .num = WSA883X_PORT_VISENSE + 1,
+- .ch_mask = 0x3,
++ .ch_mask = 0x1,
+ },
+ };
+
+--
+2.39.5
+
--- /dev/null
+From 42135e421810a700b1358625b71281351306372a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 12 Mar 2025 20:25:00 +0100
+Subject: ASoC: codecs: wsa884x: Correct VI sense channel mask
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+[ Upstream commit 060fac202eb8e5c83961f0e0bf6dad8ab6e46643 ]
+
+VI sense port on WSA883x speaker takes only one channel, so use 0x1 as
+channel mask. This fixes garbage being recorded by the speaker when
+testing the VI sense feedback path.
+
+Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Link: https://patch.msgid.link/20250312-asoc-wsa88xx-visense-v1-2-9ca705881122@linaro.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/codecs/wsa884x.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/sound/soc/codecs/wsa884x.c b/sound/soc/codecs/wsa884x.c
+index 560a2c04b6955..18b0ee8f15a55 100644
+--- a/sound/soc/codecs/wsa884x.c
++++ b/sound/soc/codecs/wsa884x.c
+@@ -891,7 +891,7 @@ static const struct sdw_port_config wsa884x_pconfig[WSA884X_MAX_SWR_PORTS] = {
+ },
+ [WSA884X_PORT_VISENSE] = {
+ .num = WSA884X_PORT_VISENSE + 1,
+- .ch_mask = 0x3,
++ .ch_mask = 0x1,
+ },
+ [WSA884X_PORT_CPS] = {
+ .num = WSA884X_PORT_CPS + 1,
+--
+2.39.5
+
--- /dev/null
+From fc8150f4c070de9f96ed9def2fb7033d1e0712b5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 23 Apr 2025 10:09:44 +0100
+Subject: ASoC: cs42l43: Disable headphone clamps during type detection
+
+From: Charles Keepax <ckeepax@opensource.cirrus.com>
+
+[ Upstream commit 70ad2e6bd180f94be030aef56e59693e36d945f3 ]
+
+The headphone clamps cause fairly loud pops during type detect
+because they sink current from the detection process itself. Disable
+the clamps whilst the type detect runs, to improve the detection
+pop performance.
+
+Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
+Link: https://patch.msgid.link/20250423090944.1504538-1-ckeepax@opensource.cirrus.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/codecs/cs42l43-jack.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/sound/soc/codecs/cs42l43-jack.c b/sound/soc/codecs/cs42l43-jack.c
+index 20e6ab6f0d4ad..6165ac16c3a95 100644
+--- a/sound/soc/codecs/cs42l43-jack.c
++++ b/sound/soc/codecs/cs42l43-jack.c
+@@ -654,6 +654,10 @@ static int cs42l43_run_type_detect(struct cs42l43_codec *priv)
+
+ reinit_completion(&priv->type_detect);
+
++ regmap_update_bits(cs42l43->regmap, CS42L43_STEREO_MIC_CLAMP_CTRL,
++ CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_VAL_MASK,
++ CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_VAL_MASK);
++
+ cs42l43_start_hs_bias(priv, true);
+ regmap_update_bits(cs42l43->regmap, CS42L43_HS2,
+ CS42L43_HSDET_MODE_MASK, 0x3 << CS42L43_HSDET_MODE_SHIFT);
+@@ -665,6 +669,9 @@ static int cs42l43_run_type_detect(struct cs42l43_codec *priv)
+ CS42L43_HSDET_MODE_MASK, 0x2 << CS42L43_HSDET_MODE_SHIFT);
+ cs42l43_stop_hs_bias(priv);
+
++ regmap_update_bits(cs42l43->regmap, CS42L43_STEREO_MIC_CLAMP_CTRL,
++ CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_VAL_MASK, 0);
++
+ if (!time_left)
+ return -ETIMEDOUT;
+
+--
+2.39.5
+
--- /dev/null
+From bffa28a9208592089e868ab261deeaa68599e94d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 6 Apr 2025 16:08:54 -0500
+Subject: ASoC: imx-card: Adjust over allocation of memory in
+ imx_card_parse_of()
+
+From: Chenyuan Yang <chenyuan0y@gmail.com>
+
+[ Upstream commit a9a69c3b38c89d7992fb53db4abb19104b531d32 ]
+
+Incorrect types are used as sizeof() arguments in devm_kcalloc().
+It should be sizeof(dai_link_data) for link_data instead of
+sizeof(snd_soc_dai_link).
+
+This is found by our static analysis tool.
+
+Signed-off-by: Chenyuan Yang <chenyuan0y@gmail.com>
+Link: https://patch.msgid.link/20250406210854.149316-1-chenyuan0y@gmail.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/fsl/imx-card.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/sound/soc/fsl/imx-card.c b/sound/soc/fsl/imx-card.c
+index 21f617f6f9fa8..566214cb3d60c 100644
+--- a/sound/soc/fsl/imx-card.c
++++ b/sound/soc/fsl/imx-card.c
+@@ -543,7 +543,7 @@ static int imx_card_parse_of(struct imx_card_data *data)
+ if (!card->dai_link)
+ return -ENOMEM;
+
+- data->link_data = devm_kcalloc(dev, num_links, sizeof(*link), GFP_KERNEL);
++ data->link_data = devm_kcalloc(dev, num_links, sizeof(*link_data), GFP_KERNEL);
+ if (!data->link_data)
+ return -ENOMEM;
+
+--
+2.39.5
+
--- /dev/null
+From 9f4f24185a20566bc046232af7a1e516c8eb5466 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 20 Apr 2025 10:56:59 +0200
+Subject: ASoC: Intel: bytcr_rt5640: Add DMI quirk for Acer Aspire SW3-013
+
+From: Takashi Iwai <tiwai@suse.de>
+
+[ Upstream commit a549b927ea3f5e50b1394209b64e6e17e31d4db8 ]
+
+Acer Aspire SW3-013 requires the very same quirk as other Acer Aspire
+model for making it working.
+
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=220011
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Link: https://patch.msgid.link/20250420085716.12095-1-tiwai@suse.de
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/intel/boards/bytcr_rt5640.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c
+index 6446cda0f8572..0f3b8f44e7011 100644
+--- a/sound/soc/intel/boards/bytcr_rt5640.c
++++ b/sound/soc/intel/boards/bytcr_rt5640.c
+@@ -576,6 +576,19 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
+ BYT_RT5640_SSP0_AIF2 |
+ BYT_RT5640_MCLK_EN),
+ },
++ { /* Acer Aspire SW3-013 */
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
++ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW3-013"),
++ },
++ .driver_data = (void *)(BYT_RT5640_DMIC1_MAP |
++ BYT_RT5640_JD_SRC_JD2_IN4N |
++ BYT_RT5640_OVCD_TH_2000UA |
++ BYT_RT5640_OVCD_SF_0P75 |
++ BYT_RT5640_DIFF_MIC |
++ BYT_RT5640_SSP0_AIF1 |
++ BYT_RT5640_MCLK_EN),
++ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+--
+2.39.5
+
--- /dev/null
+From 12d7e4f7c5dbc8b92a3bff459def8b22f2548754 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 30 Apr 2025 11:31:20 +0100
+Subject: ASoC: intel/sdw_utils: Add volume limit to cs35l56 speakers
+
+From: Stefan Binding <sbinding@opensource.cirrus.com>
+
+[ Upstream commit d5463e531c128ff1b141fdba2e13345cd50028a4 ]
+
+The volume control for cs35l56 speakers has a maximum gain of +12 dB.
+However, for many use cases, this can cause distorted audio, depending
+various factors, such as other signal-processing elements in the chain,
+for example if the audio passes through a gain control before reaching
+the amp or the signal path has been tuned for a particular maximum
+gain in the amp.
+
+In the case of systems which use the soc_sdw_* driver, audio will
+likely be distorted in all cases above 0 dB, therefore add a volume
+limit of 400, which is 0 dB maximum volume inside this driver.
+
+The volume limit should be applied to both soundwire and soundwire
+bridge configurations.
+
+Signed-off-by: Stefan Binding <sbinding@opensource.cirrus.com>
+Link: https://patch.msgid.link/20250430103134.24579-3-sbinding@opensource.cirrus.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/sound/soc_sdw_utils.h | 1 +
+ sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c | 4 ++++
+ sound/soc/sdw_utils/soc_sdw_cs_amp.c | 24 ++++++++++++++++++++
+ 3 files changed, 29 insertions(+)
+
+diff --git a/include/sound/soc_sdw_utils.h b/include/sound/soc_sdw_utils.h
+index 36a4a1e1d8ca2..d8bd5d37131aa 100644
+--- a/include/sound/soc_sdw_utils.h
++++ b/include/sound/soc_sdw_utils.h
+@@ -226,6 +226,7 @@ int asoc_sdw_cs_amp_init(struct snd_soc_card *card,
+ bool playback);
+ int asoc_sdw_cs_spk_feedback_rtd_init(struct snd_soc_pcm_runtime *rtd,
+ struct snd_soc_dai *dai);
++int asoc_sdw_cs35l56_volume_limit(struct snd_soc_card *card, const char *name_prefix);
+
+ /* MAXIM codec support */
+ int asoc_sdw_maxim_init(struct snd_soc_card *card,
+diff --git a/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c b/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c
+index 246e5c2e0af55..c7e55f4433514 100644
+--- a/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c
++++ b/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c
+@@ -60,6 +60,10 @@ static int asoc_sdw_bridge_cs35l56_asp_init(struct snd_soc_pcm_runtime *rtd)
+
+ /* 4 x 16-bit sample slots and FSYNC=48000, BCLK=3.072 MHz */
+ for_each_rtd_codec_dais(rtd, i, codec_dai) {
++ ret = asoc_sdw_cs35l56_volume_limit(card, codec_dai->component->name_prefix);
++ if (ret)
++ return ret;
++
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, tx_mask, rx_mask, 4, 16);
+ if (ret < 0)
+ return ret;
+diff --git a/sound/soc/sdw_utils/soc_sdw_cs_amp.c b/sound/soc/sdw_utils/soc_sdw_cs_amp.c
+index 4b6181cf29716..35b550bcd4ded 100644
+--- a/sound/soc/sdw_utils/soc_sdw_cs_amp.c
++++ b/sound/soc/sdw_utils/soc_sdw_cs_amp.c
+@@ -16,6 +16,25 @@
+
+ #define CODEC_NAME_SIZE 8
+ #define CS_AMP_CHANNELS_PER_AMP 4
++#define CS35L56_SPK_VOLUME_0DB 400 /* 0dB Max */
++
++int asoc_sdw_cs35l56_volume_limit(struct snd_soc_card *card, const char *name_prefix)
++{
++ char *volume_ctl_name;
++ int ret;
++
++ volume_ctl_name = kasprintf(GFP_KERNEL, "%s Speaker Volume", name_prefix);
++ if (!volume_ctl_name)
++ return -ENOMEM;
++
++ ret = snd_soc_limit_volume(card, volume_ctl_name, CS35L56_SPK_VOLUME_0DB);
++ if (ret)
++ dev_err(card->dev, "%s limit set failed: %d\n", volume_ctl_name, ret);
++
++ kfree(volume_ctl_name);
++ return ret;
++}
++EXPORT_SYMBOL_NS(asoc_sdw_cs35l56_volume_limit, "SND_SOC_SDW_UTILS");
+
+ int asoc_sdw_cs_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
+ {
+@@ -40,6 +59,11 @@ int asoc_sdw_cs_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai
+
+ snprintf(widget_name, sizeof(widget_name), "%s SPK",
+ codec_dai->component->name_prefix);
++
++ ret = asoc_sdw_cs35l56_volume_limit(card, codec_dai->component->name_prefix);
++ if (ret)
++ return ret;
++
+ ret = snd_soc_dapm_add_routes(&card->dapm, &route, 1);
+ if (ret)
+ return ret;
+--
+2.39.5
+
--- /dev/null
+From 44112ed71664d5436614bf979ac92e7dadca4134 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 30 Apr 2025 11:31:19 +0100
+Subject: ASoC: intel/sdw_utils: Add volume limit to cs42l43 speakers
+
+From: Stefan Binding <sbinding@opensource.cirrus.com>
+
+[ Upstream commit 02b44a2b2bdcee03cbb92484d31e9ca1b91b2a38 ]
+
+The volume control for cs42l43 speakers has a maximum gain of +31.5 dB.
+However, for many use cases, this can cause distorted audio, depending
+various factors, such as other signal-processing elements in the chain,
+for example if the audio passes through a gain control before reaching
+the codec or the signal path has been tuned for a particular maximum
+gain in the codec.
+
+In the case of systems which use the soc_sdw_cs42l43 driver, audio will
+likely be distorted in all cases above 0 dB, therefore add a volume
+limit of 128, which is 0 dB maximum volume inside this driver.
+
+Signed-off-by: Stefan Binding <sbinding@opensource.cirrus.com>
+Reviewed-by: Charles Keepax <ckeepax@opensource.cirrus.com>
+Link: https://patch.msgid.link/20250430103134.24579-2-sbinding@opensource.cirrus.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/sdw_utils/soc_sdw_cs42l43.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/sound/soc/sdw_utils/soc_sdw_cs42l43.c b/sound/soc/sdw_utils/soc_sdw_cs42l43.c
+index 668c9d28a1c12..b415d45d520d0 100644
+--- a/sound/soc/sdw_utils/soc_sdw_cs42l43.c
++++ b/sound/soc/sdw_utils/soc_sdw_cs42l43.c
+@@ -20,6 +20,8 @@
+ #include <sound/soc-dapm.h>
+ #include <sound/soc_sdw_utils.h>
+
++#define CS42L43_SPK_VOLUME_0DB 128 /* 0dB Max */
++
+ static const struct snd_soc_dapm_route cs42l43_hs_map[] = {
+ { "Headphone", NULL, "cs42l43 AMP3_OUT" },
+ { "Headphone", NULL, "cs42l43 AMP4_OUT" },
+@@ -117,6 +119,14 @@ int asoc_sdw_cs42l43_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_so
+ return -ENOMEM;
+ }
+
++ ret = snd_soc_limit_volume(card, "cs42l43 Speaker Digital Volume",
++ CS42L43_SPK_VOLUME_0DB);
++ if (ret)
++ dev_err(card->dev, "cs42l43 speaker volume limit failed: %d\n", ret);
++ else
++ dev_info(card->dev, "Setting CS42L43 Speaker volume limit to %d\n",
++ CS42L43_SPK_VOLUME_0DB);
++
+ ret = snd_soc_dapm_add_routes(&card->dapm, cs42l43_spk_map,
+ ARRAY_SIZE(cs42l43_spk_map));
+ if (ret)
+--
+2.39.5
+
--- /dev/null
+From 56e13e31fc8aa7c938fbdc5b53a719e8c77b7f63 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Mar 2025 16:52:17 -0300
+Subject: ASoC: mediatek: mt6359: Add stub for mt6359_accdet_enable_jack_detect
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Nícolas F. R. A. Prado <nfraprado@collabora.com>
+
+[ Upstream commit 0116a7d84b32537a10d9bea1fd1bfc06577ef527 ]
+
+Add a stub for mt6359_accdet_enable_jack_detect() to prevent linker
+failures in the machine sound drivers calling it when
+CONFIG_SND_SOC_MT6359_ACCDET is not enabled.
+
+Suggested-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Signed-off-by: Nícolas F. R. A. Prado <nfraprado@collabora.com>
+Link: https://patch.msgid.link/20250306-mt8188-accdet-v3-3-7828e835ff4b@collabora.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/codecs/mt6359-accdet.h | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/sound/soc/codecs/mt6359-accdet.h b/sound/soc/codecs/mt6359-accdet.h
+index c234f2f4276a1..78ada3a5bfae5 100644
+--- a/sound/soc/codecs/mt6359-accdet.h
++++ b/sound/soc/codecs/mt6359-accdet.h
+@@ -123,6 +123,15 @@ struct mt6359_accdet {
+ struct workqueue_struct *jd_workqueue;
+ };
+
++#if IS_ENABLED(CONFIG_SND_SOC_MT6359_ACCDET)
+ int mt6359_accdet_enable_jack_detect(struct snd_soc_component *component,
+ struct snd_soc_jack *jack);
++#else
++static inline int
++mt6359_accdet_enable_jack_detect(struct snd_soc_component *component,
++ struct snd_soc_jack *jack)
++{
++ return -EOPNOTSUPP;
++}
++#endif
+ #endif
+--
+2.39.5
+
--- /dev/null
+From 26cc06b0925f999cb78d2cc91450ea134be7aca7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 25 Feb 2025 11:33:48 -0300
+Subject: ASoC: mediatek: mt8188: Add reference for dmic clocks
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Nícolas F. R. A. Prado <nfraprado@collabora.com>
+
+[ Upstream commit bf1800073f4d55f08191b034c86b95881e99b6fd ]
+
+Add the names for the dmic clocks, aud_afe_dmic* and aud_dmic_hires*, so
+they can be acquired and enabled by the platform driver.
+
+Signed-off-by: Nícolas F. R. A. Prado <nfraprado@collabora.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://patch.msgid.link/20250225-genio700-dmic-v2-2-3076f5b50ef7@collabora.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/mediatek/mt8188/mt8188-afe-clk.c | 8 ++++++++
+ sound/soc/mediatek/mt8188/mt8188-afe-clk.h | 8 ++++++++
+ 2 files changed, 16 insertions(+)
+
+diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-clk.c b/sound/soc/mediatek/mt8188/mt8188-afe-clk.c
+index e69c1bb2cb239..7f411b8577823 100644
+--- a/sound/soc/mediatek/mt8188/mt8188-afe-clk.c
++++ b/sound/soc/mediatek/mt8188/mt8188-afe-clk.c
+@@ -58,7 +58,15 @@ static const char *aud_clks[MT8188_CLK_NUM] = {
+ [MT8188_CLK_AUD_ADC] = "aud_adc",
+ [MT8188_CLK_AUD_DAC_HIRES] = "aud_dac_hires",
+ [MT8188_CLK_AUD_A1SYS_HP] = "aud_a1sys_hp",
++ [MT8188_CLK_AUD_AFE_DMIC1] = "aud_afe_dmic1",
++ [MT8188_CLK_AUD_AFE_DMIC2] = "aud_afe_dmic2",
++ [MT8188_CLK_AUD_AFE_DMIC3] = "aud_afe_dmic3",
++ [MT8188_CLK_AUD_AFE_DMIC4] = "aud_afe_dmic4",
+ [MT8188_CLK_AUD_ADC_HIRES] = "aud_adc_hires",
++ [MT8188_CLK_AUD_DMIC_HIRES1] = "aud_dmic_hires1",
++ [MT8188_CLK_AUD_DMIC_HIRES2] = "aud_dmic_hires2",
++ [MT8188_CLK_AUD_DMIC_HIRES3] = "aud_dmic_hires3",
++ [MT8188_CLK_AUD_DMIC_HIRES4] = "aud_dmic_hires4",
+ [MT8188_CLK_AUD_I2SIN] = "aud_i2sin",
+ [MT8188_CLK_AUD_TDM_IN] = "aud_tdm_in",
+ [MT8188_CLK_AUD_I2S_OUT] = "aud_i2s_out",
+diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-clk.h b/sound/soc/mediatek/mt8188/mt8188-afe-clk.h
+index ec53c171c170a..c6c78d684f3ee 100644
+--- a/sound/soc/mediatek/mt8188/mt8188-afe-clk.h
++++ b/sound/soc/mediatek/mt8188/mt8188-afe-clk.h
+@@ -54,7 +54,15 @@ enum {
+ MT8188_CLK_AUD_ADC,
+ MT8188_CLK_AUD_DAC_HIRES,
+ MT8188_CLK_AUD_A1SYS_HP,
++ MT8188_CLK_AUD_AFE_DMIC1,
++ MT8188_CLK_AUD_AFE_DMIC2,
++ MT8188_CLK_AUD_AFE_DMIC3,
++ MT8188_CLK_AUD_AFE_DMIC4,
+ MT8188_CLK_AUD_ADC_HIRES,
++ MT8188_CLK_AUD_DMIC_HIRES1,
++ MT8188_CLK_AUD_DMIC_HIRES2,
++ MT8188_CLK_AUD_DMIC_HIRES3,
++ MT8188_CLK_AUD_DMIC_HIRES4,
+ MT8188_CLK_AUD_I2SIN,
+ MT8188_CLK_AUD_TDM_IN,
+ MT8188_CLK_AUD_I2S_OUT,
+--
+2.39.5
+
--- /dev/null
+From ef2d751ff692b41e55a44e7a3b64187348fe1163 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 25 Feb 2025 11:33:49 -0300
+Subject: ASoC: mediatek: mt8188: Treat DMIC_GAINx_CUR as non-volatile
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Nícolas F. R. A. Prado <nfraprado@collabora.com>
+
+[ Upstream commit 7d87bde21c73731ddaf15e572020f80999c38ee3 ]
+
+The DMIC_GAINx_CUR registers contain the current (as in present) gain of
+each DMIC. During capture, this gain will ramp up until a target value
+is reached, and therefore the register is volatile since it is updated
+automatically by hardware.
+
+However, after capture the register's value returns to the value that
+was written to it. So reading these registers returns the current gain,
+and writing configures the initial gain for every capture.
+
+>From an audio configuration perspective, reading the instantaneous gain
+is not really useful. Instead, reading back the initial gain that was
+configured is the desired behavior. For that reason, consider the
+DMIC_GAINx_CUR registers as non-volatile, so the regmap's cache can be
+used to retrieve the values, rather than requiring pm runtime resuming
+the device.
+
+Signed-off-by: Nícolas F. R. A. Prado <nfraprado@collabora.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://patch.msgid.link/20250225-genio700-dmic-v2-3-3076f5b50ef7@collabora.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/mediatek/mt8188/mt8188-afe-pcm.c | 4 ----
+ 1 file changed, 4 deletions(-)
+
+diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c
+index 73e5c63aeec87..d36520c6272dd 100644
+--- a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c
++++ b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c
+@@ -2855,10 +2855,6 @@ static bool mt8188_is_volatile_reg(struct device *dev, unsigned int reg)
+ case AFE_DMIC3_SRC_DEBUG_MON0:
+ case AFE_DMIC3_UL_SRC_MON0:
+ case AFE_DMIC3_UL_SRC_MON1:
+- case DMIC_GAIN1_CUR:
+- case DMIC_GAIN2_CUR:
+- case DMIC_GAIN3_CUR:
+- case DMIC_GAIN4_CUR:
+ case ETDM_IN1_MONITOR:
+ case ETDM_IN2_MONITOR:
+ case ETDM_OUT1_MONITOR:
+--
+2.39.5
+
--- /dev/null
+From f544b9d71044602e2c971a80e78a87cada75089d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 8 Feb 2025 00:57:22 +0000
+Subject: ASoC: ops: Enforce platform maximum on initial value
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Martin Povišer <povik+lin@cutebit.org>
+
+[ Upstream commit 783db6851c1821d8b983ffb12b99c279ff64f2ee ]
+
+Lower the volume if it is violating the platform maximum at its initial
+value (i.e. at the time of the 'snd_soc_limit_volume' call).
+
+Signed-off-by: Martin Povišer <povik+lin@cutebit.org>
+[Cherry picked from the Asahi kernel with fixups -- broonie]
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Link: https://patch.msgid.link/20250208-asoc-volume-limit-v1-1-b98fcf4cdbad@kernel.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/soc-ops.c | 29 ++++++++++++++++++++++++++++-
+ 1 file changed, 28 insertions(+), 1 deletion(-)
+
+diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c
+index b0e4e4168f38d..fb11003d56cf6 100644
+--- a/sound/soc/soc-ops.c
++++ b/sound/soc/soc-ops.c
+@@ -639,6 +639,33 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol,
+ }
+ EXPORT_SYMBOL_GPL(snd_soc_get_volsw_range);
+
++static int snd_soc_clip_to_platform_max(struct snd_kcontrol *kctl)
++{
++ struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value;
++ struct snd_ctl_elem_value uctl;
++ int ret;
++
++ if (!mc->platform_max)
++ return 0;
++
++ ret = kctl->get(kctl, &uctl);
++ if (ret < 0)
++ return ret;
++
++ if (uctl.value.integer.value[0] > mc->platform_max)
++ uctl.value.integer.value[0] = mc->platform_max;
++
++ if (snd_soc_volsw_is_stereo(mc) &&
++ uctl.value.integer.value[1] > mc->platform_max)
++ uctl.value.integer.value[1] = mc->platform_max;
++
++ ret = kctl->put(kctl, &uctl);
++ if (ret < 0)
++ return ret;
++
++ return 0;
++}
++
+ /**
+ * snd_soc_limit_volume - Set new limit to an existing volume control.
+ *
+@@ -663,7 +690,7 @@ int snd_soc_limit_volume(struct snd_soc_card *card,
+ struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value;
+ if (max <= mc->max - mc->min) {
+ mc->platform_max = max;
+- ret = 0;
++ ret = snd_soc_clip_to_platform_max(kctl);
+ }
+ }
+ return ret;
+--
+2.39.5
+
--- /dev/null
+From 1da39871bce05a83ffd4357fa9329a2f5d73000c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 12 Mar 2025 14:31:52 +0100
+Subject: ASoC: pcm6240: Drop bogus code handling IRQ as GPIO
+
+From: Linus Walleij <linus.walleij@linaro.org>
+
+[ Upstream commit 17fdf318f5fbe5c27353ae917c0c5a2899d9c259 ]
+
+The current code for the IRQ in pcm6240 makes no sense:
+it looks up an IRQ with of_irq_get(), treat it as a GPIO
+by issuing gpio_request(), gpio_direction_input()
+and gpio_to_irq() on it.
+
+This is just wrong, if the device tree assigns the IRQ
+from a GPIO number this is just incorrect: it is clearly
+stated that GPIO providers and IRQ providers are
+orthogonal.
+
+It is possible to look up an IRQ to a corresponding GPIO
+line but this is taking an IRQ and pretending it's a
+GPIO, which is just semantically wrong.
+
+Drop the offending code and treat the IRQ that we get
+from the device tree as any other IRQ, see for example
+other codec drivers.
+
+The DT bindings for this codec does not have any in-tree
+DTS files, which may explain why things are weird.
+
+As a bonus, this moves the driver away from the legacy
+<linux/gpio.h> include.
+
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Link: https://patch.msgid.link/20250312-pcm-codecs-v1-3-41ffc4f8fc5c@linaro.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/codecs/pcm6240.c | 28 +++++++---------------------
+ sound/soc/codecs/pcm6240.h | 7 +------
+ 2 files changed, 8 insertions(+), 27 deletions(-)
+
+diff --git a/sound/soc/codecs/pcm6240.c b/sound/soc/codecs/pcm6240.c
+index 4ff39e0b95b27..b2bd2f172ae76 100644
+--- a/sound/soc/codecs/pcm6240.c
++++ b/sound/soc/codecs/pcm6240.c
+@@ -14,7 +14,7 @@
+
+ #include <linux/unaligned.h>
+ #include <linux/firmware.h>
+-#include <linux/gpio.h>
++#include <linux/gpio/consumer.h>
+ #include <linux/i2c.h>
+ #include <linux/module.h>
+ #include <linux/of_irq.h>
+@@ -2035,10 +2035,8 @@ static const struct regmap_config pcmdevice_i2c_regmap = {
+
+ static void pcmdevice_remove(struct pcmdevice_priv *pcm_dev)
+ {
+- if (gpio_is_valid(pcm_dev->irq_info.gpio)) {
+- gpio_free(pcm_dev->irq_info.gpio);
+- free_irq(pcm_dev->irq_info.nmb, pcm_dev);
+- }
++ if (pcm_dev->irq)
++ free_irq(pcm_dev->irq, pcm_dev);
+ mutex_destroy(&pcm_dev->codec_lock);
+ }
+
+@@ -2109,7 +2107,7 @@ static int pcmdevice_i2c_probe(struct i2c_client *i2c)
+ ndev = 1;
+ dev_addrs[0] = i2c->addr;
+ }
+- pcm_dev->irq_info.gpio = of_irq_get(np, 0);
++ pcm_dev->irq = of_irq_get(np, 0);
+
+ for (i = 0; i < ndev; i++)
+ pcm_dev->addr[i] = dev_addrs[i];
+@@ -2132,22 +2130,10 @@ static int pcmdevice_i2c_probe(struct i2c_client *i2c)
+
+ if (pcm_dev->chip_id == PCM1690)
+ goto skip_interrupt;
+- if (gpio_is_valid(pcm_dev->irq_info.gpio)) {
+- dev_dbg(pcm_dev->dev, "irq-gpio = %d", pcm_dev->irq_info.gpio);
+-
+- ret = gpio_request(pcm_dev->irq_info.gpio, "PCMDEV-IRQ");
+- if (!ret) {
+- int gpio = pcm_dev->irq_info.gpio;
+-
+- gpio_direction_input(gpio);
+- pcm_dev->irq_info.nmb = gpio_to_irq(gpio);
+-
+- } else
+- dev_err(pcm_dev->dev, "%s: GPIO %d request error\n",
+- __func__, pcm_dev->irq_info.gpio);
++ if (pcm_dev->irq) {
++ dev_dbg(pcm_dev->dev, "irq = %d", pcm_dev->irq);
+ } else
+- dev_err(pcm_dev->dev, "Looking up irq-gpio failed %d\n",
+- pcm_dev->irq_info.gpio);
++ dev_err(pcm_dev->dev, "No irq provided\n");
+
+ skip_interrupt:
+ ret = devm_snd_soc_register_component(&i2c->dev,
+diff --git a/sound/soc/codecs/pcm6240.h b/sound/soc/codecs/pcm6240.h
+index 1e125bb972860..2d8f9e798139a 100644
+--- a/sound/soc/codecs/pcm6240.h
++++ b/sound/soc/codecs/pcm6240.h
+@@ -208,11 +208,6 @@ struct pcmdevice_regbin {
+ struct pcmdevice_config_info **cfg_info;
+ };
+
+-struct pcmdevice_irqinfo {
+- int gpio;
+- int nmb;
+-};
+-
+ struct pcmdevice_priv {
+ struct snd_soc_component *component;
+ struct i2c_client *client;
+@@ -221,7 +216,7 @@ struct pcmdevice_priv {
+ struct gpio_desc *hw_rst;
+ struct regmap *regmap;
+ struct pcmdevice_regbin regbin;
+- struct pcmdevice_irqinfo irq_info;
++ int irq;
+ unsigned int addr[PCMDEVICE_MAX_I2C_DEVICES];
+ unsigned int chip_id;
+ int cur_conf;
+--
+2.39.5
+
--- /dev/null
+From 4342fa55c01ed83a3fe04cc22b5be6c628731ed1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 28 Feb 2025 16:14:30 +0000
+Subject: ASoC: qcom: sm8250: explicitly set format in
+ sm8250_be_hw_params_fixup()
+
+From: Alexey Klimov <alexey.klimov@linaro.org>
+
+[ Upstream commit 89be3c15a58b2ccf31e969223c8ac93ca8932d81 ]
+
+Setting format to s16le is required for compressed playback on compatible
+soundcards.
+
+Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Signed-off-by: Alexey Klimov <alexey.klimov@linaro.org>
+Link: https://patch.msgid.link/20250228161430.373961-1-alexey.klimov@linaro.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/qcom/sm8250.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c
+index 45e0c33fc3f37..9039107972e2b 100644
+--- a/sound/soc/qcom/sm8250.c
++++ b/sound/soc/qcom/sm8250.c
+@@ -7,6 +7,7 @@
+ #include <sound/soc.h>
+ #include <sound/soc-dapm.h>
+ #include <sound/pcm.h>
++#include <sound/pcm_params.h>
+ #include <linux/soundwire/sdw.h>
+ #include <sound/jack.h>
+ #include <linux/input-event-codes.h>
+@@ -39,9 +40,11 @@ static int sm8250_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
++ struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
++ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
+
+ return 0;
+ }
+--
+2.39.5
+
--- /dev/null
+From 55bb761a764cf8c6fa27436c070dfc8f22e11628 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 7 Jan 2025 15:44:07 +0000
+Subject: ASoC: rt722-sdca: Add some missing readable registers
+
+From: Charles Keepax <ckeepax@opensource.cirrus.com>
+
+[ Upstream commit f9a5c4b6afc79073491acdab7f1e943ee3a19fbb ]
+
+Add a few missing registers from the readable register callback.
+
+Suggested-by: Shuming Fan <shumingf@realtek.com>
+Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
+Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.dev>
+Link: https://patch.msgid.link/20250107154408.814455-6-ckeepax@opensource.cirrus.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/codecs/rt722-sdca-sdw.c | 49 +++++++++++++++++++++++++++++--
+ 1 file changed, 46 insertions(+), 3 deletions(-)
+
+diff --git a/sound/soc/codecs/rt722-sdca-sdw.c b/sound/soc/codecs/rt722-sdca-sdw.c
+index 4d3043627bd04..cfb030e71e5c5 100644
+--- a/sound/soc/codecs/rt722-sdca-sdw.c
++++ b/sound/soc/codecs/rt722-sdca-sdw.c
+@@ -28,9 +28,50 @@ static bool rt722_sdca_readable_register(struct device *dev, unsigned int reg)
+ 0):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_GE49, RT722_SDCA_CTL_DETECTED_MODE,
+ 0):
+- case SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, RT722_SDCA_CTL_HIDTX_CURRENT_OWNER,
+- 0) ... SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01,
+- RT722_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0):
++ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_XU03, RT722_SDCA_CTL_SELECTED_MODE,
++ 0):
++ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05,
++ RT722_SDCA_CTL_FU_MUTE, CH_L) ...
++ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05,
++ RT722_SDCA_CTL_FU_MUTE, CH_R):
++ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_XU0D,
++ RT722_SDCA_CTL_SELECTED_MODE, 0):
++ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F,
++ RT722_SDCA_CTL_FU_MUTE, CH_L) ...
++ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F,
++ RT722_SDCA_CTL_FU_MUTE, CH_R):
++ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE40,
++ RT722_SDCA_CTL_REQ_POWER_STATE, 0):
++ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE12,
++ RT722_SDCA_CTL_REQ_POWER_STATE, 0):
++ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_CS01,
++ RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0):
++ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_CS11,
++ RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0):
++ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E,
++ RT722_SDCA_CTL_FU_MUTE, CH_01) ...
++ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E,
++ RT722_SDCA_CTL_FU_MUTE, CH_04):
++ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_IT26,
++ RT722_SDCA_CTL_VENDOR_DEF, 0):
++ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_PDE2A,
++ RT722_SDCA_CTL_REQ_POWER_STATE, 0):
++ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_CS1F,
++ RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0):
++ case SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01,
++ RT722_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ...
++ SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01,
++ RT722_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0):
++ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06,
++ RT722_SDCA_CTL_FU_MUTE, CH_L) ...
++ SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06,
++ RT722_SDCA_CTL_FU_MUTE, CH_R):
++ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_OT23,
++ RT722_SDCA_CTL_VENDOR_DEF, CH_08):
++ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_PDE23,
++ RT722_SDCA_CTL_REQ_POWER_STATE, 0):
++ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_CS31,
++ RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0):
+ case RT722_BUF_ADDR_HID1 ... RT722_BUF_ADDR_HID2:
+ return true;
+ default:
+@@ -74,6 +115,7 @@ static bool rt722_sdca_mbq_readable_register(struct device *dev, unsigned int re
+ case 0x5600000 ... 0x5600007:
+ case 0x5700000 ... 0x5700004:
+ case 0x5800000 ... 0x5800004:
++ case 0x5810000:
+ case 0x5b00003:
+ case 0x5c00011:
+ case 0x5d00006:
+@@ -81,6 +123,7 @@ static bool rt722_sdca_mbq_readable_register(struct device *dev, unsigned int re
+ case 0x5f00030:
+ case 0x6100000 ... 0x6100051:
+ case 0x6100055 ... 0x6100057:
++ case 0x6100060:
+ case 0x6100062:
+ case 0x6100064 ... 0x6100065:
+ case 0x6100067:
+--
+2.39.5
+
--- /dev/null
+From 2fc55ed1d59cd9b8e0f11963a462a396f845a4c4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 10 Mar 2025 20:57:14 -0500
+Subject: ASoC: sma1307: Add NULL check in sma1307_setting_loaded()
+
+From: Chenyuan Yang <chenyuan0y@gmail.com>
+
+[ Upstream commit 0ec6bd16705fe21d6429d6b8f7981eae2142bba8 ]
+
+All varibale allocated by kzalloc and devm_kzalloc could be NULL.
+Multiple pointer checks and their cleanup are added.
+
+This issue is found by our static analysis tool
+
+Signed-off-by: Chenyuan Yang <chenyuan0y@gmail.com>
+Link: https://patch.msgid.link/20250311015714.1333857-1-chenyuan0y@gmail.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/codecs/sma1307.c | 28 ++++++++++++++++++++++++++++
+ 1 file changed, 28 insertions(+)
+
+diff --git a/sound/soc/codecs/sma1307.c b/sound/soc/codecs/sma1307.c
+index 480bcea48541e..b9d8136fe3dc1 100644
+--- a/sound/soc/codecs/sma1307.c
++++ b/sound/soc/codecs/sma1307.c
+@@ -1728,6 +1728,11 @@ static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *fil
+ }
+
+ data = kzalloc(fw->size, GFP_KERNEL);
++ if (!data) {
++ release_firmware(fw);
++ sma1307->set.status = false;
++ return;
++ }
+ size = fw->size >> 2;
+ memcpy(data, fw->data, fw->size);
+
+@@ -1741,6 +1746,12 @@ static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *fil
+ sma1307->set.header = devm_kzalloc(sma1307->dev,
+ sma1307->set.header_size,
+ GFP_KERNEL);
++ if (!sma1307->set.header) {
++ kfree(data);
++ sma1307->set.status = false;
++ return;
++ }
++
+ memcpy(sma1307->set.header, data,
+ sma1307->set.header_size * sizeof(int));
+
+@@ -1756,6 +1767,13 @@ static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *fil
+ sma1307->set.def
+ = devm_kzalloc(sma1307->dev,
+ sma1307->set.def_size * sizeof(int), GFP_KERNEL);
++ if (!sma1307->set.def) {
++ kfree(data);
++ kfree(sma1307->set.header);
++ sma1307->set.status = false;
++ return;
++ }
++
+ memcpy(sma1307->set.def,
+ &data[sma1307->set.header_size],
+ sma1307->set.def_size * sizeof(int));
+@@ -1768,6 +1786,16 @@ static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *fil
+ = devm_kzalloc(sma1307->dev,
+ sma1307->set.mode_size * 2 * sizeof(int),
+ GFP_KERNEL);
++ if (!sma1307->set.mode_set[i]) {
++ kfree(data);
++ kfree(sma1307->set.header);
++ kfree(sma1307->set.def);
++ for (int j = 0; j < i; j++)
++ kfree(sma1307->set.mode_set[j]);
++ sma1307->set.status = false;
++ return;
++ }
++
+ for (int j = 0; j < sma1307->set.mode_size; j++) {
+ sma1307->set.mode_set[i][2 * j]
+ = data[offset + ((num_mode + 1) * j)];
+--
+2.39.5
+
--- /dev/null
+From f4966881edd405db56985a0639c1d14297b45ff0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 21 Mar 2025 17:35:25 +0300
+Subject: ASoC: sma1307: Fix error handling in sma1307_setting_loaded()
+
+From: Dan Carpenter <dan.carpenter@linaro.org>
+
+[ Upstream commit 012a6efcc805308b1d90a1056ba963eb08858645 ]
+
+There are a couple bugs in this code:
+
+1) The cleanup code calls kfree(sma1307->set.header) and
+ kfree(sma1307->set.def) but those functions were allocated using
+ devm_kzalloc(). It results in a double free. Delete all these
+ kfree() calls.
+
+2) A missing call to kfree(data) if the checksum was wrong on this error
+ path:
+ if ((sma1307->set.checksum >> 8) != SMA1307_SETTING_CHECKSUM) {
+ Since the "data" pointer is supposed to be freed on every return, I
+ changed that to use the __free(kfree) cleanup attribute.
+
+Fixes: 0ec6bd16705f ("ASoC: sma1307: Add NULL check in sma1307_setting_loaded()")
+Signed-off-by: Dan Carpenter <dan.carpenter@linaro.org>
+Link: https://patch.msgid.link/8d32dd96-1404-4373-9b6c-c612a9c18c4c@stanley.mountain
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/codecs/sma1307.c | 11 ++---------
+ 1 file changed, 2 insertions(+), 9 deletions(-)
+
+diff --git a/sound/soc/codecs/sma1307.c b/sound/soc/codecs/sma1307.c
+index b9d8136fe3dc1..793abec56dd27 100644
+--- a/sound/soc/codecs/sma1307.c
++++ b/sound/soc/codecs/sma1307.c
+@@ -1710,7 +1710,7 @@ static void sma1307_check_fault_worker(struct work_struct *work)
+ static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *file)
+ {
+ const struct firmware *fw;
+- int *data, size, offset, num_mode;
++ int size, offset, num_mode;
+ int ret;
+
+ ret = request_firmware(&fw, file, sma1307->dev);
+@@ -1727,7 +1727,7 @@ static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *fil
+ return;
+ }
+
+- data = kzalloc(fw->size, GFP_KERNEL);
++ int *data __free(kfree) = kzalloc(fw->size, GFP_KERNEL);
+ if (!data) {
+ release_firmware(fw);
+ sma1307->set.status = false;
+@@ -1747,7 +1747,6 @@ static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *fil
+ sma1307->set.header_size,
+ GFP_KERNEL);
+ if (!sma1307->set.header) {
+- kfree(data);
+ sma1307->set.status = false;
+ return;
+ }
+@@ -1768,8 +1767,6 @@ static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *fil
+ = devm_kzalloc(sma1307->dev,
+ sma1307->set.def_size * sizeof(int), GFP_KERNEL);
+ if (!sma1307->set.def) {
+- kfree(data);
+- kfree(sma1307->set.header);
+ sma1307->set.status = false;
+ return;
+ }
+@@ -1787,9 +1784,6 @@ static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *fil
+ sma1307->set.mode_size * 2 * sizeof(int),
+ GFP_KERNEL);
+ if (!sma1307->set.mode_set[i]) {
+- kfree(data);
+- kfree(sma1307->set.header);
+- kfree(sma1307->set.def);
+ for (int j = 0; j < i; j++)
+ kfree(sma1307->set.mode_set[j]);
+ sma1307->set.status = false;
+@@ -1804,7 +1798,6 @@ static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *fil
+ }
+ }
+
+- kfree(data);
+ sma1307->set.status = true;
+
+ }
+--
+2.39.5
+
--- /dev/null
+From 71e5fe9e8e44b570730b10a5727be547d9d4d8dd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 12 Feb 2025 02:24:38 +0000
+Subject: ASoC: soc-dai: check return value at snd_soc_dai_set_tdm_slot()
+
+From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
+[ Upstream commit 7f1186a8d738661b941b298fd6d1d5725ed71428 ]
+
+snd_soc_dai_set_tdm_slot() calls .xlate_tdm_slot_mask() or
+snd_soc_xlate_tdm_slot_mask(), but didn't check its return value.
+Let's check it.
+
+This patch might break existing driver. In such case, let's makes
+each func to void instead of int.
+
+Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+Link: https://patch.msgid.link/87o6z7yk61.wl-kuninori.morimoto.gx@renesas.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/soc-dai.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c
+index ca0308f6d41c1..dc7283ee4dfb0 100644
+--- a/sound/soc/soc-dai.c
++++ b/sound/soc/soc-dai.c
+@@ -275,10 +275,11 @@ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
+
+ if (dai->driver->ops &&
+ dai->driver->ops->xlate_tdm_slot_mask)
+- dai->driver->ops->xlate_tdm_slot_mask(slots,
+- &tx_mask, &rx_mask);
++ ret = dai->driver->ops->xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask);
+ else
+- snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask);
++ ret = snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask);
++ if (ret)
++ goto err;
+
+ for_each_pcm_streams(stream)
+ snd_soc_dai_tdm_mask_set(dai, stream, *tdm_mask[stream]);
+@@ -287,6 +288,7 @@ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
+ dai->driver->ops->set_tdm_slot)
+ ret = dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask,
+ slots, slot_width);
++err:
+ return soc_dai_ret(dai, ret);
+ }
+ EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot);
+--
+2.39.5
+
--- /dev/null
+From 8e03b7b3bca2c32a98f7cd96de934381b2e11c8f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 15 Feb 2025 11:02:24 +1300
+Subject: ASoC: sun4i-codec: correct dapm widgets and controls for h616
+
+From: Ryan Walklin <ryan@testtoast.com>
+
+[ Upstream commit ae5f76d4044d1580849316c49290678605e0889d ]
+
+The previous H616 support patch added a single LINEOUT DAPM pin switch
+to the card controls. As the codec in this SoC only has a single route,
+this seemed reasonable at the time, however is redundant given the
+existing DAPM codec widget definitions controlling the digital and
+analog sides of the codec.
+
+It is also insufficient to describe the scenario where separate
+components (muxes, jack detection etc) are used to modify the audio
+route external to the SoC. For example the Anbernic RG(##)XX series of
+devices uses a headphone jack detection switch, GPIO-controlled speaker
+amplifier and a passive external mux chip to route audio.
+
+Remove the redundant LINEOUT card control, and add a Speaker pin switch
+control and Headphone DAPM widget to allow control of the above
+hardware.
+
+Signed-off-by: Chris Morgan <macromorgan@hotmail.com>
+Signed-off-by: Ryan Walklin <ryan@testtoast.com>
+Tested-by: Philippe Simons <simons.philippe@gmail.com>
+Link: https://patch.msgid.link/20250214220247.10810-3-ryan@testtoast.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/sunxi/sun4i-codec.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
+index 06e85b34fdf68..3701f56c72756 100644
+--- a/sound/soc/sunxi/sun4i-codec.c
++++ b/sound/soc/sunxi/sun4i-codec.c
+@@ -1962,10 +1962,11 @@ static const struct snd_soc_component_driver sun50i_h616_codec_codec = {
+ };
+
+ static const struct snd_kcontrol_new sun50i_h616_card_controls[] = {
+- SOC_DAPM_PIN_SWITCH("LINEOUT"),
++ SOC_DAPM_PIN_SWITCH("Speaker"),
+ };
+
+ static const struct snd_soc_dapm_widget sun50i_h616_codec_card_dapm_widgets[] = {
++ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_LINE("Line Out", NULL),
+ SND_SOC_DAPM_SPK("Speaker", sun4i_codec_spk_event),
+ };
+--
+2.39.5
+
--- /dev/null
+From 05d597df8d53da68b4e6a2f4368ed7461910fe24 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 15 Feb 2025 11:02:25 +1300
+Subject: ASoC: sun4i-codec: support hp-det-gpios property
+
+From: Ryan Walklin <ryan@testtoast.com>
+
+[ Upstream commit a149377c033afe6557c50892ebbfc0e8b7e2e253 ]
+
+Add support for GPIO headphone detection with the hp-det-gpios
+property. In order for this to properly disable the path upon
+removal of headphones, the output must be labelled Headphone which
+is a common sink in the driver.
+
+Describe a headphone jack and detection GPIO in the driver, check for
+a corresponding device tree node, and enable jack detection in a new
+machine init function if described.
+
+Signed-off-by: Chris Morgan <macromorgan@hotmail.com>
+Signed-off-by: Ryan Walklin <ryan@testtoast.com>
+
+--
+Changelog v1..v2:
+- Separate DAPM changes into separate patch and add rationale.
+
+Tested-by: Philippe Simons <simons.philippe@gmail.com>
+Link: https://patch.msgid.link/20250214220247.10810-4-ryan@testtoast.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/sunxi/sun4i-codec.c | 53 +++++++++++++++++++++++++++++++++++
+ 1 file changed, 53 insertions(+)
+
+diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
+index 886b3fa537d26..06e85b34fdf68 100644
+--- a/sound/soc/sunxi/sun4i-codec.c
++++ b/sound/soc/sunxi/sun4i-codec.c
+@@ -22,6 +22,7 @@
+ #include <linux/gpio/consumer.h>
+
+ #include <sound/core.h>
++#include <sound/jack.h>
+ #include <sound/pcm.h>
+ #include <sound/pcm_params.h>
+ #include <sound/soc.h>
+@@ -331,6 +332,7 @@ struct sun4i_codec {
+ struct clk *clk_module;
+ struct reset_control *rst;
+ struct gpio_desc *gpio_pa;
++ struct gpio_desc *gpio_hp;
+
+ /* ADC_FIFOC register is at different offset on different SoCs */
+ struct regmap_field *reg_adc_fifoc;
+@@ -1583,6 +1585,49 @@ static struct snd_soc_dai_driver dummy_cpu_dai = {
+ .ops = &dummy_dai_ops,
+ };
+
++static struct snd_soc_jack sun4i_headphone_jack;
++
++static struct snd_soc_jack_pin sun4i_headphone_jack_pins[] = {
++ { .pin = "Headphone", .mask = SND_JACK_HEADPHONE },
++};
++
++static struct snd_soc_jack_gpio sun4i_headphone_jack_gpio = {
++ .name = "hp-det",
++ .report = SND_JACK_HEADPHONE,
++ .debounce_time = 150,
++};
++
++static int sun4i_codec_machine_init(struct snd_soc_pcm_runtime *rtd)
++{
++ struct snd_soc_card *card = rtd->card;
++ struct sun4i_codec *scodec = snd_soc_card_get_drvdata(card);
++ int ret;
++
++ if (scodec->gpio_hp) {
++ ret = snd_soc_card_jack_new_pins(card, "Headphone Jack",
++ SND_JACK_HEADPHONE,
++ &sun4i_headphone_jack,
++ sun4i_headphone_jack_pins,
++ ARRAY_SIZE(sun4i_headphone_jack_pins));
++ if (ret) {
++ dev_err(rtd->dev,
++ "Headphone jack creation failed: %d\n", ret);
++ return ret;
++ }
++
++ sun4i_headphone_jack_gpio.desc = scodec->gpio_hp;
++ ret = snd_soc_jack_add_gpios(&sun4i_headphone_jack, 1,
++ &sun4i_headphone_jack_gpio);
++
++ if (ret) {
++ dev_err(rtd->dev, "Headphone GPIO not added: %d\n", ret);
++ return ret;
++ }
++ }
++
++ return 0;
++}
++
+ static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev,
+ int *num_links)
+ {
+@@ -1608,6 +1653,7 @@ static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev,
+ link->codecs->name = dev_name(dev);
+ link->platforms->name = dev_name(dev);
+ link->dai_fmt = SND_SOC_DAIFMT_I2S;
++ link->init = sun4i_codec_machine_init;
+
+ *num_links = 1;
+
+@@ -2301,6 +2347,13 @@ static int sun4i_codec_probe(struct platform_device *pdev)
+ return ret;
+ }
+
++ scodec->gpio_hp = devm_gpiod_get_optional(&pdev->dev, "hp-det", GPIOD_IN);
++ if (IS_ERR(scodec->gpio_hp)) {
++ ret = PTR_ERR(scodec->gpio_hp);
++ dev_err_probe(&pdev->dev, ret, "Failed to get hp-det gpio\n");
++ return ret;
++ }
++
+ /* reg_field setup */
+ scodec->reg_adc_fifoc = devm_regmap_field_alloc(&pdev->dev,
+ scodec->regmap,
+--
+2.39.5
+
--- /dev/null
+From 2929ff79d54a666f11a39cb24be50f8bfc4588e5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 8 Feb 2025 01:03:27 +0000
+Subject: ASoC: tas2764: Add reg defaults for TAS2764_INT_CLK_CFG
+
+From: Hector Martin <marcan@marcan.st>
+
+[ Upstream commit d64c4c3d1c578f98d70db1c5e2535b47adce9d07 ]
+
+Signed-off-by: Hector Martin <marcan@marcan.st>
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Link: https://patch.msgid.link/20250208-asoc-tas2764-v1-4-dbab892a69b5@kernel.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/codecs/tas2764.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c
+index 58315eab492a1..bc0a73fc7ab41 100644
+--- a/sound/soc/codecs/tas2764.c
++++ b/sound/soc/codecs/tas2764.c
+@@ -634,6 +634,7 @@ static const struct reg_default tas2764_reg_defaults[] = {
+ { TAS2764_TDM_CFG2, 0x0a },
+ { TAS2764_TDM_CFG3, 0x10 },
+ { TAS2764_TDM_CFG5, 0x42 },
++ { TAS2764_INT_CLK_CFG, 0x19 },
+ };
+
+ static const struct regmap_range_cfg tas2764_regmap_ranges[] = {
+--
+2.39.5
+
--- /dev/null
+From 11963ee4b7329839024ec2c677d2193c1e6e4058 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 8 Feb 2025 01:03:26 +0000
+Subject: ASoC: tas2764: Mark SW_RESET as volatile
+
+From: Hector Martin <marcan@marcan.st>
+
+[ Upstream commit f37f1748564ac51d32f7588bd7bfc99913ccab8e ]
+
+Since the bit is self-clearing.
+
+Signed-off-by: Hector Martin <marcan@marcan.st>
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Link: https://patch.msgid.link/20250208-asoc-tas2764-v1-3-dbab892a69b5@kernel.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/codecs/tas2764.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c
+index bc0a73fc7ab41..31f94c8cf2844 100644
+--- a/sound/soc/codecs/tas2764.c
++++ b/sound/soc/codecs/tas2764.c
+@@ -652,6 +652,7 @@ static const struct regmap_range_cfg tas2764_regmap_ranges[] = {
+ static bool tas2764_volatile_register(struct device *dev, unsigned int reg)
+ {
+ switch (reg) {
++ case TAS2764_SW_RST:
+ case TAS2764_INT_LTCH0 ... TAS2764_INT_LTCH4:
+ case TAS2764_INT_CLK_CFG:
+ return true;
+--
+2.39.5
+
--- /dev/null
+From c85a7a3468d1daec003ef3fe171adcd7e4bedf18 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 8 Feb 2025 01:03:24 +0000
+Subject: ASoC: tas2764: Power up/down amp on mute ops
+
+From: Hector Martin <marcan@marcan.st>
+
+[ Upstream commit 1c3b5f37409682184669457a5bdf761268eafbe5 ]
+
+The ASoC convention is that clocks are removed after codec mute, and
+power up/down is more about top level power management. For these chips,
+the "mute" state still expects a TDM clock, and yanking the clock in
+this state will trigger clock errors. So, do the full
+shutdown<->mute<->active transition on the mute operation, so the amp is
+in software shutdown by the time the clocks are removed.
+
+This fixes TDM clock errors when streams are stopped.
+
+Signed-off-by: Hector Martin <marcan@marcan.st>
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Link: https://patch.msgid.link/20250208-asoc-tas2764-v1-1-dbab892a69b5@kernel.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/codecs/tas2764.c | 51 ++++++++++++++++----------------------
+ 1 file changed, 21 insertions(+), 30 deletions(-)
+
+diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c
+index 31f94c8cf2844..39a7d39536fe6 100644
+--- a/sound/soc/codecs/tas2764.c
++++ b/sound/soc/codecs/tas2764.c
+@@ -180,33 +180,6 @@ static SOC_ENUM_SINGLE_DECL(
+ static const struct snd_kcontrol_new tas2764_asi1_mux =
+ SOC_DAPM_ENUM("ASI1 Source", tas2764_ASI1_src_enum);
+
+-static int tas2764_dac_event(struct snd_soc_dapm_widget *w,
+- struct snd_kcontrol *kcontrol, int event)
+-{
+- struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+- struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
+- int ret;
+-
+- switch (event) {
+- case SND_SOC_DAPM_POST_PMU:
+- tas2764->dac_powered = true;
+- ret = tas2764_update_pwr_ctrl(tas2764);
+- break;
+- case SND_SOC_DAPM_PRE_PMD:
+- tas2764->dac_powered = false;
+- ret = tas2764_update_pwr_ctrl(tas2764);
+- break;
+- default:
+- dev_err(tas2764->dev, "Unsupported event\n");
+- return -EINVAL;
+- }
+-
+- if (ret < 0)
+- return ret;
+-
+- return 0;
+-}
+-
+ static const struct snd_kcontrol_new isense_switch =
+ SOC_DAPM_SINGLE("Switch", TAS2764_PWR_CTRL, TAS2764_ISENSE_POWER_EN, 1, 1);
+ static const struct snd_kcontrol_new vsense_switch =
+@@ -219,8 +192,7 @@ static const struct snd_soc_dapm_widget tas2764_dapm_widgets[] = {
+ 1, &isense_switch),
+ SND_SOC_DAPM_SWITCH("VSENSE", TAS2764_PWR_CTRL, TAS2764_VSENSE_POWER_EN,
+ 1, &vsense_switch),
+- SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas2764_dac_event,
+- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
++ SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_OUTPUT("OUT"),
+ SND_SOC_DAPM_SIGGEN("VMON"),
+ SND_SOC_DAPM_SIGGEN("IMON")
+@@ -241,9 +213,28 @@ static int tas2764_mute(struct snd_soc_dai *dai, int mute, int direction)
+ {
+ struct tas2764_priv *tas2764 =
+ snd_soc_component_get_drvdata(dai->component);
++ int ret;
++
++ if (!mute) {
++ tas2764->dac_powered = true;
++ ret = tas2764_update_pwr_ctrl(tas2764);
++ if (ret)
++ return ret;
++ }
+
+ tas2764->unmuted = !mute;
+- return tas2764_update_pwr_ctrl(tas2764);
++ ret = tas2764_update_pwr_ctrl(tas2764);
++ if (ret)
++ return ret;
++
++ if (mute) {
++ tas2764->dac_powered = false;
++ ret = tas2764_update_pwr_ctrl(tas2764);
++ if (ret)
++ return ret;
++ }
++
++ return 0;
+ }
+
+ static int tas2764_set_bitwidth(struct tas2764_priv *tas2764, int bitwidth)
+--
+2.39.5
+
--- /dev/null
+From e1fa420a06af2750033c554ef077af277f7a5fb6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 24 Feb 2025 19:27:38 +0200
+Subject: auxdisplay: charlcd: Partially revert "Move hwidth and bwidth to
+ struct hd44780_common"
+
+From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+
+[ Upstream commit 09965a142078080fe7807bab0f6f1890cb5987a4 ]
+
+Commit 2545c1c948a6 ("auxdisplay: Move hwidth and bwidth to struct
+hd44780_common") makes charlcd_alloc() argument-less effectively dropping
+the single allocation for the struct charlcd_priv object along with
+the driver specific one. Restore that behaviour here.
+
+Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Reviewed-by: Geert Uytterhoeven <geert@linux-m68k.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/auxdisplay/charlcd.c | 5 +++--
+ drivers/auxdisplay/charlcd.h | 5 +++--
+ drivers/auxdisplay/hd44780.c | 2 +-
+ drivers/auxdisplay/lcd2s.c | 2 +-
+ drivers/auxdisplay/panel.c | 2 +-
+ 5 files changed, 9 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/auxdisplay/charlcd.c b/drivers/auxdisplay/charlcd.c
+index 19b619376d48b..09020bb8ad15f 100644
+--- a/drivers/auxdisplay/charlcd.c
++++ b/drivers/auxdisplay/charlcd.c
+@@ -595,18 +595,19 @@ static int charlcd_init(struct charlcd *lcd)
+ return 0;
+ }
+
+-struct charlcd *charlcd_alloc(void)
++struct charlcd *charlcd_alloc(unsigned int drvdata_size)
+ {
+ struct charlcd_priv *priv;
+ struct charlcd *lcd;
+
+- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
++ priv = kzalloc(sizeof(*priv) + drvdata_size, GFP_KERNEL);
+ if (!priv)
+ return NULL;
+
+ priv->esc_seq.len = -1;
+
+ lcd = &priv->lcd;
++ lcd->drvdata = priv->drvdata;
+
+ return lcd;
+ }
+diff --git a/drivers/auxdisplay/charlcd.h b/drivers/auxdisplay/charlcd.h
+index 4d4287209d04c..d10b89740bcae 100644
+--- a/drivers/auxdisplay/charlcd.h
++++ b/drivers/auxdisplay/charlcd.h
+@@ -51,7 +51,7 @@ struct charlcd {
+ unsigned long y;
+ } addr;
+
+- void *drvdata;
++ void *drvdata; /* Set by charlcd_alloc() */
+ };
+
+ /**
+@@ -95,7 +95,8 @@ struct charlcd_ops {
+ };
+
+ void charlcd_backlight(struct charlcd *lcd, enum charlcd_onoff on);
+-struct charlcd *charlcd_alloc(void);
++
++struct charlcd *charlcd_alloc(unsigned int drvdata_size);
+ void charlcd_free(struct charlcd *lcd);
+
+ int charlcd_register(struct charlcd *lcd);
+diff --git a/drivers/auxdisplay/hd44780.c b/drivers/auxdisplay/hd44780.c
+index 9d0ae9c02e9ba..1d67fe3243412 100644
+--- a/drivers/auxdisplay/hd44780.c
++++ b/drivers/auxdisplay/hd44780.c
+@@ -226,7 +226,7 @@ static int hd44780_probe(struct platform_device *pdev)
+ if (!hdc)
+ return -ENOMEM;
+
+- lcd = charlcd_alloc();
++ lcd = charlcd_alloc(0);
+ if (!lcd)
+ goto fail1;
+
+diff --git a/drivers/auxdisplay/lcd2s.c b/drivers/auxdisplay/lcd2s.c
+index a28daa4ffbf75..c71ebb925971b 100644
+--- a/drivers/auxdisplay/lcd2s.c
++++ b/drivers/auxdisplay/lcd2s.c
+@@ -307,7 +307,7 @@ static int lcd2s_i2c_probe(struct i2c_client *i2c)
+ if (err < 0)
+ return err;
+
+- lcd = charlcd_alloc();
++ lcd = charlcd_alloc(0);
+ if (!lcd)
+ return -ENOMEM;
+
+diff --git a/drivers/auxdisplay/panel.c b/drivers/auxdisplay/panel.c
+index 6dc8798d01f98..4da142692d55f 100644
+--- a/drivers/auxdisplay/panel.c
++++ b/drivers/auxdisplay/panel.c
+@@ -835,7 +835,7 @@ static void lcd_init(void)
+ if (!hdc)
+ return;
+
+- charlcd = charlcd_alloc();
++ charlcd = charlcd_alloc(0);
+ if (!charlcd) {
+ kfree(hdc);
+ return;
+--
+2.39.5
+
--- /dev/null
+From 571c55ef7955f3fe0ad50b77cc3f67a4eed4dd23 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 9 Mar 2025 12:05:56 -0400
+Subject: badblocks: Fix a nonsense WARN_ON() which checks whether a u64
+ variable < 0
+
+From: Coly Li <colyli@kernel.org>
+
+[ Upstream commit 7e76336e14de9a2b67af96012ddd46c5676cf340 ]
+
+In _badblocks_check(), there are lines of code like this,
+1246 sectors -= len;
+[snipped]
+1251 WARN_ON(sectors < 0);
+
+The WARN_ON() at line 1257 doesn't make sense because sectors is
+unsigned long long type and never to be <0.
+
+Fix it by checking directly checking whether sectors is less than len.
+
+Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
+Signed-off-by: Coly Li <colyli@kernel.org>
+Reviewed-by: Yu Kuai <yukuai3@huawei.com>
+Link: https://lore.kernel.org/r/20250309160556.42854-1-colyli@kernel.org
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ block/badblocks.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/block/badblocks.c b/block/badblocks.c
+index dc147c0179612..23acdf7c6f363 100644
+--- a/block/badblocks.c
++++ b/block/badblocks.c
+@@ -1246,14 +1246,15 @@ static int _badblocks_check(struct badblocks *bb, sector_t s, sector_t sectors,
+ len = sectors;
+
+ update_sectors:
++ /* This situation should never happen */
++ WARN_ON(sectors < len);
++
+ s += len;
+ sectors -= len;
+
+ if (sectors > 0)
+ goto re_check;
+
+- WARN_ON(sectors < 0);
+-
+ if (unacked_badblocks > 0)
+ rv = -1;
+ else if (acked_badblocks > 0)
+--
+2.39.5
+
--- /dev/null
+From c3c5ac9594d9a9d26dd88ea5079b022abca055c9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 17 Mar 2025 10:29:24 +0800
+Subject: blk-cgroup: improve policy registration error handling
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Chen Linxuan <chenlinxuan@uniontech.com>
+
+[ Upstream commit e1a0202c6bfda24002a3ae2115154fa90104c649 ]
+
+This patch improve the returned error code of blkcg_policy_register().
+
+1. Move the validation check for cpd/pd_alloc_fn and cpd/pd_free_fn
+ function pairs to the start of blkcg_policy_register(). This ensures
+ we immediately return -EINVAL if the function pairs are not correctly
+ provided, rather than returning -ENOSPC after locking and unlocking
+ mutexes unnecessarily.
+
+ Those locks should not contention any problems, as error of policy
+ registration is a super cold path.
+
+2. Return -ENOMEM when cpd_alloc_fn() failed.
+
+Co-authored-by: Wen Tao <wentao@uniontech.com>
+Signed-off-by: Wen Tao <wentao@uniontech.com>
+Signed-off-by: Chen Linxuan <chenlinxuan@uniontech.com>
+Reviewed-by: Michal Koutný <mkoutny@suse.com>
+Acked-by: Tejun Heo <tj@kernel.org>
+Reviewed-by: Yu Kuai <yukuai3@huawei.com>
+Link: https://lore.kernel.org/r/3E333A73B6B6DFC0+20250317022924.150907-1-chenlinxuan@uniontech.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ block/blk-cgroup.c | 22 ++++++++++++----------
+ 1 file changed, 12 insertions(+), 10 deletions(-)
+
+diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
+index c94efae5bcfaf..8b07015db819a 100644
+--- a/block/blk-cgroup.c
++++ b/block/blk-cgroup.c
+@@ -1727,27 +1727,27 @@ int blkcg_policy_register(struct blkcg_policy *pol)
+ struct blkcg *blkcg;
+ int i, ret;
+
++ /*
++ * Make sure cpd/pd_alloc_fn and cpd/pd_free_fn in pairs, and policy
++ * without pd_alloc_fn/pd_free_fn can't be activated.
++ */
++ if ((!pol->cpd_alloc_fn ^ !pol->cpd_free_fn) ||
++ (!pol->pd_alloc_fn ^ !pol->pd_free_fn))
++ return -EINVAL;
++
+ mutex_lock(&blkcg_pol_register_mutex);
+ mutex_lock(&blkcg_pol_mutex);
+
+ /* find an empty slot */
+- ret = -ENOSPC;
+ for (i = 0; i < BLKCG_MAX_POLS; i++)
+ if (!blkcg_policy[i])
+ break;
+ if (i >= BLKCG_MAX_POLS) {
+ pr_warn("blkcg_policy_register: BLKCG_MAX_POLS too small\n");
++ ret = -ENOSPC;
+ goto err_unlock;
+ }
+
+- /*
+- * Make sure cpd/pd_alloc_fn and cpd/pd_free_fn in pairs, and policy
+- * without pd_alloc_fn/pd_free_fn can't be activated.
+- */
+- if ((!pol->cpd_alloc_fn ^ !pol->cpd_free_fn) ||
+- (!pol->pd_alloc_fn ^ !pol->pd_free_fn))
+- goto err_unlock;
+-
+ /* register @pol */
+ pol->plid = i;
+ blkcg_policy[pol->plid] = pol;
+@@ -1758,8 +1758,10 @@ int blkcg_policy_register(struct blkcg_policy *pol)
+ struct blkcg_policy_data *cpd;
+
+ cpd = pol->cpd_alloc_fn(GFP_KERNEL);
+- if (!cpd)
++ if (!cpd) {
++ ret = -ENOMEM;
+ goto err_free_cpds;
++ }
+
+ blkcg->cpd[pol->plid] = cpd;
+ cpd->blkcg = blkcg;
+--
+2.39.5
+
--- /dev/null
+From 7c9b5f8a6247f0a7b9425df9f82267b3c3ab9d1d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Mar 2025 12:31:20 +0800
+Subject: blk-throttle: don't take carryover for prioritized processing of
+ metadata
+
+From: Ming Lei <ming.lei@redhat.com>
+
+[ Upstream commit a9fc8868b350cbf4ff730a4ea9651319cc669516 ]
+
+Commit 29390bb5661d ("blk-throttle: support prioritized processing of metadata")
+takes bytes/ios carryover for prioritized processing of metadata. Turns out
+we can support it by charging it directly without trimming slice, and the
+result is same with carryover.
+
+Cc: Tejun Heo <tj@kernel.org>
+Cc: Josef Bacik <josef@toxicpanda.com>
+Cc: Yu Kuai <yukuai3@huawei.com>
+Signed-off-by: Ming Lei <ming.lei@redhat.com>
+Acked-by: Tejun Heo <tj@kernel.org>
+Link: https://lore.kernel.org/r/20250305043123.3938491-3-ming.lei@redhat.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ block/blk-throttle.c | 15 +++++----------
+ 1 file changed, 5 insertions(+), 10 deletions(-)
+
+diff --git a/block/blk-throttle.c b/block/blk-throttle.c
+index a52f0d6b40ad4..762fbbd388c87 100644
+--- a/block/blk-throttle.c
++++ b/block/blk-throttle.c
+@@ -1623,13 +1623,6 @@ static bool tg_within_limit(struct throtl_grp *tg, struct bio *bio, bool rw)
+ return tg_may_dispatch(tg, bio, NULL);
+ }
+
+-static void tg_dispatch_in_debt(struct throtl_grp *tg, struct bio *bio, bool rw)
+-{
+- if (!bio_flagged(bio, BIO_BPS_THROTTLED))
+- tg->carryover_bytes[rw] -= throtl_bio_data_size(bio);
+- tg->carryover_ios[rw]--;
+-}
+-
+ bool __blk_throtl_bio(struct bio *bio)
+ {
+ struct request_queue *q = bdev_get_queue(bio->bi_bdev);
+@@ -1666,10 +1659,12 @@ bool __blk_throtl_bio(struct bio *bio)
+ /*
+ * IOs which may cause priority inversions are
+ * dispatched directly, even if they're over limit.
+- * Debts are handled by carryover_bytes/ios while
+- * calculating wait time.
++ *
++ * Charge and dispatch directly, and our throttle
++ * control algorithm is adaptive, and extra IO bytes
++ * will be throttled for paying the debt
+ */
+- tg_dispatch_in_debt(tg, bio, rw);
++ throtl_charge_bio(tg, bio);
+ } else {
+ /* if above limits, break to queue */
+ break;
+--
+2.39.5
+
--- /dev/null
+From 9f167debab5dc7e5a53132b2ecb62ab6b3928361 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Mar 2025 15:52:30 +0530
+Subject: block: acquire q->limits_lock while reading sysfs attributes
+
+From: Nilay Shroff <nilay@linux.ibm.com>
+
+[ Upstream commit 6e51a1279cd60cb93e3379ff140d8fa6c39ecf20 ]
+
+There're few sysfs attributes(RW) whose store method is protected
+with q->limits_lock, however the corresponding show method of these
+attributes run holding q->sysfs_lock and that doesn't make sense
+as ideally the show method of these attributes should also run
+holding q->limits_lock instead of q->sysfs_lock. Hence update the
+show method of these sysfs attributes so that reading of these
+attributes acquire q->limits_lock instead of q->sysfs_lock.
+
+Similarly, there're few sysfs attributes(RO) whose show method is
+currently protected with q->sysfs_lock however updates to these
+attributes could occur using atomic limit update APIs such as queue_
+limits_start_update() and queue_limits_commit_update() which run
+holding q->limits_lock. So that means that reading these attributes
+holding q->sysfs_lock doesn't make sense. Hence update the show method
+of these sysfs attributes(RO) such that they run with holding q->
+limits_lock instead of q->sysfs_lock.
+
+We have defined a new macro QUEUE_LIM_RO_ENTRY() which uses new ->show_
+limit() method and it runs holding q->limits_lock. All existing sysfs
+attributes(RO) which needs protection using q->limits_lock while
+reading have been now updated to use this new macro for initialization.
+
+Also, the existing QUEUE_LIM_RW_ENTRY() is updated to use new ->show_
+limit() method for reading attributes instead of existing ->show()
+method. As ->show_limit() runs holding q->limits_lock, the existing
+sysfs attributes(RW) requiring protection are now inherently protected
+using q->limits_lock instead of q->sysfs_lock.
+
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Reviewed-by: Hannes Reinecke <hare@suse.de>
+Reviewed-by: Ming Lei <ming.lei@redhat.com>
+Signed-off-by: Nilay Shroff <nilay@linux.ibm.com>
+Link: https://lore.kernel.org/r/20250304102551.2533767-2-nilay@linux.ibm.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ block/blk-sysfs.c | 102 +++++++++++++++++++++++++++++-----------------
+ 1 file changed, 65 insertions(+), 37 deletions(-)
+
+diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
+index 7802186849074..dc4037e27e36e 100644
+--- a/block/blk-sysfs.c
++++ b/block/blk-sysfs.c
+@@ -23,9 +23,12 @@
+ struct queue_sysfs_entry {
+ struct attribute attr;
+ ssize_t (*show)(struct gendisk *disk, char *page);
++ ssize_t (*show_limit)(struct gendisk *disk, char *page);
++
+ ssize_t (*store)(struct gendisk *disk, const char *page, size_t count);
+ int (*store_limit)(struct gendisk *disk, const char *page,
+ size_t count, struct queue_limits *lim);
++
+ void (*load_module)(struct gendisk *disk, const char *page, size_t count);
+ };
+
+@@ -412,10 +415,16 @@ static struct queue_sysfs_entry _prefix##_entry = { \
+ .store = _prefix##_store, \
+ };
+
++#define QUEUE_LIM_RO_ENTRY(_prefix, _name) \
++static struct queue_sysfs_entry _prefix##_entry = { \
++ .attr = { .name = _name, .mode = 0444 }, \
++ .show_limit = _prefix##_show, \
++}
++
+ #define QUEUE_LIM_RW_ENTRY(_prefix, _name) \
+ static struct queue_sysfs_entry _prefix##_entry = { \
+ .attr = { .name = _name, .mode = 0644 }, \
+- .show = _prefix##_show, \
++ .show_limit = _prefix##_show, \
+ .store_limit = _prefix##_store, \
+ }
+
+@@ -430,39 +439,39 @@ static struct queue_sysfs_entry _prefix##_entry = { \
+ QUEUE_RW_ENTRY(queue_requests, "nr_requests");
+ QUEUE_RW_ENTRY(queue_ra, "read_ahead_kb");
+ QUEUE_LIM_RW_ENTRY(queue_max_sectors, "max_sectors_kb");
+-QUEUE_RO_ENTRY(queue_max_hw_sectors, "max_hw_sectors_kb");
+-QUEUE_RO_ENTRY(queue_max_segments, "max_segments");
+-QUEUE_RO_ENTRY(queue_max_integrity_segments, "max_integrity_segments");
+-QUEUE_RO_ENTRY(queue_max_segment_size, "max_segment_size");
++QUEUE_LIM_RO_ENTRY(queue_max_hw_sectors, "max_hw_sectors_kb");
++QUEUE_LIM_RO_ENTRY(queue_max_segments, "max_segments");
++QUEUE_LIM_RO_ENTRY(queue_max_integrity_segments, "max_integrity_segments");
++QUEUE_LIM_RO_ENTRY(queue_max_segment_size, "max_segment_size");
+ QUEUE_RW_LOAD_MODULE_ENTRY(elv_iosched, "scheduler");
+
+-QUEUE_RO_ENTRY(queue_logical_block_size, "logical_block_size");
+-QUEUE_RO_ENTRY(queue_physical_block_size, "physical_block_size");
+-QUEUE_RO_ENTRY(queue_chunk_sectors, "chunk_sectors");
+-QUEUE_RO_ENTRY(queue_io_min, "minimum_io_size");
+-QUEUE_RO_ENTRY(queue_io_opt, "optimal_io_size");
++QUEUE_LIM_RO_ENTRY(queue_logical_block_size, "logical_block_size");
++QUEUE_LIM_RO_ENTRY(queue_physical_block_size, "physical_block_size");
++QUEUE_LIM_RO_ENTRY(queue_chunk_sectors, "chunk_sectors");
++QUEUE_LIM_RO_ENTRY(queue_io_min, "minimum_io_size");
++QUEUE_LIM_RO_ENTRY(queue_io_opt, "optimal_io_size");
+
+-QUEUE_RO_ENTRY(queue_max_discard_segments, "max_discard_segments");
+-QUEUE_RO_ENTRY(queue_discard_granularity, "discard_granularity");
+-QUEUE_RO_ENTRY(queue_max_hw_discard_sectors, "discard_max_hw_bytes");
++QUEUE_LIM_RO_ENTRY(queue_max_discard_segments, "max_discard_segments");
++QUEUE_LIM_RO_ENTRY(queue_discard_granularity, "discard_granularity");
++QUEUE_LIM_RO_ENTRY(queue_max_hw_discard_sectors, "discard_max_hw_bytes");
+ QUEUE_LIM_RW_ENTRY(queue_max_discard_sectors, "discard_max_bytes");
+ QUEUE_RO_ENTRY(queue_discard_zeroes_data, "discard_zeroes_data");
+
+-QUEUE_RO_ENTRY(queue_atomic_write_max_sectors, "atomic_write_max_bytes");
+-QUEUE_RO_ENTRY(queue_atomic_write_boundary_sectors,
++QUEUE_LIM_RO_ENTRY(queue_atomic_write_max_sectors, "atomic_write_max_bytes");
++QUEUE_LIM_RO_ENTRY(queue_atomic_write_boundary_sectors,
+ "atomic_write_boundary_bytes");
+-QUEUE_RO_ENTRY(queue_atomic_write_unit_max, "atomic_write_unit_max_bytes");
+-QUEUE_RO_ENTRY(queue_atomic_write_unit_min, "atomic_write_unit_min_bytes");
++QUEUE_LIM_RO_ENTRY(queue_atomic_write_unit_max, "atomic_write_unit_max_bytes");
++QUEUE_LIM_RO_ENTRY(queue_atomic_write_unit_min, "atomic_write_unit_min_bytes");
+
+ QUEUE_RO_ENTRY(queue_write_same_max, "write_same_max_bytes");
+-QUEUE_RO_ENTRY(queue_max_write_zeroes_sectors, "write_zeroes_max_bytes");
+-QUEUE_RO_ENTRY(queue_max_zone_append_sectors, "zone_append_max_bytes");
+-QUEUE_RO_ENTRY(queue_zone_write_granularity, "zone_write_granularity");
++QUEUE_LIM_RO_ENTRY(queue_max_write_zeroes_sectors, "write_zeroes_max_bytes");
++QUEUE_LIM_RO_ENTRY(queue_max_zone_append_sectors, "zone_append_max_bytes");
++QUEUE_LIM_RO_ENTRY(queue_zone_write_granularity, "zone_write_granularity");
+
+-QUEUE_RO_ENTRY(queue_zoned, "zoned");
++QUEUE_LIM_RO_ENTRY(queue_zoned, "zoned");
+ QUEUE_RO_ENTRY(queue_nr_zones, "nr_zones");
+-QUEUE_RO_ENTRY(queue_max_open_zones, "max_open_zones");
+-QUEUE_RO_ENTRY(queue_max_active_zones, "max_active_zones");
++QUEUE_LIM_RO_ENTRY(queue_max_open_zones, "max_open_zones");
++QUEUE_LIM_RO_ENTRY(queue_max_active_zones, "max_active_zones");
+
+ QUEUE_RW_ENTRY(queue_nomerges, "nomerges");
+ QUEUE_LIM_RW_ENTRY(queue_iostats_passthrough, "iostats_passthrough");
+@@ -470,16 +479,16 @@ QUEUE_RW_ENTRY(queue_rq_affinity, "rq_affinity");
+ QUEUE_RW_ENTRY(queue_poll, "io_poll");
+ QUEUE_RW_ENTRY(queue_poll_delay, "io_poll_delay");
+ QUEUE_LIM_RW_ENTRY(queue_wc, "write_cache");
+-QUEUE_RO_ENTRY(queue_fua, "fua");
+-QUEUE_RO_ENTRY(queue_dax, "dax");
++QUEUE_LIM_RO_ENTRY(queue_fua, "fua");
++QUEUE_LIM_RO_ENTRY(queue_dax, "dax");
+ QUEUE_RW_ENTRY(queue_io_timeout, "io_timeout");
+-QUEUE_RO_ENTRY(queue_virt_boundary_mask, "virt_boundary_mask");
+-QUEUE_RO_ENTRY(queue_dma_alignment, "dma_alignment");
++QUEUE_LIM_RO_ENTRY(queue_virt_boundary_mask, "virt_boundary_mask");
++QUEUE_LIM_RO_ENTRY(queue_dma_alignment, "dma_alignment");
+
+ /* legacy alias for logical_block_size: */
+ static struct queue_sysfs_entry queue_hw_sector_size_entry = {
+- .attr = {.name = "hw_sector_size", .mode = 0444 },
+- .show = queue_logical_block_size_show,
++ .attr = {.name = "hw_sector_size", .mode = 0444 },
++ .show_limit = queue_logical_block_size_show,
+ };
+
+ QUEUE_LIM_RW_ENTRY(queue_rotational, "rotational");
+@@ -561,7 +570,9 @@ QUEUE_RW_ENTRY(queue_wb_lat, "wbt_lat_usec");
+
+ /* Common attributes for bio-based and request-based queues. */
+ static struct attribute *queue_attrs[] = {
+- &queue_ra_entry.attr,
++ /*
++ * Attributes which are protected with q->limits_lock.
++ */
+ &queue_max_hw_sectors_entry.attr,
+ &queue_max_sectors_entry.attr,
+ &queue_max_segments_entry.attr,
+@@ -577,37 +588,46 @@ static struct attribute *queue_attrs[] = {
+ &queue_discard_granularity_entry.attr,
+ &queue_max_discard_sectors_entry.attr,
+ &queue_max_hw_discard_sectors_entry.attr,
+- &queue_discard_zeroes_data_entry.attr,
+ &queue_atomic_write_max_sectors_entry.attr,
+ &queue_atomic_write_boundary_sectors_entry.attr,
+ &queue_atomic_write_unit_min_entry.attr,
+ &queue_atomic_write_unit_max_entry.attr,
+- &queue_write_same_max_entry.attr,
+ &queue_max_write_zeroes_sectors_entry.attr,
+ &queue_max_zone_append_sectors_entry.attr,
+ &queue_zone_write_granularity_entry.attr,
+ &queue_rotational_entry.attr,
+ &queue_zoned_entry.attr,
+- &queue_nr_zones_entry.attr,
+ &queue_max_open_zones_entry.attr,
+ &queue_max_active_zones_entry.attr,
+- &queue_nomerges_entry.attr,
+ &queue_iostats_passthrough_entry.attr,
+ &queue_iostats_entry.attr,
+ &queue_stable_writes_entry.attr,
+ &queue_add_random_entry.attr,
+- &queue_poll_entry.attr,
+ &queue_wc_entry.attr,
+ &queue_fua_entry.attr,
+ &queue_dax_entry.attr,
+- &queue_poll_delay_entry.attr,
+ &queue_virt_boundary_mask_entry.attr,
+ &queue_dma_alignment_entry.attr,
++
++ /*
++ * Attributes which are protected with q->sysfs_lock.
++ */
++ &queue_ra_entry.attr,
++ &queue_discard_zeroes_data_entry.attr,
++ &queue_write_same_max_entry.attr,
++ &queue_nr_zones_entry.attr,
++ &queue_nomerges_entry.attr,
++ &queue_poll_entry.attr,
++ &queue_poll_delay_entry.attr,
++
+ NULL,
+ };
+
+ /* Request-based queue attributes that are not relevant for bio-based queues. */
+ static struct attribute *blk_mq_queue_attrs[] = {
++ /*
++ * Attributes which are protected with q->sysfs_lock.
++ */
+ &queue_requests_entry.attr,
+ &elv_iosched_entry.attr,
+ &queue_rq_affinity_entry.attr,
+@@ -666,8 +686,16 @@ queue_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
+ struct gendisk *disk = container_of(kobj, struct gendisk, queue_kobj);
+ ssize_t res;
+
+- if (!entry->show)
++ if (!entry->show && !entry->show_limit)
+ return -EIO;
++
++ if (entry->show_limit) {
++ mutex_lock(&disk->queue->limits_lock);
++ res = entry->show_limit(disk, page);
++ mutex_unlock(&disk->queue->limits_lock);
++ return res;
++ }
++
+ mutex_lock(&disk->queue->sysfs_lock);
+ res = entry->show(disk, page);
+ mutex_unlock(&disk->queue->sysfs_lock);
+--
+2.39.5
+
--- /dev/null
+From d84b8e15b814ba4e58268921d63c2bb4a84a374a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 23 Apr 2025 12:53:42 -0700
+Subject: block: fix race between set_blocksize and read paths
+
+From: Darrick J. Wong <djwong@kernel.org>
+
+[ Upstream commit c0e473a0d226479e8e925d5ba93f751d8df628e9 ]
+
+With the new large sector size support, it's now the case that
+set_blocksize can change i_blksize and the folio order in a manner that
+conflicts with a concurrent reader and causes a kernel crash.
+
+Specifically, let's say that udev-worker calls libblkid to detect the
+labels on a block device. The read call can create an order-0 folio to
+read the first 4096 bytes from the disk. But then udev is preempted.
+
+Next, someone tries to mount an 8k-sectorsize filesystem from the same
+block device. The filesystem calls set_blksize, which sets i_blksize to
+8192 and the minimum folio order to 1.
+
+Now udev resumes, still holding the order-0 folio it allocated. It then
+tries to schedule a read bio and do_mpage_readahead tries to create
+bufferheads for the folio. Unfortunately, blocks_per_folio == 0 because
+the page size is 4096 but the blocksize is 8192 so no bufferheads are
+attached and the bh walk never sets bdev. We then submit the bio with a
+NULL block device and crash.
+
+Therefore, truncate the page cache after flushing but before updating
+i_blksize. However, that's not enough -- we also need to lock out file
+IO and page faults during the update. Take both the i_rwsem and the
+invalidate_lock in exclusive mode for invalidations, and in shared mode
+for read/write operations.
+
+I don't know if this is the correct fix, but xfs/259 found it.
+
+Signed-off-by: Darrick J. Wong <djwong@kernel.org>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Reviewed-by: Luis Chamberlain <mcgrof@kernel.org>
+Tested-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
+Link: https://lore.kernel.org/r/174543795699.4139148.2086129139322431423.stgit@frogsfrogsfrogs
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ block/bdev.c | 17 +++++++++++++++++
+ block/blk-zoned.c | 5 ++++-
+ block/fops.c | 16 ++++++++++++++++
+ block/ioctl.c | 6 ++++++
+ 4 files changed, 43 insertions(+), 1 deletion(-)
+
+diff --git a/block/bdev.c b/block/bdev.c
+index 5aebcf437f17c..74f2fe8aa1604 100644
+--- a/block/bdev.c
++++ b/block/bdev.c
+@@ -167,9 +167,26 @@ int set_blocksize(struct file *file, int size)
+
+ /* Don't change the size if it is same as current */
+ if (inode->i_blkbits != blksize_bits(size)) {
++ /*
++ * Flush and truncate the pagecache before we reconfigure the
++ * mapping geometry because folio sizes are variable now. If a
++ * reader has already allocated a folio whose size is smaller
++ * than the new min_order but invokes readahead after the new
++ * min_order becomes visible, readahead will think there are
++ * "zero" blocks per folio and crash. Take the inode and
++ * invalidation locks to avoid racing with
++ * read/write/fallocate.
++ */
++ inode_lock(inode);
++ filemap_invalidate_lock(inode->i_mapping);
++
+ sync_blockdev(bdev);
++ kill_bdev(bdev);
++
+ inode->i_blkbits = blksize_bits(size);
+ kill_bdev(bdev);
++ filemap_invalidate_unlock(inode->i_mapping);
++ inode_unlock(inode);
+ }
+ return 0;
+ }
+diff --git a/block/blk-zoned.c b/block/blk-zoned.c
+index 0c77244a35c92..8f15d1aa6eb89 100644
+--- a/block/blk-zoned.c
++++ b/block/blk-zoned.c
+@@ -343,6 +343,7 @@ int blkdev_zone_mgmt_ioctl(struct block_device *bdev, blk_mode_t mode,
+ op = REQ_OP_ZONE_RESET;
+
+ /* Invalidate the page cache, including dirty pages. */
++ inode_lock(bdev->bd_mapping->host);
+ filemap_invalidate_lock(bdev->bd_mapping);
+ ret = blkdev_truncate_zone_range(bdev, mode, &zrange);
+ if (ret)
+@@ -364,8 +365,10 @@ int blkdev_zone_mgmt_ioctl(struct block_device *bdev, blk_mode_t mode,
+ ret = blkdev_zone_mgmt(bdev, op, zrange.sector, zrange.nr_sectors);
+
+ fail:
+- if (cmd == BLKRESETZONE)
++ if (cmd == BLKRESETZONE) {
+ filemap_invalidate_unlock(bdev->bd_mapping);
++ inode_unlock(bdev->bd_mapping->host);
++ }
+
+ return ret;
+ }
+diff --git a/block/fops.c b/block/fops.c
+index d23ddb2dc1138..82b672d15ea4f 100644
+--- a/block/fops.c
++++ b/block/fops.c
+@@ -746,7 +746,14 @@ static ssize_t blkdev_write_iter(struct kiocb *iocb, struct iov_iter *from)
+ ret = direct_write_fallback(iocb, from, ret,
+ blkdev_buffered_write(iocb, from));
+ } else {
++ /*
++ * Take i_rwsem and invalidate_lock to avoid racing with
++ * set_blocksize changing i_blkbits/folio order and punching
++ * out the pagecache.
++ */
++ inode_lock_shared(bd_inode);
+ ret = blkdev_buffered_write(iocb, from);
++ inode_unlock_shared(bd_inode);
+ }
+
+ if (ret > 0)
+@@ -757,6 +764,7 @@ static ssize_t blkdev_write_iter(struct kiocb *iocb, struct iov_iter *from)
+
+ static ssize_t blkdev_read_iter(struct kiocb *iocb, struct iov_iter *to)
+ {
++ struct inode *bd_inode = bdev_file_inode(iocb->ki_filp);
+ struct block_device *bdev = I_BDEV(iocb->ki_filp->f_mapping->host);
+ loff_t size = bdev_nr_bytes(bdev);
+ loff_t pos = iocb->ki_pos;
+@@ -793,7 +801,13 @@ static ssize_t blkdev_read_iter(struct kiocb *iocb, struct iov_iter *to)
+ goto reexpand;
+ }
+
++ /*
++ * Take i_rwsem and invalidate_lock to avoid racing with set_blocksize
++ * changing i_blkbits/folio order and punching out the pagecache.
++ */
++ inode_lock_shared(bd_inode);
+ ret = filemap_read(iocb, to, ret);
++ inode_unlock_shared(bd_inode);
+
+ reexpand:
+ if (unlikely(shorted))
+@@ -836,6 +850,7 @@ static long blkdev_fallocate(struct file *file, int mode, loff_t start,
+ if ((start | len) & (bdev_logical_block_size(bdev) - 1))
+ return -EINVAL;
+
++ inode_lock(inode);
+ filemap_invalidate_lock(inode->i_mapping);
+
+ /*
+@@ -868,6 +883,7 @@ static long blkdev_fallocate(struct file *file, int mode, loff_t start,
+
+ fail:
+ filemap_invalidate_unlock(inode->i_mapping);
++ inode_unlock(inode);
+ return error;
+ }
+
+diff --git a/block/ioctl.c b/block/ioctl.c
+index 6554b728bae6a..919066b4bb49c 100644
+--- a/block/ioctl.c
++++ b/block/ioctl.c
+@@ -141,6 +141,7 @@ static int blk_ioctl_discard(struct block_device *bdev, blk_mode_t mode,
+ if (err)
+ return err;
+
++ inode_lock(bdev->bd_mapping->host);
+ filemap_invalidate_lock(bdev->bd_mapping);
+ err = truncate_bdev_range(bdev, mode, start, start + len - 1);
+ if (err)
+@@ -173,6 +174,7 @@ static int blk_ioctl_discard(struct block_device *bdev, blk_mode_t mode,
+ blk_finish_plug(&plug);
+ fail:
+ filemap_invalidate_unlock(bdev->bd_mapping);
++ inode_unlock(bdev->bd_mapping->host);
+ return err;
+ }
+
+@@ -198,12 +200,14 @@ static int blk_ioctl_secure_erase(struct block_device *bdev, blk_mode_t mode,
+ end > bdev_nr_bytes(bdev))
+ return -EINVAL;
+
++ inode_lock(bdev->bd_mapping->host);
+ filemap_invalidate_lock(bdev->bd_mapping);
+ err = truncate_bdev_range(bdev, mode, start, end - 1);
+ if (!err)
+ err = blkdev_issue_secure_erase(bdev, start >> 9, len >> 9,
+ GFP_KERNEL);
+ filemap_invalidate_unlock(bdev->bd_mapping);
++ inode_unlock(bdev->bd_mapping->host);
+ return err;
+ }
+
+@@ -235,6 +239,7 @@ static int blk_ioctl_zeroout(struct block_device *bdev, blk_mode_t mode,
+ return -EINVAL;
+
+ /* Invalidate the page cache, including dirty pages */
++ inode_lock(bdev->bd_mapping->host);
+ filemap_invalidate_lock(bdev->bd_mapping);
+ err = truncate_bdev_range(bdev, mode, start, end);
+ if (err)
+@@ -245,6 +250,7 @@ static int blk_ioctl_zeroout(struct block_device *bdev, blk_mode_t mode,
+
+ fail:
+ filemap_invalidate_unlock(bdev->bd_mapping);
++ inode_unlock(bdev->bd_mapping->host);
+ return err;
+ }
+
+--
+2.39.5
+
--- /dev/null
+From b1afbe5a121c263813e0e52d8c8091166fb667e9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 23 Apr 2025 12:53:57 -0700
+Subject: block: hoist block size validation code to a separate function
+
+From: Darrick J. Wong <djwong@kernel.org>
+
+[ Upstream commit e03463d247ddac66e71143468373df3d74a3a6bd ]
+
+Hoist the block size validation code to bdev_validate_blocksize so that
+we can call it from filesystems that don't care about the bdev pagecache
+manipulations of set_blocksize.
+
+Signed-off-by: Darrick J. Wong <djwong@kernel.org>
+Reviewed-by: Luis Chamberlain <mcgrof@kernel.org>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Link: https://lore.kernel.org/r/174543795720.4139148.840349813093799165.stgit@frogsfrogsfrogs
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ block/bdev.c | 33 +++++++++++++++++++++++++++------
+ include/linux/blkdev.h | 1 +
+ 2 files changed, 28 insertions(+), 6 deletions(-)
+
+diff --git a/block/bdev.c b/block/bdev.c
+index 74f2fe8aa1604..9bb7e041bd9ce 100644
+--- a/block/bdev.c
++++ b/block/bdev.c
+@@ -150,18 +150,39 @@ static void set_init_blocksize(struct block_device *bdev)
+ BD_INODE(bdev)->i_blkbits = blksize_bits(bsize);
+ }
+
+-int set_blocksize(struct file *file, int size)
++/**
++ * bdev_validate_blocksize - check that this block size is acceptable
++ * @bdev: blockdevice to check
++ * @block_size: block size to check
++ *
++ * For block device users that do not use buffer heads or the block device
++ * page cache, make sure that this block size can be used with the device.
++ *
++ * Return: On success zero is returned, negative error code on failure.
++ */
++int bdev_validate_blocksize(struct block_device *bdev, int block_size)
+ {
+- struct inode *inode = file->f_mapping->host;
+- struct block_device *bdev = I_BDEV(inode);
+-
+- if (blk_validate_block_size(size))
++ if (blk_validate_block_size(block_size))
+ return -EINVAL;
+
+ /* Size cannot be smaller than the size supported by the device */
+- if (size < bdev_logical_block_size(bdev))
++ if (block_size < bdev_logical_block_size(bdev))
+ return -EINVAL;
+
++ return 0;
++}
++EXPORT_SYMBOL_GPL(bdev_validate_blocksize);
++
++int set_blocksize(struct file *file, int size)
++{
++ struct inode *inode = file->f_mapping->host;
++ struct block_device *bdev = I_BDEV(inode);
++ int ret;
++
++ ret = bdev_validate_blocksize(bdev, size);
++ if (ret)
++ return ret;
++
+ if (!file->private_data)
+ return -EINVAL;
+
+diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
+index 0fec27d6b986c..844af92bea1e4 100644
+--- a/include/linux/blkdev.h
++++ b/include/linux/blkdev.h
+@@ -1616,6 +1616,7 @@ static inline void bio_end_io_acct(struct bio *bio, unsigned long start_time)
+ return bio_end_io_acct_remapped(bio, start_time, bio->bi_bdev);
+ }
+
++int bdev_validate_blocksize(struct block_device *bdev, int block_size);
+ int set_blocksize(struct file *file, int size);
+
+ int lookup_bdev(const char *pathname, dev_t *dev);
+--
+2.39.5
+
--- /dev/null
+From 9c28d57bd498c81ce1ff636c2d580be1b5b0e388 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 25 Feb 2025 07:44:31 -0800
+Subject: block: mark bounce buffering as incompatible with integrity
+
+From: Christoph Hellwig <hch@lst.de>
+
+[ Upstream commit 5fd0268a8806d35dcaf89139bfcda92be51b2b2f ]
+
+None of the few drivers still using the legacy block layer bounce
+buffering support integrity metadata. Explicitly mark the features as
+incompatible and stop creating the slab and mempool for integrity
+buffers for the bounce bio_set.
+
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Reviewed-by: Anuj Gupta <anuj20.g@samsung.com>
+Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
+Reviewed-by: Hannes Reinecke <hare@suse.de>
+Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
+Link: https://lore.kernel.org/r/20250225154449.422989-2-hch@lst.de
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ block/blk-settings.c | 5 +++++
+ block/bounce.c | 2 --
+ 2 files changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/block/blk-settings.c b/block/blk-settings.c
+index 67b119ffa1689..c430c10c864b6 100644
+--- a/block/blk-settings.c
++++ b/block/blk-settings.c
+@@ -124,6 +124,11 @@ static int blk_validate_integrity_limits(struct queue_limits *lim)
+ return 0;
+ }
+
++ if (lim->features & BLK_FEAT_BOUNCE_HIGH) {
++ pr_warn("no bounce buffer support for integrity metadata\n");
++ return -EINVAL;
++ }
++
+ if (!IS_ENABLED(CONFIG_BLK_DEV_INTEGRITY)) {
+ pr_warn("integrity support disabled.\n");
+ return -EINVAL;
+diff --git a/block/bounce.c b/block/bounce.c
+index 0d898cd5ec497..09a9616cf2094 100644
+--- a/block/bounce.c
++++ b/block/bounce.c
+@@ -41,8 +41,6 @@ static void init_bounce_bioset(void)
+
+ ret = bioset_init(&bounce_bio_set, BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS);
+ BUG_ON(ret);
+- if (bioset_integrity_create(&bounce_bio_set, BIO_POOL_SIZE))
+- BUG_ON(1);
+
+ ret = bioset_init(&bounce_bio_split, BIO_POOL_SIZE, 0, 0);
+ BUG_ON(ret);
+--
+2.39.5
+
--- /dev/null
+From e323ee2093795c9375d9f3d5943e88c5a69f78d0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 6 May 2025 13:27:30 +0200
+Subject: block: only update request sector if needed
+
+From: Johannes Thumshirn <johannes.thumshirn@wdc.com>
+
+[ Upstream commit db492e24f9b05547ba12b4783f09c9d943cf42fe ]
+
+In case of a ZONE APPEND write, regardless of native ZONE APPEND or the
+emulation layer in the zone write plugging code, the sector the data got
+written to by the device needs to be updated in the bio.
+
+At the moment, this is done for every native ZONE APPEND write and every
+request that is flagged with 'BIO_ZONE_WRITE_PLUGGING'. But thus
+superfluously updates the sector for regular writes to a zoned block
+device.
+
+Check if a bio is a native ZONE APPEND write or if the bio is flagged as
+'BIO_EMULATES_ZONE_APPEND', meaning the block layer's zone write plugging
+code handles the ZONE APPEND and translates it into a regular write and
+back. Only if one of these two criterion is met, update the sector in the
+bio upon completion.
+
+Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Link: https://lore.kernel.org/r/dea089581cb6b777c1cd1500b38ac0b61df4b2d1.1746530748.git.jth@kernel.org
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ block/blk.h | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/block/blk.h b/block/blk.h
+index 9dcc92c7f2b50..c14f415de5228 100644
+--- a/block/blk.h
++++ b/block/blk.h
+@@ -480,7 +480,8 @@ static inline void blk_zone_update_request_bio(struct request *rq,
+ * the original BIO sector so that blk_zone_write_plug_bio_endio() can
+ * lookup the zone write plug.
+ */
+- if (req_op(rq) == REQ_OP_ZONE_APPEND || bio_zone_write_plugging(bio))
++ if (req_op(rq) == REQ_OP_ZONE_APPEND ||
++ bio_flagged(bio, BIO_EMULATES_ZONE_APPEND))
+ bio->bi_iter.bi_sector = rq->__sector;
+ }
+ void blk_zone_write_plug_bio_endio(struct bio *bio);
+--
+2.39.5
+
--- /dev/null
+From f6d09e15227f761697dffbf10934f9f9d49b2a70 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Mar 2025 18:25:22 -0700
+Subject: Bluetooth: btmtksdio: Prevent enabling interrupts after IRQ handler
+ removal
+
+From: Sean Wang <sean.wang@mediatek.com>
+
+[ Upstream commit 6ac4233afb9a389a7629b7f812395d1d1eca5a83 ]
+
+Ensure interrupts are not re-enabled when the IRQ handler has already been
+removed. This prevents unexpected IRQ handler execution due to stale or
+unhandled interrupts.
+
+Modify btmtksdio_txrx_work to check if bdev->func->irq_handler exists
+before calling sdio_writel to enable interrupts.
+
+Co-developed-by: Pedro Tsai <pedro.tsai@mediatek.com>
+Signed-off-by: Pedro Tsai <pedro.tsai@mediatek.com>
+Co-developed-by: Felix Freimann <felix.freimann@mediatek.com>
+Signed-off-by: Felix Freimann <felix.freimann@mediatek.com>
+Signed-off-by: Sean Wang <sean.wang@mediatek.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/bluetooth/btmtksdio.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c
+index bd5464bde174f..edd5eead1e93b 100644
+--- a/drivers/bluetooth/btmtksdio.c
++++ b/drivers/bluetooth/btmtksdio.c
+@@ -610,7 +610,8 @@ static void btmtksdio_txrx_work(struct work_struct *work)
+ } while (int_status || time_is_before_jiffies(txrx_timeout));
+
+ /* Enable interrupt */
+- sdio_writel(bdev->func, C_INT_EN_SET, MTK_REG_CHLPCR, NULL);
++ if (bdev->func->irq_handler)
++ sdio_writel(bdev->func, C_INT_EN_SET, MTK_REG_CHLPCR, NULL);
+
+ sdio_release_host(bdev->func);
+
+--
+2.39.5
+
--- /dev/null
+From 77457a5abbcdbe18a59fc1571fb1bf7c52b8ff0a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 1 Mar 2025 03:23:00 -0300
+Subject: Bluetooth: Disable SCO support if READ_VOICE_SETTING is
+ unsupported/broken
+
+From: Pedro Nishiyama <nishiyama.pedro@gmail.com>
+
+[ Upstream commit 14d17c78a4b1660c443bae9d38c814edea506f62 ]
+
+A SCO connection without the proper voice_setting can cause
+the controller to lock up.
+
+Signed-off-by: Pedro Nishiyama <nishiyama.pedro@gmail.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bluetooth/hci_event.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
+index ab940ec698c0f..7152a1ca56778 100644
+--- a/net/bluetooth/hci_event.c
++++ b/net/bluetooth/hci_event.c
+@@ -930,6 +930,9 @@ static u8 hci_cc_read_buffer_size(struct hci_dev *hdev, void *data,
+ hdev->sco_pkts = 8;
+ }
+
++ if (!read_voice_setting_capable(hdev))
++ hdev->sco_pkts = 0;
++
+ hdev->acl_cnt = hdev->acl_pkts;
+ hdev->sco_cnt = hdev->sco_pkts;
+
+--
+2.39.5
+
--- /dev/null
+From 024d1bb7f270f3601c38a51cc2e0754e3f7fe8b3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 10 Mar 2025 11:31:26 -0700
+Subject: bnxt_en: Query FW parameters when the CAPS_CHANGE bit is set
+
+From: shantiprasad shettar <shantiprasad.shettar@broadcom.com>
+
+[ Upstream commit a6c81e32aeacbfd530d576fa401edd506ec966ef ]
+
+Newer FW can set the CAPS_CHANGE flag during ifup if some capabilities
+or configurations have changed. For example, the CoS queue
+configurations may have changed. Support this new flag by treating it
+almost like FW reset. The driver will essentially rediscover all
+features and capabilities, reconfigure all backing store context memory,
+reset everything to default, and reserve all resources.
+
+Reviewed-by: Somnath Kotur <somnath.kotur@broadcom.com>
+Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Signed-off-by: shantiprasad shettar <shantiprasad.shettar@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20250310183129.3154117-5-michael.chan@broadcom.com
+Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index bd8b9cb05ae98..1a19c922009d1 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -12104,6 +12104,7 @@ static int bnxt_hwrm_if_change(struct bnxt *bp, bool up)
+ struct hwrm_func_drv_if_change_input *req;
+ bool fw_reset = !bp->irq_tbl;
+ bool resc_reinit = false;
++ bool caps_change = false;
+ int rc, retry = 0;
+ u32 flags = 0;
+
+@@ -12159,8 +12160,11 @@ static int bnxt_hwrm_if_change(struct bnxt *bp, bool up)
+ set_bit(BNXT_STATE_ABORT_ERR, &bp->state);
+ return -ENODEV;
+ }
+- if (resc_reinit || fw_reset) {
+- if (fw_reset) {
++ if (flags & FUNC_DRV_IF_CHANGE_RESP_FLAGS_CAPS_CHANGE)
++ caps_change = true;
++
++ if (resc_reinit || fw_reset || caps_change) {
++ if (fw_reset || caps_change) {
+ set_bit(BNXT_STATE_FW_RESET_DET, &bp->state);
+ if (!test_bit(BNXT_STATE_IN_FW_RESET, &bp->state))
+ bnxt_ulp_irq_stop(bp);
+--
+2.39.5
+
--- /dev/null
+From 099dd05b4c77fd0d1a6cf6c26441e9593975fa3c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 12 Feb 2025 17:12:29 -0800
+Subject: bnxt_en: Set NPAR 1.2 support when registering with firmware
+
+From: Michael Chan <michael.chan@broadcom.com>
+
+[ Upstream commit ebdf7fe488c512b18add66b6c26e11e4d3830213 ]
+
+NPAR (Network interface card partitioning)[1] 1.2 adds a transparent
+VLAN tag for all packets between the NIC and the switch. Because of
+that, RX VLAN acceleration cannot be supported for any additional
+host configured VLANs. The driver has to acknowledge that it can
+support no RX VLAN acceleration and set the NPAR 1.2 supported flag
+when registering with the FW. Otherwise, the FW call will fail and
+the driver will abort on these NPAR 1.2 NICs with this error:
+
+bnxt_en 0000:26:00.0 (unnamed net_device) (uninitialized): hwrm req_type 0x1d seq id 0xb error 0x2
+
+[1] https://techdocs.broadcom.com/us/en/storage-and-ethernet-connectivity/ethernet-nic-controllers/bcm957xxx/adapters/introduction/features/network-partitioning-npar.html
+
+Reviewed-by: Somnath Kotur <somnath.kotur@broadcom.com>
+Reviewed-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20250213011240.1640031-2-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 5 +++++
+ drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 +
+ 2 files changed, 6 insertions(+)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index 1a19c922009d1..d844cf621dd23 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -5589,6 +5589,8 @@ int bnxt_hwrm_func_drv_rgtr(struct bnxt *bp, unsigned long *bmap, int bmap_size,
+ if (bp->fw_cap & BNXT_FW_CAP_ERROR_RECOVERY)
+ flags |= FUNC_DRV_RGTR_REQ_FLAGS_ERROR_RECOVERY_SUPPORT |
+ FUNC_DRV_RGTR_REQ_FLAGS_MASTER_SUPPORT;
++ if (bp->fw_cap & BNXT_FW_CAP_NPAR_1_2)
++ flags |= FUNC_DRV_RGTR_REQ_FLAGS_NPAR_1_2_SUPPORT;
+ req->flags = cpu_to_le32(flags);
+ req->ver_maj_8b = DRV_VER_MAJ;
+ req->ver_min_8b = DRV_VER_MIN;
+@@ -8389,6 +8391,7 @@ static int bnxt_hwrm_func_qcfg(struct bnxt *bp)
+
+ switch (resp->port_partition_type) {
+ case FUNC_QCFG_RESP_PORT_PARTITION_TYPE_NPAR1_0:
++ case FUNC_QCFG_RESP_PORT_PARTITION_TYPE_NPAR1_2:
+ case FUNC_QCFG_RESP_PORT_PARTITION_TYPE_NPAR1_5:
+ case FUNC_QCFG_RESP_PORT_PARTITION_TYPE_NPAR2_0:
+ bp->port_partition_type = resp->port_partition_type;
+@@ -9553,6 +9556,8 @@ static int __bnxt_hwrm_func_qcaps(struct bnxt *bp)
+ bp->fw_cap |= BNXT_FW_CAP_HOT_RESET_IF;
+ if (BNXT_PF(bp) && (flags_ext & FUNC_QCAPS_RESP_FLAGS_EXT_FW_LIVEPATCH_SUPPORTED))
+ bp->fw_cap |= BNXT_FW_CAP_LIVEPATCH;
++ if (flags_ext & FUNC_QCAPS_RESP_FLAGS_EXT_NPAR_1_2_SUPPORTED)
++ bp->fw_cap |= BNXT_FW_CAP_NPAR_1_2;
+ if (BNXT_PF(bp) && (flags_ext & FUNC_QCAPS_RESP_FLAGS_EXT_DFLT_VLAN_TPID_PCP_SUPPORTED))
+ bp->fw_cap |= BNXT_FW_CAP_DFLT_VLAN_TPID_PCP;
+ if (flags_ext & FUNC_QCAPS_RESP_FLAGS_EXT_BS_V2_SUPPORTED)
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+index d621fb621f30c..f91d9d8eacb97 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+@@ -2498,6 +2498,7 @@ struct bnxt {
+ #define BNXT_FW_CAP_CFA_RFS_RING_TBL_IDX_V3 BIT_ULL(39)
+ #define BNXT_FW_CAP_VNIC_RE_FLUSH BIT_ULL(40)
+ #define BNXT_FW_CAP_SW_MAX_RESOURCE_LIMITS BIT_ULL(41)
++ #define BNXT_FW_CAP_NPAR_1_2 BIT_ULL(42)
+
+ u32 fw_dbg_cap;
+
+--
+2.39.5
+
--- /dev/null
+From fedd93f605a29be19d1102d7f1051bca1ba1add7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 25 Feb 2025 03:39:14 +0000
+Subject: bonding: report duplicate MAC address in all situations
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Hangbin Liu <liuhangbin@gmail.com>
+
+[ Upstream commit 28d68d396a1cd21591e8c6d74afbde33a7ea107e ]
+
+Normally, a bond uses the MAC address of the first added slave as the bond’s
+MAC address. And the bond will set active slave’s MAC address to bond’s
+address if fail_over_mac is set to none (0) or follow (2).
+
+When the first slave is removed, the bond will still use the removed slave’s
+MAC address, which can lead to a duplicate MAC address and potentially cause
+issues with the switch. To avoid confusion, let's warn the user in all
+situations, including when fail_over_mac is set to 2 or not in active-backup
+mode.
+
+Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
+Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org>
+Link: https://patch.msgid.link/20250225033914.18617-1-liuhangbin@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/bonding/bond_main.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
+index 4da5fcb7def47..203d3467dcbcd 100644
+--- a/drivers/net/bonding/bond_main.c
++++ b/drivers/net/bonding/bond_main.c
+@@ -2551,7 +2551,7 @@ static int __bond_release_one(struct net_device *bond_dev,
+
+ RCU_INIT_POINTER(bond->current_arp_slave, NULL);
+
+- if (!all && (!bond->params.fail_over_mac ||
++ if (!all && (bond->params.fail_over_mac != BOND_FOM_ACTIVE ||
+ BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP)) {
+ if (ether_addr_equal_64bits(bond_dev->dev_addr, slave->perm_hwaddr) &&
+ bond_has_slaves(bond))
+--
+2.39.5
+
--- /dev/null
+From 413945f13cd00d58eaf0c6ae4d627efaedb9fedf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 10 Mar 2025 07:44:09 -0500
+Subject: book3s64/radix: Fix compile errors when
+ CONFIG_ARCH_WANT_OPTIMIZE_DAX_VMEMMAP=n
+
+From: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
+
+[ Upstream commit 29bdc1f1c1df80868fb35bc69d1f073183adc6de ]
+
+Fix compile errors when CONFIG_ARCH_WANT_OPTIMIZE_DAX_VMEMMAP=n
+
+Signed-off-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
+Signed-off-by: Donet Tom <donettom@linux.ibm.com>
+Signed-off-by: Madhavan Srinivasan <maddy@linux.ibm.com>
+Link: https://patch.msgid.link/8231763344223c193e3452eab0ae8ea966aff466.1741609795.git.donettom@linux.ibm.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/powerpc/mm/book3s64/radix_pgtable.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/arch/powerpc/mm/book3s64/radix_pgtable.c b/arch/powerpc/mm/book3s64/radix_pgtable.c
+index 128c011afc481..9f764bc42b8cc 100644
+--- a/arch/powerpc/mm/book3s64/radix_pgtable.c
++++ b/arch/powerpc/mm/book3s64/radix_pgtable.c
+@@ -976,7 +976,7 @@ int __meminit radix__vmemmap_create_mapping(unsigned long start,
+ return 0;
+ }
+
+-
++#ifdef CONFIG_ARCH_WANT_OPTIMIZE_DAX_VMEMMAP
+ bool vmemmap_can_optimize(struct vmem_altmap *altmap, struct dev_pagemap *pgmap)
+ {
+ if (radix_enabled())
+@@ -984,6 +984,7 @@ bool vmemmap_can_optimize(struct vmem_altmap *altmap, struct dev_pagemap *pgmap)
+
+ return false;
+ }
++#endif
+
+ int __meminit vmemmap_check_pmd(pmd_t *pmdp, int node,
+ unsigned long addr, unsigned long next)
+--
+2.39.5
+
--- /dev/null
+From 660ea29bcc54cea0b7e664ab14d192a99a42a19f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 24 Feb 2025 16:38:38 -0800
+Subject: bpf: abort verification if env->cur_state->loop_entry != NULL
+
+From: Eduard Zingerman <eddyz87@gmail.com>
+
+[ Upstream commit f3c2d243a36ef23be07bc2bce7c6a5cb6e07d9e3 ]
+
+In addition to warning abort verification with -EFAULT.
+If env->cur_state->loop_entry != NULL something is irrecoverably
+buggy.
+
+Fixes: bbbc02b7445e ("bpf: copy_verifier_state() should copy 'loop_entry' field")
+Suggested-by: Andrii Nakryiko <andrii.nakryiko@gmail.com>
+Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
+Acked-by: Andrii Nakryiko <andrii@kernel.org>
+Link: https://lore.kernel.org/r/20250225003838.135319-1-eddyz87@gmail.com
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/verifier.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index 4392436ba7511..1841467c4f2e5 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -19265,8 +19265,10 @@ static int do_check(struct bpf_verifier_env *env)
+ return err;
+ break;
+ } else {
+- if (WARN_ON_ONCE(env->cur_state->loop_entry))
+- env->cur_state->loop_entry = NULL;
++ if (WARN_ON_ONCE(env->cur_state->loop_entry)) {
++ verbose(env, "verifier bug: env->cur_state->loop_entry != NULL\n");
++ return -EFAULT;
++ }
+ do_print_state = true;
+ continue;
+ }
+--
+2.39.5
+
--- /dev/null
+From cb7b489bf28ad53fee98de808363b2eb2bb4324e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 24 Feb 2025 15:01:16 -0800
+Subject: bpf: Allow pre-ordering for bpf cgroup progs
+
+From: Yonghong Song <yonghong.song@linux.dev>
+
+[ Upstream commit 4b82b181a26cff8bf7adc3a85a88d121d92edeaf ]
+
+Currently for bpf progs in a cgroup hierarchy, the effective prog array
+is computed from bottom cgroup to upper cgroups (post-ordering). For
+example, the following cgroup hierarchy
+ root cgroup: p1, p2
+ subcgroup: p3, p4
+have BPF_F_ALLOW_MULTI for both cgroup levels.
+The effective cgroup array ordering looks like
+ p3 p4 p1 p2
+and at run time, progs will execute based on that order.
+
+But in some cases, it is desirable to have root prog executes earlier than
+children progs (pre-ordering). For example,
+ - prog p1 intends to collect original pkt dest addresses.
+ - prog p3 will modify original pkt dest addresses to a proxy address for
+ security reason.
+The end result is that prog p1 gets proxy address which is not what it
+wants. Putting p1 to every child cgroup is not desirable either as it
+will duplicate itself in many child cgroups. And this is exactly a use case
+we are encountering in Meta.
+
+To fix this issue, let us introduce a flag BPF_F_PREORDER. If the flag
+is specified at attachment time, the prog has higher priority and the
+ordering with that flag will be from top to bottom (pre-ordering).
+For example, in the above example,
+ root cgroup: p1, p2
+ subcgroup: p3, p4
+Let us say p2 and p4 are marked with BPF_F_PREORDER. The final
+effective array ordering will be
+ p2 p4 p3 p1
+
+Suggested-by: Andrii Nakryiko <andrii@kernel.org>
+Acked-by: Andrii Nakryiko <andrii@kernel.org>
+Signed-off-by: Yonghong Song <yonghong.song@linux.dev>
+Link: https://lore.kernel.org/r/20250224230116.283071-1-yonghong.song@linux.dev
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/bpf-cgroup.h | 1 +
+ include/uapi/linux/bpf.h | 1 +
+ kernel/bpf/cgroup.c | 33 +++++++++++++++++++++++++--------
+ kernel/bpf/syscall.c | 3 ++-
+ tools/include/uapi/linux/bpf.h | 1 +
+ 5 files changed, 30 insertions(+), 9 deletions(-)
+
+diff --git a/include/linux/bpf-cgroup.h b/include/linux/bpf-cgroup.h
+index 7fc69083e7450..9de7adb682948 100644
+--- a/include/linux/bpf-cgroup.h
++++ b/include/linux/bpf-cgroup.h
+@@ -111,6 +111,7 @@ struct bpf_prog_list {
+ struct bpf_prog *prog;
+ struct bpf_cgroup_link *link;
+ struct bpf_cgroup_storage *storage[MAX_BPF_CGROUP_STORAGE_TYPE];
++ u32 flags;
+ };
+
+ int cgroup_bpf_inherit(struct cgroup *cgrp);
+diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
+index 2acf9b3363717..89242184a1937 100644
+--- a/include/uapi/linux/bpf.h
++++ b/include/uapi/linux/bpf.h
+@@ -1207,6 +1207,7 @@ enum bpf_perf_event_type {
+ #define BPF_F_BEFORE (1U << 3)
+ #define BPF_F_AFTER (1U << 4)
+ #define BPF_F_ID (1U << 5)
++#define BPF_F_PREORDER (1U << 6)
+ #define BPF_F_LINK BPF_F_LINK /* 1 << 13 */
+
+ /* If BPF_F_STRICT_ALIGNMENT is used in BPF_PROG_LOAD command, the
+diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c
+index 46e5db65dbc8d..84f58f3d028a3 100644
+--- a/kernel/bpf/cgroup.c
++++ b/kernel/bpf/cgroup.c
+@@ -369,7 +369,7 @@ static struct bpf_prog *prog_list_prog(struct bpf_prog_list *pl)
+ /* count number of elements in the list.
+ * it's slow but the list cannot be long
+ */
+-static u32 prog_list_length(struct hlist_head *head)
++static u32 prog_list_length(struct hlist_head *head, int *preorder_cnt)
+ {
+ struct bpf_prog_list *pl;
+ u32 cnt = 0;
+@@ -377,6 +377,8 @@ static u32 prog_list_length(struct hlist_head *head)
+ hlist_for_each_entry(pl, head, node) {
+ if (!prog_list_prog(pl))
+ continue;
++ if (preorder_cnt && (pl->flags & BPF_F_PREORDER))
++ (*preorder_cnt)++;
+ cnt++;
+ }
+ return cnt;
+@@ -400,7 +402,7 @@ static bool hierarchy_allows_attach(struct cgroup *cgrp,
+
+ if (flags & BPF_F_ALLOW_MULTI)
+ return true;
+- cnt = prog_list_length(&p->bpf.progs[atype]);
++ cnt = prog_list_length(&p->bpf.progs[atype], NULL);
+ WARN_ON_ONCE(cnt > 1);
+ if (cnt == 1)
+ return !!(flags & BPF_F_ALLOW_OVERRIDE);
+@@ -423,12 +425,12 @@ static int compute_effective_progs(struct cgroup *cgrp,
+ struct bpf_prog_array *progs;
+ struct bpf_prog_list *pl;
+ struct cgroup *p = cgrp;
+- int cnt = 0;
++ int i, j, cnt = 0, preorder_cnt = 0, fstart, bstart, init_bstart;
+
+ /* count number of effective programs by walking parents */
+ do {
+ if (cnt == 0 || (p->bpf.flags[atype] & BPF_F_ALLOW_MULTI))
+- cnt += prog_list_length(&p->bpf.progs[atype]);
++ cnt += prog_list_length(&p->bpf.progs[atype], &preorder_cnt);
+ p = cgroup_parent(p);
+ } while (p);
+
+@@ -439,20 +441,34 @@ static int compute_effective_progs(struct cgroup *cgrp,
+ /* populate the array with effective progs */
+ cnt = 0;
+ p = cgrp;
++ fstart = preorder_cnt;
++ bstart = preorder_cnt - 1;
+ do {
+ if (cnt > 0 && !(p->bpf.flags[atype] & BPF_F_ALLOW_MULTI))
+ continue;
+
++ init_bstart = bstart;
+ hlist_for_each_entry(pl, &p->bpf.progs[atype], node) {
+ if (!prog_list_prog(pl))
+ continue;
+
+- item = &progs->items[cnt];
++ if (pl->flags & BPF_F_PREORDER) {
++ item = &progs->items[bstart];
++ bstart--;
++ } else {
++ item = &progs->items[fstart];
++ fstart++;
++ }
+ item->prog = prog_list_prog(pl);
+ bpf_cgroup_storages_assign(item->cgroup_storage,
+ pl->storage);
+ cnt++;
+ }
++
++ /* reverse pre-ordering progs at this cgroup level */
++ for (i = bstart + 1, j = init_bstart; i < j; i++, j--)
++ swap(progs->items[i], progs->items[j]);
++
+ } while ((p = cgroup_parent(p)));
+
+ *array = progs;
+@@ -663,7 +679,7 @@ static int __cgroup_bpf_attach(struct cgroup *cgrp,
+ */
+ return -EPERM;
+
+- if (prog_list_length(progs) >= BPF_CGROUP_MAX_PROGS)
++ if (prog_list_length(progs, NULL) >= BPF_CGROUP_MAX_PROGS)
+ return -E2BIG;
+
+ pl = find_attach_entry(progs, prog, link, replace_prog,
+@@ -698,6 +714,7 @@ static int __cgroup_bpf_attach(struct cgroup *cgrp,
+
+ pl->prog = prog;
+ pl->link = link;
++ pl->flags = flags;
+ bpf_cgroup_storages_assign(pl->storage, storage);
+ cgrp->bpf.flags[atype] = saved_flags;
+
+@@ -1073,7 +1090,7 @@ static int __cgroup_bpf_query(struct cgroup *cgrp, const union bpf_attr *attr,
+ lockdep_is_held(&cgroup_mutex));
+ total_cnt += bpf_prog_array_length(effective);
+ } else {
+- total_cnt += prog_list_length(&cgrp->bpf.progs[atype]);
++ total_cnt += prog_list_length(&cgrp->bpf.progs[atype], NULL);
+ }
+ }
+
+@@ -1105,7 +1122,7 @@ static int __cgroup_bpf_query(struct cgroup *cgrp, const union bpf_attr *attr,
+ u32 id;
+
+ progs = &cgrp->bpf.progs[atype];
+- cnt = min_t(int, prog_list_length(progs), total_cnt);
++ cnt = min_t(int, prog_list_length(progs, NULL), total_cnt);
+ i = 0;
+ hlist_for_each_entry(pl, progs, node) {
+ prog = prog_list_prog(pl);
+diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
+index 87f886ed33bc3..8c42c094f0d1e 100644
+--- a/kernel/bpf/syscall.c
++++ b/kernel/bpf/syscall.c
+@@ -4169,7 +4169,8 @@ static int bpf_prog_attach_check_attach_type(const struct bpf_prog *prog,
+ #define BPF_F_ATTACH_MASK_BASE \
+ (BPF_F_ALLOW_OVERRIDE | \
+ BPF_F_ALLOW_MULTI | \
+- BPF_F_REPLACE)
++ BPF_F_REPLACE | \
++ BPF_F_PREORDER)
+
+ #define BPF_F_ATTACH_MASK_MPROG \
+ (BPF_F_REPLACE | \
+diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
+index 2acf9b3363717..89242184a1937 100644
+--- a/tools/include/uapi/linux/bpf.h
++++ b/tools/include/uapi/linux/bpf.h
+@@ -1207,6 +1207,7 @@ enum bpf_perf_event_type {
+ #define BPF_F_BEFORE (1U << 3)
+ #define BPF_F_AFTER (1U << 4)
+ #define BPF_F_ID (1U << 5)
++#define BPF_F_PREORDER (1U << 6)
+ #define BPF_F_LINK BPF_F_LINK /* 1 << 13 */
+
+ /* If BPF_F_STRICT_ALIGNMENT is used in BPF_PROG_LOAD command, the
+--
+2.39.5
+
--- /dev/null
+From 0975780bdc4f437d30ba5c9257822b6eb9ab185a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Feb 2025 00:02:40 -0800
+Subject: bpf: arm64: Silence "UBSAN: negation-overflow" warning
+
+From: Song Liu <song@kernel.org>
+
+[ Upstream commit 239860828f8660e2be487e2fbdae2640cce3fd67 ]
+
+With UBSAN, test_bpf.ko triggers warnings like:
+
+UBSAN: negation-overflow in arch/arm64/net/bpf_jit_comp.c:1333:28
+negation of -2147483648 cannot be represented in type 's32' (aka 'int'):
+
+Silence these warnings by casting imm to u32 first.
+
+Reported-by: Breno Leitao <leitao@debian.org>
+Signed-off-by: Song Liu <song@kernel.org>
+Tested-by: Breno Leitao <leitao@debian.org>
+Link: https://lore.kernel.org/r/20250218080240.2431257-1-song@kernel.org
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/net/bpf_jit_comp.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c
+index 3126881fe6768..970c49bb7ed47 100644
+--- a/arch/arm64/net/bpf_jit_comp.c
++++ b/arch/arm64/net/bpf_jit_comp.c
+@@ -274,7 +274,7 @@ static inline void emit_a64_add_i(const bool is64, const int dst, const int src,
+ {
+ if (is_addsub_imm(imm)) {
+ emit(A64_ADD_I(is64, dst, src, imm), ctx);
+- } else if (is_addsub_imm(-imm)) {
++ } else if (is_addsub_imm(-(u32)imm)) {
+ emit(A64_SUB_I(is64, dst, src, -imm), ctx);
+ } else {
+ emit_a64_mov_i(is64, tmp, imm, ctx);
+@@ -1208,7 +1208,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
+ case BPF_ALU64 | BPF_SUB | BPF_K:
+ if (is_addsub_imm(imm)) {
+ emit(A64_SUB_I(is64, dst, dst, imm), ctx);
+- } else if (is_addsub_imm(-imm)) {
++ } else if (is_addsub_imm(-(u32)imm)) {
+ emit(A64_ADD_I(is64, dst, dst, -imm), ctx);
+ } else {
+ emit_a64_mov_i(is64, tmp, imm, ctx);
+@@ -1379,7 +1379,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
+ case BPF_JMP32 | BPF_JSLE | BPF_K:
+ if (is_addsub_imm(imm)) {
+ emit(A64_CMP_I(is64, dst, imm), ctx);
+- } else if (is_addsub_imm(-imm)) {
++ } else if (is_addsub_imm(-(u32)imm)) {
+ emit(A64_CMN_I(is64, dst, -imm), ctx);
+ } else {
+ emit_a64_mov_i(is64, tmp, imm, ctx);
+--
+2.39.5
+
--- /dev/null
+From 2cf0389fa61d40c380f3c3d1e5249511d3c473dd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 15 Feb 2025 03:03:52 -0800
+Subject: bpf: copy_verifier_state() should copy 'loop_entry' field
+
+From: Eduard Zingerman <eddyz87@gmail.com>
+
+[ Upstream commit bbbc02b7445ebfda13e4847f4f1413c6480a85a9 ]
+
+The bpf_verifier_state.loop_entry state should be copied by
+copy_verifier_state(). Otherwise, .loop_entry values from unrelated
+states would poison env->cur_state.
+
+Additionally, env->stack should not contain any states with
+.loop_entry != NULL. The states in env->stack are yet to be verified,
+while .loop_entry is set for states that reached an equivalent state.
+This means that env->cur_state->loop_entry should always be NULL after
+pop_stack().
+
+See the selftest in the next commit for an example of the program that
+is not safe yet is accepted by verifier w/o this fix.
+
+This change has some verification performance impact for selftests:
+
+File Program Insns (A) Insns (B) Insns (DIFF) States (A) States (B) States (DIFF)
+---------------------------------- ---------------------------- --------- --------- -------------- ---------- ---------- -------------
+arena_htab.bpf.o arena_htab_llvm 717 426 -291 (-40.59%) 57 37 -20 (-35.09%)
+arena_htab_asm.bpf.o arena_htab_asm 597 445 -152 (-25.46%) 47 37 -10 (-21.28%)
+arena_list.bpf.o arena_list_del 309 279 -30 (-9.71%) 23 14 -9 (-39.13%)
+iters.bpf.o iter_subprog_check_stacksafe 155 141 -14 (-9.03%) 15 14 -1 (-6.67%)
+iters.bpf.o iter_subprog_iters 1094 1003 -91 (-8.32%) 88 83 -5 (-5.68%)
+iters.bpf.o loop_state_deps2 479 725 +246 (+51.36%) 46 63 +17 (+36.96%)
+kmem_cache_iter.bpf.o open_coded_iter 63 59 -4 (-6.35%) 7 6 -1 (-14.29%)
+verifier_bits_iter.bpf.o max_words 92 84 -8 (-8.70%) 8 7 -1 (-12.50%)
+verifier_iterating_callbacks.bpf.o cond_break2 113 107 -6 (-5.31%) 12 12 +0 (+0.00%)
+
+And significant negative impact for sched_ext:
+
+File Program Insns (A) Insns (B) Insns (DIFF) States (A) States (B) States (DIFF)
+----------------- ---------------------- --------- --------- -------------------- ---------- ---------- ------------------
+bpf.bpf.o lavd_init 7039 14723 +7684 (+109.16%) 490 1139 +649 (+132.45%)
+bpf.bpf.o layered_dispatch 11485 10548 -937 (-8.16%) 848 762 -86 (-10.14%)
+bpf.bpf.o layered_dump 7422 1000001 +992579 (+13373.47%) 681 31178 +30497 (+4478.27%)
+bpf.bpf.o layered_enqueue 16854 71127 +54273 (+322.02%) 1611 6450 +4839 (+300.37%)
+bpf.bpf.o p2dq_dispatch 665 791 +126 (+18.95%) 68 78 +10 (+14.71%)
+bpf.bpf.o p2dq_init 2343 2980 +637 (+27.19%) 201 237 +36 (+17.91%)
+bpf.bpf.o refresh_layer_cpumasks 16487 674760 +658273 (+3992.68%) 1770 65370 +63600 (+3593.22%)
+bpf.bpf.o rusty_select_cpu 1937 40872 +38935 (+2010.07%) 177 3210 +3033 (+1713.56%)
+scx_central.bpf.o central_dispatch 636 2687 +2051 (+322.48%) 63 227 +164 (+260.32%)
+scx_nest.bpf.o nest_init 636 815 +179 (+28.14%) 60 73 +13 (+21.67%)
+scx_qmap.bpf.o qmap_dispatch 2393 3580 +1187 (+49.60%) 196 253 +57 (+29.08%)
+scx_qmap.bpf.o qmap_dump 233 318 +85 (+36.48%) 22 30 +8 (+36.36%)
+scx_qmap.bpf.o qmap_init 16367 17436 +1069 (+6.53%) 603 669 +66 (+10.95%)
+
+Note 'layered_dump' program, which now hits 1M instructions limit.
+This impact would be mitigated in the next patch.
+
+Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
+Link: https://lore.kernel.org/r/20250215110411.3236773-2-eddyz87@gmail.com
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/verifier.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index 68715b18df5e2..0752e8e556389 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -1661,6 +1661,7 @@ static int copy_verifier_state(struct bpf_verifier_state *dst_state,
+ dst_state->callback_unroll_depth = src->callback_unroll_depth;
+ dst_state->used_as_loop_entry = src->used_as_loop_entry;
+ dst_state->may_goto_depth = src->may_goto_depth;
++ dst_state->loop_entry = src->loop_entry;
+ for (i = 0; i <= src->curframe; i++) {
+ dst = dst_state->frame[i];
+ if (!dst) {
+@@ -19264,6 +19265,8 @@ static int do_check(struct bpf_verifier_env *env)
+ return err;
+ break;
+ } else {
++ if (WARN_ON_ONCE(env->cur_state->loop_entry))
++ env->cur_state->loop_entry = NULL;
+ do_print_state = true;
+ continue;
+ }
+--
+2.39.5
+
--- /dev/null
+From c897c66288748b76a15149ef63802a7bf694d2db Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 15 Feb 2025 03:03:54 -0800
+Subject: bpf: don't do clean_live_states when state->loop_entry->branches > 0
+
+From: Eduard Zingerman <eddyz87@gmail.com>
+
+[ Upstream commit 9e63fdb0cbdf3268c86638a8274f4d5549a82820 ]
+
+verifier.c:is_state_visited() uses RANGE_WITHIN states comparison rules
+for cached states that have loop_entry with non-zero branches count
+(meaning that loop_entry's verification is not yet done).
+
+The RANGE_WITHIN rules in regsafe()/stacksafe() require register and
+stack objects types to be identical in current and old states.
+
+verifier.c:clean_live_states() replaces registers and stack spills
+with NOT_INIT/STACK_INVALID marks, if these registers/stack spills are
+not read in any child state. This means that clean_live_states() works
+against loop convergence logic under some conditions. See selftest in
+the next patch for a specific example.
+
+Mitigate this by prohibiting clean_verifier_state() when
+state->loop_entry->branches > 0.
+
+This undoes negative verification performance impact of the
+copy_verifier_state() fix from the previous patch.
+Below is comparison between master and current patch.
+
+selftests:
+
+File Program Insns (A) Insns (B) Insns (DIFF) States (A) States (B) States (DIFF)
+---------------------------------- ---------------------------- --------- --------- --------------- ---------- ---------- --------------
+arena_htab.bpf.o arena_htab_llvm 717 423 -294 (-41.00%) 57 37 -20 (-35.09%)
+arena_htab_asm.bpf.o arena_htab_asm 597 445 -152 (-25.46%) 47 37 -10 (-21.28%)
+arena_list.bpf.o arena_list_add 1493 1822 +329 (+22.04%) 30 37 +7 (+23.33%)
+arena_list.bpf.o arena_list_del 309 261 -48 (-15.53%) 23 15 -8 (-34.78%)
+iters.bpf.o checkpoint_states_deletion 18125 22154 +4029 (+22.23%) 818 918 +100 (+12.22%)
+iters.bpf.o iter_nested_deeply_iters 593 367 -226 (-38.11%) 67 43 -24 (-35.82%)
+iters.bpf.o iter_nested_iters 813 772 -41 (-5.04%) 79 72 -7 (-8.86%)
+iters.bpf.o iter_subprog_check_stacksafe 155 135 -20 (-12.90%) 15 14 -1 (-6.67%)
+iters.bpf.o iter_subprog_iters 1094 808 -286 (-26.14%) 88 68 -20 (-22.73%)
+iters.bpf.o loop_state_deps2 479 356 -123 (-25.68%) 46 35 -11 (-23.91%)
+iters.bpf.o triple_continue 35 31 -4 (-11.43%) 3 3 +0 (+0.00%)
+kmem_cache_iter.bpf.o open_coded_iter 63 59 -4 (-6.35%) 7 6 -1 (-14.29%)
+mptcp_subflow.bpf.o _getsockopt_subflow 501 446 -55 (-10.98%) 25 23 -2 (-8.00%)
+pyperf600_iter.bpf.o on_event 12339 6379 -5960 (-48.30%) 441 286 -155 (-35.15%)
+verifier_bits_iter.bpf.o max_words 92 84 -8 (-8.70%) 8 7 -1 (-12.50%)
+verifier_iterating_callbacks.bpf.o cond_break2 113 192 +79 (+69.91%) 12 21 +9 (+75.00%)
+
+sched_ext:
+
+File Program Insns (A) Insns (B) Insns (DIFF) States (A) States (B) States (DIFF)
+----------------- ---------------------- --------- --------- ----------------- ---------- ---------- ----------------
+bpf.bpf.o layered_dispatch 11485 9039 -2446 (-21.30%) 848 662 -186 (-21.93%)
+bpf.bpf.o layered_dump 7422 5022 -2400 (-32.34%) 681 298 -383 (-56.24%)
+bpf.bpf.o layered_enqueue 16854 13753 -3101 (-18.40%) 1611 1308 -303 (-18.81%)
+bpf.bpf.o layered_init 1000001 5549 -994452 (-99.45%) 84672 523 -84149 (-99.38%)
+bpf.bpf.o layered_runnable 3149 1899 -1250 (-39.70%) 288 151 -137 (-47.57%)
+bpf.bpf.o p2dq_init 2343 1936 -407 (-17.37%) 201 170 -31 (-15.42%)
+bpf.bpf.o refresh_layer_cpumasks 16487 1285 -15202 (-92.21%) 1770 120 -1650 (-93.22%)
+bpf.bpf.o rusty_select_cpu 1937 1386 -551 (-28.45%) 177 125 -52 (-29.38%)
+scx_central.bpf.o central_dispatch 636 600 -36 (-5.66%) 63 59 -4 (-6.35%)
+scx_central.bpf.o central_init 913 632 -281 (-30.78%) 48 39 -9 (-18.75%)
+scx_nest.bpf.o nest_init 636 601 -35 (-5.50%) 60 58 -2 (-3.33%)
+scx_pair.bpf.o pair_dispatch 1000001 1914 -998087 (-99.81%) 58169 142 -58027 (-99.76%)
+scx_qmap.bpf.o qmap_dispatch 2393 2187 -206 (-8.61%) 196 174 -22 (-11.22%)
+scx_qmap.bpf.o qmap_init 16367 22777 +6410 (+39.16%) 603 768 +165 (+27.36%)
+
+'layered_init' and 'pair_dispatch' hit 1M on master, but are verified
+ok with this patch.
+
+Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
+Link: https://lore.kernel.org/r/20250215110411.3236773-4-eddyz87@gmail.com
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/verifier.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index e2801472c0ae4..68715b18df5e2 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -17830,12 +17830,16 @@ static void clean_verifier_state(struct bpf_verifier_env *env,
+ static void clean_live_states(struct bpf_verifier_env *env, int insn,
+ struct bpf_verifier_state *cur)
+ {
++ struct bpf_verifier_state *loop_entry;
+ struct bpf_verifier_state_list *sl;
+
+ sl = *explored_state(env, insn);
+ while (sl) {
+ if (sl->state.branches)
+ goto next;
++ loop_entry = get_loop_entry(&sl->state);
++ if (loop_entry && loop_entry->branches)
++ goto next;
+ if (sl->state.insn_idx != insn ||
+ !same_callsites(&sl->state, cur))
+ goto next;
+--
+2.39.5
+
--- /dev/null
+From 8b9554d18434ea5039f2e447372901c3ce096823 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 24 Apr 2025 11:32:51 -0400
+Subject: bpf: fix possible endless loop in BPF map iteration
+
+From: Brandon Kammerdiener <brandon.kammerdiener@intel.com>
+
+[ Upstream commit 75673fda0c557ae26078177dd14d4857afbf128d ]
+
+The _safe variant used here gets the next element before running the callback,
+avoiding the endless loop condition.
+
+Signed-off-by: Brandon Kammerdiener <brandon.kammerdiener@intel.com>
+Link: https://lore.kernel.org/r/20250424153246.141677-2-brandon.kammerdiener@intel.com
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Acked-by: Hou Tao <houtao1@huawei.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/hashtab.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c
+index c308300fc72f6..c620ffb2b6629 100644
+--- a/kernel/bpf/hashtab.c
++++ b/kernel/bpf/hashtab.c
+@@ -2224,7 +2224,7 @@ static long bpf_for_each_hash_elem(struct bpf_map *map, bpf_callback_t callback_
+ b = &htab->buckets[i];
+ rcu_read_lock();
+ head = &b->head;
+- hlist_nulls_for_each_entry_rcu(elem, n, head, hash_node) {
++ hlist_nulls_for_each_entry_safe(elem, n, head, hash_node) {
+ key = elem->key;
+ if (is_percpu) {
+ /* current cpu value for percpu map */
+--
+2.39.5
+
--- /dev/null
+From 475cfc2665dfdafcc8a384965eb8467cdd9af06f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 17 Feb 2025 11:06:36 -0800
+Subject: bpf: Make every prog keep a copy of ctx_arg_info
+
+From: Amery Hung <ameryhung@gmail.com>
+
+[ Upstream commit 432051806f614ca512da401b80257b95b2a2241e ]
+
+Currently, ctx_arg_info is read-only in the view of the verifier since
+it is shared among programs of the same attach type. Make each program
+have their own copy of ctx_arg_info so that we can use it to store
+program specific information.
+
+In the next patch where we support acquiring a referenced kptr through a
+struct_ops argument tagged with "__ref", ctx_arg_info->ref_obj_id will
+be used to store the unique reference object id of the argument. This
+avoids creating a requirement in the verifier that "__ref" tagged
+arguments must be the first set of references acquired [0].
+
+[0] https://lore.kernel.org/bpf/20241220195619.2022866-2-amery.hung@gmail.com/
+
+Signed-off-by: Amery Hung <ameryhung@gmail.com>
+Acked-by: Eduard Zingerman <eddyz87@gmail.com>
+Acked-by: Martin KaFai Lau <martin.lau@kernel.org>
+Link: https://lore.kernel.org/r/20250217190640.1748177-2-ameryhung@gmail.com
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/bpf.h | 7 +++++--
+ kernel/bpf/bpf_iter.c | 13 ++++++-------
+ kernel/bpf/syscall.c | 1 +
+ kernel/bpf/verifier.c | 22 ++++++++++++----------
+ 4 files changed, 24 insertions(+), 19 deletions(-)
+
+diff --git a/include/linux/bpf.h b/include/linux/bpf.h
+index f3f50e29d6392..f4df39e8c7357 100644
+--- a/include/linux/bpf.h
++++ b/include/linux/bpf.h
+@@ -1507,7 +1507,7 @@ struct bpf_prog_aux {
+ u32 max_rdonly_access;
+ u32 max_rdwr_access;
+ struct btf *attach_btf;
+- const struct bpf_ctx_arg_aux *ctx_arg_info;
++ struct bpf_ctx_arg_aux *ctx_arg_info;
+ void __percpu *priv_stack_ptr;
+ struct mutex dst_mutex; /* protects dst_* pointers below, *after* prog becomes visible */
+ struct bpf_prog *dst_prog;
+@@ -1945,6 +1945,9 @@ static inline void bpf_struct_ops_desc_release(struct bpf_struct_ops_desc *st_op
+
+ #endif
+
++int bpf_prog_ctx_arg_info_init(struct bpf_prog *prog,
++ const struct bpf_ctx_arg_aux *info, u32 cnt);
++
+ #if defined(CONFIG_CGROUP_BPF) && defined(CONFIG_BPF_LSM)
+ int bpf_trampoline_link_cgroup_shim(struct bpf_prog *prog,
+ int cgroup_atype);
+@@ -2546,7 +2549,7 @@ struct bpf_iter__bpf_map_elem {
+
+ int bpf_iter_reg_target(const struct bpf_iter_reg *reg_info);
+ void bpf_iter_unreg_target(const struct bpf_iter_reg *reg_info);
+-bool bpf_iter_prog_supported(struct bpf_prog *prog);
++int bpf_iter_prog_supported(struct bpf_prog *prog);
+ const struct bpf_func_proto *
+ bpf_iter_get_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog);
+ int bpf_iter_link_attach(const union bpf_attr *attr, bpfptr_t uattr, struct bpf_prog *prog);
+diff --git a/kernel/bpf/bpf_iter.c b/kernel/bpf/bpf_iter.c
+index 106735145948b..380e9a7cac75d 100644
+--- a/kernel/bpf/bpf_iter.c
++++ b/kernel/bpf/bpf_iter.c
+@@ -335,7 +335,7 @@ static void cache_btf_id(struct bpf_iter_target_info *tinfo,
+ tinfo->btf_id = prog->aux->attach_btf_id;
+ }
+
+-bool bpf_iter_prog_supported(struct bpf_prog *prog)
++int bpf_iter_prog_supported(struct bpf_prog *prog)
+ {
+ const char *attach_fname = prog->aux->attach_func_name;
+ struct bpf_iter_target_info *tinfo = NULL, *iter;
+@@ -344,7 +344,7 @@ bool bpf_iter_prog_supported(struct bpf_prog *prog)
+ int prefix_len = strlen(prefix);
+
+ if (strncmp(attach_fname, prefix, prefix_len))
+- return false;
++ return -EINVAL;
+
+ mutex_lock(&targets_mutex);
+ list_for_each_entry(iter, &targets, list) {
+@@ -360,12 +360,11 @@ bool bpf_iter_prog_supported(struct bpf_prog *prog)
+ }
+ mutex_unlock(&targets_mutex);
+
+- if (tinfo) {
+- prog->aux->ctx_arg_info_size = tinfo->reg_info->ctx_arg_info_size;
+- prog->aux->ctx_arg_info = tinfo->reg_info->ctx_arg_info;
+- }
++ if (!tinfo)
++ return -EINVAL;
+
+- return tinfo != NULL;
++ return bpf_prog_ctx_arg_info_init(prog, tinfo->reg_info->ctx_arg_info,
++ tinfo->reg_info->ctx_arg_info_size);
+ }
+
+ const struct bpf_func_proto *
+diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
+index 8c42c094f0d1e..32a8d5fd98612 100644
+--- a/kernel/bpf/syscall.c
++++ b/kernel/bpf/syscall.c
+@@ -2314,6 +2314,7 @@ static void __bpf_prog_put_noref(struct bpf_prog *prog, bool deferred)
+ kvfree(prog->aux->jited_linfo);
+ kvfree(prog->aux->linfo);
+ kfree(prog->aux->kfunc_tab);
++ kfree(prog->aux->ctx_arg_info);
+ if (prog->aux->attach_btf)
+ btf_put(prog->aux->attach_btf);
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index 0752e8e556389..4392436ba7511 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -22429,6 +22429,15 @@ static void print_verification_stats(struct bpf_verifier_env *env)
+ env->peak_states, env->longest_mark_read_walk);
+ }
+
++int bpf_prog_ctx_arg_info_init(struct bpf_prog *prog,
++ const struct bpf_ctx_arg_aux *info, u32 cnt)
++{
++ prog->aux->ctx_arg_info = kmemdup_array(info, cnt, sizeof(*info), GFP_KERNEL);
++ prog->aux->ctx_arg_info_size = cnt;
++
++ return prog->aux->ctx_arg_info ? 0 : -ENOMEM;
++}
++
+ static int check_struct_ops_btf_id(struct bpf_verifier_env *env)
+ {
+ const struct btf_type *t, *func_proto;
+@@ -22509,17 +22518,12 @@ static int check_struct_ops_btf_id(struct bpf_verifier_env *env)
+ return -EACCES;
+ }
+
+- /* btf_ctx_access() used this to provide argument type info */
+- prog->aux->ctx_arg_info =
+- st_ops_desc->arg_info[member_idx].info;
+- prog->aux->ctx_arg_info_size =
+- st_ops_desc->arg_info[member_idx].cnt;
+-
+ prog->aux->attach_func_proto = func_proto;
+ prog->aux->attach_func_name = mname;
+ env->ops = st_ops->verifier_ops;
+
+- return 0;
++ return bpf_prog_ctx_arg_info_init(prog, st_ops_desc->arg_info[member_idx].info,
++ st_ops_desc->arg_info[member_idx].cnt);
+ }
+ #define SECURITY_PREFIX "security_"
+
+@@ -22996,9 +23000,7 @@ static int check_attach_btf_id(struct bpf_verifier_env *env)
+ prog->aux->attach_btf_trace = true;
+ return 0;
+ } else if (prog->expected_attach_type == BPF_TRACE_ITER) {
+- if (!bpf_iter_prog_supported(prog))
+- return -EINVAL;
+- return 0;
++ return bpf_iter_prog_supported(prog);
+ }
+
+ if (prog->type == BPF_PROG_TYPE_LSM) {
+--
+2.39.5
+
--- /dev/null
+From bde15bbd09f5c71ce5cd34e322dc50311ffefa42 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 20 Feb 2025 15:29:31 +0800
+Subject: bpf: Prevent unsafe access to the sock fields in the BPF timestamping
+ callback
+
+From: Jason Xing <kerneljasonxing@gmail.com>
+
+[ Upstream commit fd93eaffb3f977b23bc0a48d4c8616e654fcf133 ]
+
+The subsequent patch will implement BPF TX timestamping. It will
+call the sockops BPF program without holding the sock lock.
+
+This breaks the current assumption that all sock ops programs will
+hold the sock lock. The sock's fields of the uapi's bpf_sock_ops
+requires this assumption.
+
+To address this, a new "u8 is_locked_tcp_sock;" field is added. This
+patch sets it in the current sock_ops callbacks. The "is_fullsock"
+test is then replaced by the "is_locked_tcp_sock" test during
+sock_ops_convert_ctx_access().
+
+The new TX timestamping callbacks added in the subsequent patch will
+not have this set. This will prevent unsafe access from the new
+timestamping callbacks.
+
+Potentially, we could allow read-only access. However, this would
+require identifying which callback is read-safe-only and also requires
+additional BPF instruction rewrites in the covert_ctx. Since the BPF
+program can always read everything from a socket (e.g., by using
+bpf_core_cast), this patch keeps it simple and disables all read
+and write access to any socket fields through the bpf_sock_ops
+UAPI from the new TX timestamping callback.
+
+Moreover, note that some of the fields in bpf_sock_ops are specific
+to tcp_sock, and sock_ops currently only supports tcp_sock. In
+the future, UDP timestamping will be added, which will also break
+this assumption. The same idea used in this patch will be reused.
+Considering that the current sock_ops only supports tcp_sock, the
+variable is named is_locked_"tcp"_sock.
+
+Signed-off-by: Jason Xing <kerneljasonxing@gmail.com>
+Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
+Link: https://patch.msgid.link/20250220072940.99994-4-kerneljasonxing@gmail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/filter.h | 1 +
+ include/net/tcp.h | 1 +
+ net/core/filter.c | 8 ++++----
+ net/ipv4/tcp_input.c | 2 ++
+ net/ipv4/tcp_output.c | 2 ++
+ 5 files changed, 10 insertions(+), 4 deletions(-)
+
+diff --git a/include/linux/filter.h b/include/linux/filter.h
+index a3ea462815957..d36d5d5180b11 100644
+--- a/include/linux/filter.h
++++ b/include/linux/filter.h
+@@ -1508,6 +1508,7 @@ struct bpf_sock_ops_kern {
+ void *skb_data_end;
+ u8 op;
+ u8 is_fullsock;
++ u8 is_locked_tcp_sock;
+ u8 remaining_opt_len;
+ u64 temp; /* temp and everything after is not
+ * initialized to 0 before calling
+diff --git a/include/net/tcp.h b/include/net/tcp.h
+index 2d08473a6dc00..33c50ea976c88 100644
+--- a/include/net/tcp.h
++++ b/include/net/tcp.h
+@@ -2671,6 +2671,7 @@ static inline int tcp_call_bpf(struct sock *sk, int op, u32 nargs, u32 *args)
+ memset(&sock_ops, 0, offsetof(struct bpf_sock_ops_kern, temp));
+ if (sk_fullsock(sk)) {
+ sock_ops.is_fullsock = 1;
++ sock_ops.is_locked_tcp_sock = 1;
+ sock_owned_by_me(sk);
+ }
+
+diff --git a/net/core/filter.c b/net/core/filter.c
+index 6c8fbc96b14a3..7e6ad73df6b17 100644
+--- a/net/core/filter.c
++++ b/net/core/filter.c
+@@ -10367,10 +10367,10 @@ static u32 sock_ops_convert_ctx_access(enum bpf_access_type type,
+ } \
+ *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF( \
+ struct bpf_sock_ops_kern, \
+- is_fullsock), \
++ is_locked_tcp_sock), \
+ fullsock_reg, si->src_reg, \
+ offsetof(struct bpf_sock_ops_kern, \
+- is_fullsock)); \
++ is_locked_tcp_sock)); \
+ *insn++ = BPF_JMP_IMM(BPF_JEQ, fullsock_reg, 0, jmp); \
+ if (si->dst_reg == si->src_reg) \
+ *insn++ = BPF_LDX_MEM(BPF_DW, reg, si->src_reg, \
+@@ -10455,10 +10455,10 @@ static u32 sock_ops_convert_ctx_access(enum bpf_access_type type,
+ temp)); \
+ *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF( \
+ struct bpf_sock_ops_kern, \
+- is_fullsock), \
++ is_locked_tcp_sock), \
+ reg, si->dst_reg, \
+ offsetof(struct bpf_sock_ops_kern, \
+- is_fullsock)); \
++ is_locked_tcp_sock)); \
+ *insn++ = BPF_JMP_IMM(BPF_JEQ, reg, 0, 2); \
+ *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF( \
+ struct bpf_sock_ops_kern, sk),\
+diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
+index 1b09b4d76c296..d1ed4ac74e1d0 100644
+--- a/net/ipv4/tcp_input.c
++++ b/net/ipv4/tcp_input.c
+@@ -169,6 +169,7 @@ static void bpf_skops_parse_hdr(struct sock *sk, struct sk_buff *skb)
+ memset(&sock_ops, 0, offsetof(struct bpf_sock_ops_kern, temp));
+ sock_ops.op = BPF_SOCK_OPS_PARSE_HDR_OPT_CB;
+ sock_ops.is_fullsock = 1;
++ sock_ops.is_locked_tcp_sock = 1;
+ sock_ops.sk = sk;
+ bpf_skops_init_skb(&sock_ops, skb, tcp_hdrlen(skb));
+
+@@ -185,6 +186,7 @@ static void bpf_skops_established(struct sock *sk, int bpf_op,
+ memset(&sock_ops, 0, offsetof(struct bpf_sock_ops_kern, temp));
+ sock_ops.op = bpf_op;
+ sock_ops.is_fullsock = 1;
++ sock_ops.is_locked_tcp_sock = 1;
+ sock_ops.sk = sk;
+ /* sk with TCP_REPAIR_ON does not have skb in tcp_finish_connect */
+ if (skb)
+diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
+index 6031d7f7f5198..2398b0fc62225 100644
+--- a/net/ipv4/tcp_output.c
++++ b/net/ipv4/tcp_output.c
+@@ -525,6 +525,7 @@ static void bpf_skops_hdr_opt_len(struct sock *sk, struct sk_buff *skb,
+ sock_owned_by_me(sk);
+
+ sock_ops.is_fullsock = 1;
++ sock_ops.is_locked_tcp_sock = 1;
+ sock_ops.sk = sk;
+ }
+
+@@ -570,6 +571,7 @@ static void bpf_skops_write_hdr_opt(struct sock *sk, struct sk_buff *skb,
+ sock_owned_by_me(sk);
+
+ sock_ops.is_fullsock = 1;
++ sock_ops.is_locked_tcp_sock = 1;
+ sock_ops.sk = sk;
+ }
+
+--
+2.39.5
+
--- /dev/null
+From 0257fa043584e21c1ab5ae765e34cb302eb402dc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 17 Mar 2025 17:40:37 +0000
+Subject: bpf: Return prog btf_id without capable check
+
+From: Mykyta Yatsenko <yatsenko@meta.com>
+
+[ Upstream commit 07651ccda9ff10a8ca427670cdd06ce2c8e4269c ]
+
+Return prog's btf_id from bpf_prog_get_info_by_fd regardless of capable
+check. This patch enables scenario, when freplace program, running
+from user namespace, requires to query target prog's btf.
+
+Signed-off-by: Mykyta Yatsenko <yatsenko@meta.com>
+Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
+Acked-by: Yonghong Song <yonghong.song@linux.dev>
+Link: https://lore.kernel.org/bpf/20250317174039.161275-3-mykyta.yatsenko5@gmail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/syscall.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
+index 1c2caae0d8946..87f886ed33bc3 100644
+--- a/kernel/bpf/syscall.c
++++ b/kernel/bpf/syscall.c
+@@ -4733,6 +4733,8 @@ static int bpf_prog_get_info_by_fd(struct file *file,
+ info.recursion_misses = stats.misses;
+
+ info.verified_insns = prog->aux->verified_insns;
++ if (prog->aux->btf)
++ info.btf_id = btf_obj_id(prog->aux->btf);
+
+ if (!bpf_capable()) {
+ info.jited_prog_len = 0;
+@@ -4879,8 +4881,6 @@ static int bpf_prog_get_info_by_fd(struct file *file,
+ }
+ }
+
+- if (prog->aux->btf)
+- info.btf_id = btf_obj_id(prog->aux->btf);
+ info.attach_btf_id = prog->aux->attach_btf_id;
+ if (attach_btf)
+ info.attach_btf_obj_id = btf_obj_id(attach_btf);
+--
+2.39.5
+
--- /dev/null
+From 087c9b131768c055ac56f7e8c971dbd5ac7cdf3b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 25 Feb 2025 15:35:44 -0800
+Subject: bpf: Search and add kfuncs in struct_ops prologue and epilogue
+
+From: Amery Hung <amery.hung@bytedance.com>
+
+[ Upstream commit d519594ee2445d7cd1ad51f4db4cee58f8213400 ]
+
+Currently, add_kfunc_call() is only invoked once before the main
+verification loop. Therefore, the verifier could not find the
+bpf_kfunc_btf_tab of a new kfunc call which is not seen in user defined
+struct_ops operators but introduced in gen_prologue or gen_epilogue
+during do_misc_fixup(). Fix this by searching kfuncs in the patching
+instruction buffer and add them to prog->aux->kfunc_tab.
+
+Signed-off-by: Amery Hung <amery.hung@bytedance.com>
+Acked-by: Eduard Zingerman <eddyz87@gmail.com>
+Acked-by: Martin KaFai Lau <martin.lau@kernel.org>
+Link: https://lore.kernel.org/r/20250225233545.285481-1-ameryhung@gmail.com
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/verifier.c | 25 ++++++++++++++++++++++++-
+ 1 file changed, 24 insertions(+), 1 deletion(-)
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index db95b76f5c139..e2801472c0ae4 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -3206,6 +3206,21 @@ bpf_jit_find_kfunc_model(const struct bpf_prog *prog,
+ return res ? &res->func_model : NULL;
+ }
+
++static int add_kfunc_in_insns(struct bpf_verifier_env *env,
++ struct bpf_insn *insn, int cnt)
++{
++ int i, ret;
++
++ for (i = 0; i < cnt; i++, insn++) {
++ if (bpf_pseudo_kfunc_call(insn)) {
++ ret = add_kfunc_call(env, insn->imm, insn->off);
++ if (ret < 0)
++ return ret;
++ }
++ }
++ return 0;
++}
++
+ static int add_subprog_and_kfunc(struct bpf_verifier_env *env)
+ {
+ struct bpf_subprog_info *subprog = env->subprog_info;
+@@ -20334,7 +20349,7 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
+ {
+ struct bpf_subprog_info *subprogs = env->subprog_info;
+ const struct bpf_verifier_ops *ops = env->ops;
+- int i, cnt, size, ctx_field_size, delta = 0, epilogue_cnt = 0;
++ int i, cnt, size, ctx_field_size, ret, delta = 0, epilogue_cnt = 0;
+ const int insn_cnt = env->prog->len;
+ struct bpf_insn *epilogue_buf = env->epilogue_buf;
+ struct bpf_insn *insn_buf = env->insn_buf;
+@@ -20363,6 +20378,10 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
+ return -ENOMEM;
+ env->prog = new_prog;
+ delta += cnt - 1;
++
++ ret = add_kfunc_in_insns(env, epilogue_buf, epilogue_cnt - 1);
++ if (ret < 0)
++ return ret;
+ }
+ }
+
+@@ -20383,6 +20402,10 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
+
+ env->prog = new_prog;
+ delta += cnt - 1;
++
++ ret = add_kfunc_in_insns(env, insn_buf, cnt - 1);
++ if (ret < 0)
++ return ret;
+ }
+ }
+
+--
+2.39.5
+
--- /dev/null
+From 79f498a51c216ddd2ef0ce65ccf6c71686fc0fef Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jan 2025 14:27:19 -0800
+Subject: bpf: Use kallsyms to find the function name of a struct_ops's stub
+ function
+
+From: Martin KaFai Lau <martin.lau@kernel.org>
+
+[ Upstream commit 12fdd29d5d71d2987a1aec434b704d850a4d7fcb ]
+
+In commit 1611603537a4 ("bpf: Create argument information for nullable arguments."),
+it introduced a "__nullable" tagging at the argument name of a
+stub function. Some background on the commit:
+it requires to tag the stub function instead of directly tagging
+the "ops" of a struct. This is because the btf func_proto of the "ops"
+does not have the argument name and the "__nullable" is tagged at
+the argument name.
+
+To find the stub function of a "ops", it currently relies on a naming
+convention on the stub function "st_ops__ops_name".
+e.g. tcp_congestion_ops__ssthresh. However, the new kernel
+sub system implementing bpf_struct_ops have missed this and
+have been surprised that the "__nullable" and the to-be-landed
+"__ref" tagging was not effective.
+
+One option would be to give a warning whenever the stub function does
+not follow the naming convention, regardless if it requires arg tagging
+or not.
+
+Instead, this patch uses the kallsyms_lookup approach and removes
+the requirement on the naming convention. The st_ops->cfi_stubs has
+all the stub function kernel addresses. kallsyms_lookup() is used to
+lookup the function name. With the function name, BTF can be used to
+find the BTF func_proto. The existing "__nullable" arg name searching
+logic will then fall through.
+
+One notable change is,
+if it failed in kallsyms_lookup or it failed in looking up the stub
+function name from the BTF, the bpf_struct_ops registration will fail.
+This is different from the previous behavior that it silently ignored
+the "st_ops__ops_name" function not found error.
+
+The "tcp_congestion_ops", "sched_ext_ops", and "hid_bpf_ops" can still be
+registered successfully after this patch. There is struct_ops_maybe_null
+selftest to cover the "__nullable" tagging.
+
+Other minor changes:
+1. Removed the "%s__%s" format from the pr_warn because the naming
+ convention is removed.
+2. The existing bpf_struct_ops_supported() is also moved earlier
+ because prepare_arg_info needs to use it to decide if the
+ stub function is NULL before calling the prepare_arg_info.
+
+Cc: Tejun Heo <tj@kernel.org>
+Cc: Benjamin Tissoires <bentiss@kernel.org>
+Cc: Yonghong Song <yonghong.song@linux.dev>
+Cc: Amery Hung <ameryhung@gmail.com>
+Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
+Reviewed-by: Amery Hung <ameryhung@gmail.com>
+Link: https://lore.kernel.org/r/20250127222719.2544255-1-martin.lau@linux.dev
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/bpf_struct_ops.c | 98 +++++++++++++++++--------------------
+ 1 file changed, 44 insertions(+), 54 deletions(-)
+
+diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c
+index 040fb1cd840b6..9b7f3b9c52622 100644
+--- a/kernel/bpf/bpf_struct_ops.c
++++ b/kernel/bpf/bpf_struct_ops.c
+@@ -146,39 +146,6 @@ void bpf_struct_ops_image_free(void *image)
+ }
+
+ #define MAYBE_NULL_SUFFIX "__nullable"
+-#define MAX_STUB_NAME 128
+-
+-/* Return the type info of a stub function, if it exists.
+- *
+- * The name of a stub function is made up of the name of the struct_ops and
+- * the name of the function pointer member, separated by "__". For example,
+- * if the struct_ops type is named "foo_ops" and the function pointer
+- * member is named "bar", the stub function name would be "foo_ops__bar".
+- */
+-static const struct btf_type *
+-find_stub_func_proto(const struct btf *btf, const char *st_op_name,
+- const char *member_name)
+-{
+- char stub_func_name[MAX_STUB_NAME];
+- const struct btf_type *func_type;
+- s32 btf_id;
+- int cp;
+-
+- cp = snprintf(stub_func_name, MAX_STUB_NAME, "%s__%s",
+- st_op_name, member_name);
+- if (cp >= MAX_STUB_NAME) {
+- pr_warn("Stub function name too long\n");
+- return NULL;
+- }
+- btf_id = btf_find_by_name_kind(btf, stub_func_name, BTF_KIND_FUNC);
+- if (btf_id < 0)
+- return NULL;
+- func_type = btf_type_by_id(btf, btf_id);
+- if (!func_type)
+- return NULL;
+-
+- return btf_type_by_id(btf, func_type->type); /* FUNC_PROTO */
+-}
+
+ /* Prepare argument info for every nullable argument of a member of a
+ * struct_ops type.
+@@ -203,27 +170,42 @@ find_stub_func_proto(const struct btf *btf, const char *st_op_name,
+ static int prepare_arg_info(struct btf *btf,
+ const char *st_ops_name,
+ const char *member_name,
+- const struct btf_type *func_proto,
++ const struct btf_type *func_proto, void *stub_func_addr,
+ struct bpf_struct_ops_arg_info *arg_info)
+ {
+ const struct btf_type *stub_func_proto, *pointed_type;
+ const struct btf_param *stub_args, *args;
+ struct bpf_ctx_arg_aux *info, *info_buf;
+ u32 nargs, arg_no, info_cnt = 0;
++ char ksym[KSYM_SYMBOL_LEN];
++ const char *stub_fname;
++ s32 stub_func_id;
+ u32 arg_btf_id;
+ int offset;
+
+- stub_func_proto = find_stub_func_proto(btf, st_ops_name, member_name);
+- if (!stub_func_proto)
+- return 0;
++ stub_fname = kallsyms_lookup((unsigned long)stub_func_addr, NULL, NULL, NULL, ksym);
++ if (!stub_fname) {
++ pr_warn("Cannot find the stub function name for the %s in struct %s\n",
++ member_name, st_ops_name);
++ return -ENOENT;
++ }
++
++ stub_func_id = btf_find_by_name_kind(btf, stub_fname, BTF_KIND_FUNC);
++ if (stub_func_id < 0) {
++ pr_warn("Cannot find the stub function %s in btf\n", stub_fname);
++ return -ENOENT;
++ }
++
++ stub_func_proto = btf_type_by_id(btf, stub_func_id);
++ stub_func_proto = btf_type_by_id(btf, stub_func_proto->type);
+
+ /* Check if the number of arguments of the stub function is the same
+ * as the number of arguments of the function pointer.
+ */
+ nargs = btf_type_vlen(func_proto);
+ if (nargs != btf_type_vlen(stub_func_proto)) {
+- pr_warn("the number of arguments of the stub function %s__%s does not match the number of arguments of the member %s of struct %s\n",
+- st_ops_name, member_name, member_name, st_ops_name);
++ pr_warn("the number of arguments of the stub function %s does not match the number of arguments of the member %s of struct %s\n",
++ stub_fname, member_name, st_ops_name);
+ return -EINVAL;
+ }
+
+@@ -253,21 +235,21 @@ static int prepare_arg_info(struct btf *btf,
+ &arg_btf_id);
+ if (!pointed_type ||
+ !btf_type_is_struct(pointed_type)) {
+- pr_warn("stub function %s__%s has %s tagging to an unsupported type\n",
+- st_ops_name, member_name, MAYBE_NULL_SUFFIX);
++ pr_warn("stub function %s has %s tagging to an unsupported type\n",
++ stub_fname, MAYBE_NULL_SUFFIX);
+ goto err_out;
+ }
+
+ offset = btf_ctx_arg_offset(btf, func_proto, arg_no);
+ if (offset < 0) {
+- pr_warn("stub function %s__%s has an invalid trampoline ctx offset for arg#%u\n",
+- st_ops_name, member_name, arg_no);
++ pr_warn("stub function %s has an invalid trampoline ctx offset for arg#%u\n",
++ stub_fname, arg_no);
+ goto err_out;
+ }
+
+ if (args[arg_no].type != stub_args[arg_no].type) {
+- pr_warn("arg#%u type in stub function %s__%s does not match with its original func_proto\n",
+- arg_no, st_ops_name, member_name);
++ pr_warn("arg#%u type in stub function %s does not match with its original func_proto\n",
++ arg_no, stub_fname);
+ goto err_out;
+ }
+
+@@ -324,6 +306,13 @@ static bool is_module_member(const struct btf *btf, u32 id)
+ return !strcmp(btf_name_by_offset(btf, t->name_off), "module");
+ }
+
++int bpf_struct_ops_supported(const struct bpf_struct_ops *st_ops, u32 moff)
++{
++ void *func_ptr = *(void **)(st_ops->cfi_stubs + moff);
++
++ return func_ptr ? 0 : -ENOTSUPP;
++}
++
+ int bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc,
+ struct btf *btf,
+ struct bpf_verifier_log *log)
+@@ -387,7 +376,10 @@ int bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc,
+
+ for_each_member(i, t, member) {
+ const struct btf_type *func_proto;
++ void **stub_func_addr;
++ u32 moff;
+
++ moff = __btf_member_bit_offset(t, member) / 8;
+ mname = btf_name_by_offset(btf, member->name_off);
+ if (!*mname) {
+ pr_warn("anon member in struct %s is not supported\n",
+@@ -413,7 +405,11 @@ int bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc,
+ func_proto = btf_type_resolve_func_ptr(btf,
+ member->type,
+ NULL);
+- if (!func_proto)
++
++ /* The member is not a function pointer or
++ * the function pointer is not supported.
++ */
++ if (!func_proto || bpf_struct_ops_supported(st_ops, moff))
+ continue;
+
+ if (btf_distill_func_proto(log, btf,
+@@ -425,8 +421,9 @@ int bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc,
+ goto errout;
+ }
+
++ stub_func_addr = *(void **)(st_ops->cfi_stubs + moff);
+ err = prepare_arg_info(btf, st_ops->name, mname,
+- func_proto,
++ func_proto, stub_func_addr,
+ arg_info + i);
+ if (err)
+ goto errout;
+@@ -1152,13 +1149,6 @@ void bpf_struct_ops_put(const void *kdata)
+ bpf_map_put(&st_map->map);
+ }
+
+-int bpf_struct_ops_supported(const struct bpf_struct_ops *st_ops, u32 moff)
+-{
+- void *func_ptr = *(void **)(st_ops->cfi_stubs + moff);
+-
+- return func_ptr ? 0 : -ENOTSUPP;
+-}
+-
+ static bool bpf_struct_ops_valid_to_reg(struct bpf_map *map)
+ {
+ struct bpf_struct_ops_map *st_map = (struct bpf_struct_ops_map *)map;
+--
+2.39.5
+
--- /dev/null
+From a81a41498bb460b6c0a48b0fc1bf7f3f15480a16 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jan 2025 08:18:57 +0100
+Subject: bpftool: Fix readlink usage in get_fd_type
+
+From: Viktor Malik <vmalik@redhat.com>
+
+[ Upstream commit 0053f7d39d491b6138d7c526876d13885cbb65f1 ]
+
+The `readlink(path, buf, sizeof(buf))` call reads at most sizeof(buf)
+bytes and *does not* append null-terminator to buf. With respect to
+that, fix two pieces in get_fd_type:
+
+1. Change the truncation check to contain sizeof(buf) rather than
+ sizeof(path).
+2. Append null-terminator to buf.
+
+Reported by Coverity.
+
+Signed-off-by: Viktor Malik <vmalik@redhat.com>
+Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
+Reviewed-by: Quentin Monnet <qmo@kernel.org>
+Link: https://lore.kernel.org/bpf/20250129071857.75182-1-vmalik@redhat.com
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/bpf/bpftool/common.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/tools/bpf/bpftool/common.c b/tools/bpf/bpftool/common.c
+index b921231d602e4..ecfa790adc13f 100644
+--- a/tools/bpf/bpftool/common.c
++++ b/tools/bpf/bpftool/common.c
+@@ -461,10 +461,11 @@ int get_fd_type(int fd)
+ p_err("can't read link type: %s", strerror(errno));
+ return -1;
+ }
+- if (n == sizeof(path)) {
++ if (n == sizeof(buf)) {
+ p_err("can't read link type: path too long!");
+ return -1;
+ }
++ buf[n] = '\0';
+
+ if (strstr(buf, "bpf-map"))
+ return BPF_OBJ_MAP;
+--
+2.39.5
+
--- /dev/null
+From b5a99ae00ce91508b8084a80b3013f463332378f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Mar 2025 19:28:09 +0800
+Subject: bpftool: Using the right format specifiers
+
+From: Jiayuan Chen <jiayuan.chen@linux.dev>
+
+[ Upstream commit 3775be3417cc3243b0df0492bd308559dcf0560b ]
+
+Fixed some formatting specifiers errors, such as using %d for int and %u
+for unsigned int, as well as other byte-length types.
+
+Perform type cast using the type derived from the data type itself, for
+example, if it's originally an int, it will be cast to unsigned int if
+forced to unsigned.
+
+Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
+Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
+Link: https://lore.kernel.org/bpf/20250311112809.81901-3-jiayuan.chen@linux.dev
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/disasm.c | 4 ++--
+ tools/bpf/bpftool/btf.c | 14 +++++++-------
+ tools/bpf/bpftool/btf_dumper.c | 2 +-
+ tools/bpf/bpftool/cgroup.c | 2 +-
+ tools/bpf/bpftool/common.c | 4 ++--
+ tools/bpf/bpftool/jit_disasm.c | 3 ++-
+ tools/bpf/bpftool/map_perf_ring.c | 6 +++---
+ tools/bpf/bpftool/net.c | 4 ++--
+ tools/bpf/bpftool/netlink_dumper.c | 6 +++---
+ tools/bpf/bpftool/prog.c | 12 ++++++------
+ tools/bpf/bpftool/tracelog.c | 2 +-
+ tools/bpf/bpftool/xlated_dumper.c | 6 +++---
+ 12 files changed, 33 insertions(+), 32 deletions(-)
+
+diff --git a/kernel/bpf/disasm.c b/kernel/bpf/disasm.c
+index 309c4aa1b026a..c235acbd65095 100644
+--- a/kernel/bpf/disasm.c
++++ b/kernel/bpf/disasm.c
+@@ -202,7 +202,7 @@ void print_bpf_insn(const struct bpf_insn_cbs *cbs,
+ insn->dst_reg, class == BPF_ALU ? 'w' : 'r',
+ insn->dst_reg);
+ } else if (is_addr_space_cast(insn)) {
+- verbose(cbs->private_data, "(%02x) r%d = addr_space_cast(r%d, %d, %d)\n",
++ verbose(cbs->private_data, "(%02x) r%d = addr_space_cast(r%d, %u, %u)\n",
+ insn->code, insn->dst_reg,
+ insn->src_reg, ((u32)insn->imm) >> 16, (u16)insn->imm);
+ } else if (is_mov_percpu_addr(insn)) {
+@@ -369,7 +369,7 @@ void print_bpf_insn(const struct bpf_insn_cbs *cbs,
+ insn->code, class == BPF_JMP32 ? 'w' : 'r',
+ insn->dst_reg,
+ bpf_jmp_string[BPF_OP(insn->code) >> 4],
+- insn->imm, insn->off);
++ (u32)insn->imm, insn->off);
+ }
+ } else {
+ verbose(cbs->private_data, "(%02x) %s\n",
+diff --git a/tools/bpf/bpftool/btf.c b/tools/bpf/bpftool/btf.c
+index 2636655ac1808..6b14cbfa58aa2 100644
+--- a/tools/bpf/bpftool/btf.c
++++ b/tools/bpf/bpftool/btf.c
+@@ -253,7 +253,7 @@ static int dump_btf_type(const struct btf *btf, __u32 id,
+ if (btf_kflag(t))
+ printf("\n\t'%s' val=%d", name, v->val);
+ else
+- printf("\n\t'%s' val=%u", name, v->val);
++ printf("\n\t'%s' val=%u", name, (__u32)v->val);
+ }
+ }
+ if (json_output)
+@@ -1022,7 +1022,7 @@ static int do_dump(int argc, char **argv)
+ for (i = 0; i < root_type_cnt; i++) {
+ if (root_type_ids[i] == root_id) {
+ err = -EINVAL;
+- p_err("duplicate root_id %d supplied", root_id);
++ p_err("duplicate root_id %u supplied", root_id);
+ goto done;
+ }
+ }
+@@ -1132,7 +1132,7 @@ build_btf_type_table(struct hashmap *tab, enum bpf_obj_type type,
+ break;
+ default:
+ err = -1;
+- p_err("unexpected object type: %d", type);
++ p_err("unexpected object type: %u", type);
+ goto err_free;
+ }
+ if (err) {
+@@ -1155,7 +1155,7 @@ build_btf_type_table(struct hashmap *tab, enum bpf_obj_type type,
+ break;
+ default:
+ err = -1;
+- p_err("unexpected object type: %d", type);
++ p_err("unexpected object type: %u", type);
+ goto err_free;
+ }
+ if (fd < 0) {
+@@ -1188,7 +1188,7 @@ build_btf_type_table(struct hashmap *tab, enum bpf_obj_type type,
+ break;
+ default:
+ err = -1;
+- p_err("unexpected object type: %d", type);
++ p_err("unexpected object type: %u", type);
+ goto err_free;
+ }
+ if (!btf_id)
+@@ -1254,12 +1254,12 @@ show_btf_plain(struct bpf_btf_info *info, int fd,
+
+ n = 0;
+ hashmap__for_each_key_entry(btf_prog_table, entry, info->id) {
+- printf("%s%lu", n++ == 0 ? " prog_ids " : ",", entry->value);
++ printf("%s%lu", n++ == 0 ? " prog_ids " : ",", (unsigned long)entry->value);
+ }
+
+ n = 0;
+ hashmap__for_each_key_entry(btf_map_table, entry, info->id) {
+- printf("%s%lu", n++ == 0 ? " map_ids " : ",", entry->value);
++ printf("%s%lu", n++ == 0 ? " map_ids " : ",", (unsigned long)entry->value);
+ }
+
+ emit_obj_refs_plain(refs_table, info->id, "\n\tpids ");
+diff --git a/tools/bpf/bpftool/btf_dumper.c b/tools/bpf/bpftool/btf_dumper.c
+index 527fe867a8fbd..4e896d8a2416e 100644
+--- a/tools/bpf/bpftool/btf_dumper.c
++++ b/tools/bpf/bpftool/btf_dumper.c
+@@ -653,7 +653,7 @@ static int __btf_dumper_type_only(const struct btf *btf, __u32 type_id,
+ case BTF_KIND_ARRAY:
+ array = (struct btf_array *)(t + 1);
+ BTF_PRINT_TYPE(array->type);
+- BTF_PRINT_ARG("[%d]", array->nelems);
++ BTF_PRINT_ARG("[%u]", array->nelems);
+ break;
+ case BTF_KIND_PTR:
+ BTF_PRINT_TYPE(t->type);
+diff --git a/tools/bpf/bpftool/cgroup.c b/tools/bpf/bpftool/cgroup.c
+index 9af426d432993..93b139bfb9880 100644
+--- a/tools/bpf/bpftool/cgroup.c
++++ b/tools/bpf/bpftool/cgroup.c
+@@ -191,7 +191,7 @@ static int show_bpf_prog(int id, enum bpf_attach_type attach_type,
+ if (attach_btf_name)
+ printf(" %-15s", attach_btf_name);
+ else if (info.attach_btf_id)
+- printf(" attach_btf_obj_id=%d attach_btf_id=%d",
++ printf(" attach_btf_obj_id=%u attach_btf_id=%u",
+ info.attach_btf_obj_id, info.attach_btf_id);
+ printf("\n");
+ }
+diff --git a/tools/bpf/bpftool/common.c b/tools/bpf/bpftool/common.c
+index 9b75639434b81..b921231d602e4 100644
+--- a/tools/bpf/bpftool/common.c
++++ b/tools/bpf/bpftool/common.c
+@@ -713,7 +713,7 @@ ifindex_to_arch(__u32 ifindex, __u64 ns_dev, __u64 ns_ino, const char **opt)
+ int vendor_id;
+
+ if (!ifindex_to_name_ns(ifindex, ns_dev, ns_ino, devname)) {
+- p_err("Can't get net device name for ifindex %d: %s", ifindex,
++ p_err("Can't get net device name for ifindex %u: %s", ifindex,
+ strerror(errno));
+ return NULL;
+ }
+@@ -738,7 +738,7 @@ ifindex_to_arch(__u32 ifindex, __u64 ns_dev, __u64 ns_ino, const char **opt)
+ /* No NFP support in LLVM, we have no valid triple to return. */
+ default:
+ p_err("Can't get arch name for device vendor id 0x%04x",
+- vendor_id);
++ (unsigned int)vendor_id);
+ return NULL;
+ }
+ }
+diff --git a/tools/bpf/bpftool/jit_disasm.c b/tools/bpf/bpftool/jit_disasm.c
+index c032d2c6ab6d5..8895b4e1f6903 100644
+--- a/tools/bpf/bpftool/jit_disasm.c
++++ b/tools/bpf/bpftool/jit_disasm.c
+@@ -343,7 +343,8 @@ int disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,
+ {
+ const struct bpf_line_info *linfo = NULL;
+ unsigned int nr_skip = 0;
+- int count, i, pc = 0;
++ int count, i;
++ unsigned int pc = 0;
+ disasm_ctx_t ctx;
+
+ if (!len)
+diff --git a/tools/bpf/bpftool/map_perf_ring.c b/tools/bpf/bpftool/map_perf_ring.c
+index 21d7d447e1f3b..552b4ca40c27c 100644
+--- a/tools/bpf/bpftool/map_perf_ring.c
++++ b/tools/bpf/bpftool/map_perf_ring.c
+@@ -91,15 +91,15 @@ print_bpf_output(void *private_data, int cpu, struct perf_event_header *event)
+ jsonw_end_object(json_wtr);
+ } else {
+ if (e->header.type == PERF_RECORD_SAMPLE) {
+- printf("== @%lld.%09lld CPU: %d index: %d =====\n",
++ printf("== @%llu.%09llu CPU: %d index: %d =====\n",
+ e->time / 1000000000ULL, e->time % 1000000000ULL,
+ cpu, idx);
+ fprint_hex(stdout, e->data, e->size, " ");
+ printf("\n");
+ } else if (e->header.type == PERF_RECORD_LOST) {
+- printf("lost %lld events\n", lost->lost);
++ printf("lost %llu events\n", lost->lost);
+ } else {
+- printf("unknown event type=%d size=%d\n",
++ printf("unknown event type=%u size=%u\n",
+ e->header.type, e->header.size);
+ }
+ }
+diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c
+index d2242d9f84411..64f958f437b01 100644
+--- a/tools/bpf/bpftool/net.c
++++ b/tools/bpf/bpftool/net.c
+@@ -476,7 +476,7 @@ static void __show_dev_tc_bpf(const struct ip_devname_ifindex *dev,
+ for (i = 0; i < optq.count; i++) {
+ NET_START_OBJECT;
+ NET_DUMP_STR("devname", "%s", dev->devname);
+- NET_DUMP_UINT("ifindex", "(%u)", dev->ifindex);
++ NET_DUMP_UINT("ifindex", "(%u)", (unsigned int)dev->ifindex);
+ NET_DUMP_STR("kind", " %s", attach_loc_strings[loc]);
+ ret = __show_dev_tc_bpf_name(prog_ids[i], prog_name,
+ sizeof(prog_name));
+@@ -831,7 +831,7 @@ static void show_link_netfilter(void)
+ if (err) {
+ if (errno == ENOENT)
+ break;
+- p_err("can't get next link: %s (id %d)", strerror(errno), id);
++ p_err("can't get next link: %s (id %u)", strerror(errno), id);
+ break;
+ }
+
+diff --git a/tools/bpf/bpftool/netlink_dumper.c b/tools/bpf/bpftool/netlink_dumper.c
+index 5f65140b003b2..0a3c7e96c797a 100644
+--- a/tools/bpf/bpftool/netlink_dumper.c
++++ b/tools/bpf/bpftool/netlink_dumper.c
+@@ -45,7 +45,7 @@ static int do_xdp_dump_one(struct nlattr *attr, unsigned int ifindex,
+ NET_START_OBJECT;
+ if (name)
+ NET_DUMP_STR("devname", "%s", name);
+- NET_DUMP_UINT("ifindex", "(%d)", ifindex);
++ NET_DUMP_UINT("ifindex", "(%u)", ifindex);
+
+ if (mode == XDP_ATTACHED_MULTI) {
+ if (json_output) {
+@@ -74,7 +74,7 @@ int do_xdp_dump(struct ifinfomsg *ifinfo, struct nlattr **tb)
+ if (!tb[IFLA_XDP])
+ return 0;
+
+- return do_xdp_dump_one(tb[IFLA_XDP], ifinfo->ifi_index,
++ return do_xdp_dump_one(tb[IFLA_XDP], (unsigned int)ifinfo->ifi_index,
+ libbpf_nla_getattr_str(tb[IFLA_IFNAME]));
+ }
+
+@@ -168,7 +168,7 @@ int do_filter_dump(struct tcmsg *info, struct nlattr **tb, const char *kind,
+ NET_START_OBJECT;
+ if (devname[0] != '\0')
+ NET_DUMP_STR("devname", "%s", devname);
+- NET_DUMP_UINT("ifindex", "(%u)", ifindex);
++ NET_DUMP_UINT("ifindex", "(%u)", (unsigned int)ifindex);
+ NET_DUMP_STR("kind", " %s", kind);
+ ret = do_bpf_filter_dump(tb[TCA_OPTIONS]);
+ NET_END_OBJECT_FINAL;
+diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c
+index 52ffb74ae4e89..f010295350be5 100644
+--- a/tools/bpf/bpftool/prog.c
++++ b/tools/bpf/bpftool/prog.c
+@@ -521,10 +521,10 @@ static void print_prog_header_plain(struct bpf_prog_info *info, int fd)
+ print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino);
+ printf("%s", info->gpl_compatible ? " gpl" : "");
+ if (info->run_time_ns)
+- printf(" run_time_ns %lld run_cnt %lld",
++ printf(" run_time_ns %llu run_cnt %llu",
+ info->run_time_ns, info->run_cnt);
+ if (info->recursion_misses)
+- printf(" recursion_misses %lld", info->recursion_misses);
++ printf(" recursion_misses %llu", info->recursion_misses);
+ printf("\n");
+ }
+
+@@ -569,7 +569,7 @@ static void print_prog_plain(struct bpf_prog_info *info, int fd, bool orphaned)
+ }
+
+ if (info->btf_id)
+- printf("\n\tbtf_id %d", info->btf_id);
++ printf("\n\tbtf_id %u", info->btf_id);
+
+ emit_obj_refs_plain(refs_table, info->id, "\n\tpids ");
+
+@@ -1164,7 +1164,7 @@ static int get_run_data(const char *fname, void **data_ptr, unsigned int *size)
+ }
+ if (nb_read > buf_size - block_size) {
+ if (buf_size == UINT32_MAX) {
+- p_err("data_in/ctx_in is too long (max: %d)",
++ p_err("data_in/ctx_in is too long (max: %u)",
+ UINT32_MAX);
+ goto err_free;
+ }
+@@ -2252,7 +2252,7 @@ static char *profile_target_name(int tgt_fd)
+
+ t = btf__type_by_id(btf, func_info.type_id);
+ if (!t) {
+- p_err("btf %d doesn't have type %d",
++ p_err("btf %u doesn't have type %u",
+ info.btf_id, func_info.type_id);
+ goto out;
+ }
+@@ -2330,7 +2330,7 @@ static int profile_open_perf_events(struct profiler_bpf *obj)
+ continue;
+ for (cpu = 0; cpu < obj->rodata->num_cpu; cpu++) {
+ if (profile_open_perf_event(m, cpu, map_fd)) {
+- p_err("failed to create event %s on cpu %d",
++ p_err("failed to create event %s on cpu %u",
+ metrics[m].name, cpu);
+ return -1;
+ }
+diff --git a/tools/bpf/bpftool/tracelog.c b/tools/bpf/bpftool/tracelog.c
+index bf1f022127972..31d806e3bdaaa 100644
+--- a/tools/bpf/bpftool/tracelog.c
++++ b/tools/bpf/bpftool/tracelog.c
+@@ -78,7 +78,7 @@ static bool get_tracefs_pipe(char *mnt)
+ return false;
+
+ /* Allow room for NULL terminating byte and pipe file name */
+- snprintf(format, sizeof(format), "%%*s %%%zds %%99s %%*s %%*d %%*d\\n",
++ snprintf(format, sizeof(format), "%%*s %%%zus %%99s %%*s %%*d %%*d\\n",
+ PATH_MAX - strlen(pipe_name) - 1);
+ while (fscanf(fp, format, mnt, type) == 2)
+ if (strcmp(type, fstype) == 0) {
+diff --git a/tools/bpf/bpftool/xlated_dumper.c b/tools/bpf/bpftool/xlated_dumper.c
+index d0094345fb2bc..5e7cb8b36fef2 100644
+--- a/tools/bpf/bpftool/xlated_dumper.c
++++ b/tools/bpf/bpftool/xlated_dumper.c
+@@ -199,13 +199,13 @@ static const char *print_imm(void *private_data,
+
+ if (insn->src_reg == BPF_PSEUDO_MAP_FD)
+ snprintf(dd->scratch_buff, sizeof(dd->scratch_buff),
+- "map[id:%u]", insn->imm);
++ "map[id:%d]", insn->imm);
+ else if (insn->src_reg == BPF_PSEUDO_MAP_VALUE)
+ snprintf(dd->scratch_buff, sizeof(dd->scratch_buff),
+- "map[id:%u][0]+%u", insn->imm, (insn + 1)->imm);
++ "map[id:%d][0]+%d", insn->imm, (insn + 1)->imm);
+ else if (insn->src_reg == BPF_PSEUDO_MAP_IDX_VALUE)
+ snprintf(dd->scratch_buff, sizeof(dd->scratch_buff),
+- "map[idx:%u]+%u", insn->imm, (insn + 1)->imm);
++ "map[idx:%d]+%d", insn->imm, (insn + 1)->imm);
+ else if (insn->src_reg == BPF_PSEUDO_FUNC)
+ snprintf(dd->scratch_buff, sizeof(dd->scratch_buff),
+ "subprog[%+d]", insn->imm);
+--
+2.39.5
+
--- /dev/null
+From d4da1d68011b437d787e07c265a1f4726a38efc0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Feb 2025 18:37:15 +0100
+Subject: bridge: mdb: Allow replace of a host-joined group
+
+From: Petr Machata <petrm@nvidia.com>
+
+[ Upstream commit d9e9f6d7b7d0c520bb87f19d2cbc57aeeb2091d5 ]
+
+Attempts to replace an MDB group membership of the host itself are
+currently bounced:
+
+ # ip link add name br up type bridge vlan_filtering 1
+ # bridge mdb replace dev br port br grp 239.0.0.1 vid 2
+ # bridge mdb replace dev br port br grp 239.0.0.1 vid 2
+ Error: bridge: Group is already joined by host.
+
+A similar operation done on a member port would succeed. Ignore the check
+for replacement of host group memberships as well.
+
+The bit of code that this enables is br_multicast_host_join(), which, for
+already-joined groups only refreshes the MC group expiration timer, which
+is desirable; and a userspace notification, also desirable.
+
+Change a selftest that exercises this code path from expecting a rejection
+to expecting a pass. The rest of MDB selftests pass without modification.
+
+Signed-off-by: Petr Machata <petrm@nvidia.com>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Acked-by: Nikolay Aleksandrov <razor@blackwall.org>
+Link: https://patch.msgid.link/e5c5188b9787ae806609e7ca3aa2a0a501b9b5c4.1738685648.git.petrm@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bridge/br_mdb.c | 2 +-
+ tools/testing/selftests/net/forwarding/bridge_mdb.sh | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c
+index 1a52a0bca086d..7e1ad229e1330 100644
+--- a/net/bridge/br_mdb.c
++++ b/net/bridge/br_mdb.c
+@@ -1040,7 +1040,7 @@ static int br_mdb_add_group(const struct br_mdb_config *cfg,
+
+ /* host join */
+ if (!port) {
+- if (mp->host_joined) {
++ if (mp->host_joined && !(cfg->nlflags & NLM_F_REPLACE)) {
+ NL_SET_ERR_MSG_MOD(extack, "Group is already joined by host");
+ return -EEXIST;
+ }
+diff --git a/tools/testing/selftests/net/forwarding/bridge_mdb.sh b/tools/testing/selftests/net/forwarding/bridge_mdb.sh
+index d9d587454d207..8c1597ebc2d38 100755
+--- a/tools/testing/selftests/net/forwarding/bridge_mdb.sh
++++ b/tools/testing/selftests/net/forwarding/bridge_mdb.sh
+@@ -149,7 +149,7 @@ cfg_test_host_common()
+ check_err $? "Failed to add $name host entry"
+
+ bridge mdb replace dev br0 port br0 grp $grp $state vid 10 &> /dev/null
+- check_fail $? "Managed to replace $name host entry"
++ check_err $? "Failed to replace $name host entry"
+
+ bridge mdb del dev br0 port br0 grp $grp $state vid 10
+ bridge mdb get dev br0 grp $grp vid 10 &> /dev/null
+--
+2.39.5
+
--- /dev/null
+From de0860d610aaaee77a8c5c713c41fea584ac83b3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 30 Oct 2024 17:04:02 +1030
+Subject: btrfs: allow buffered write to avoid full page read if it's block
+ aligned
+
+From: Qu Wenruo <wqu@suse.com>
+
+[ Upstream commit 0d31ca6584f21821c708752d379871b9fce2dc48 ]
+
+[BUG]
+Since the support of block size (sector size) < page size for btrfs,
+test case generic/563 fails with 4K block size and 64K page size:
+
+ --- tests/generic/563.out 2024-04-25 18:13:45.178550333 +0930
+ +++ /home/adam/xfstests-dev/results//generic/563.out.bad 2024-09-30 09:09:16.155312379 +0930
+ @@ -3,7 +3,8 @@
+ read is in range
+ write is in range
+ write -> read/write
+ -read is in range
+ +read has value of 8388608
+ +read is NOT in range -33792 .. 33792
+ write is in range
+ ...
+
+[CAUSE]
+The test case creates a 8MiB file, then does buffered write into the 8MiB
+using 4K block size, to overwrite the whole file.
+
+On 4K page sized systems, since the write range covers the full block and
+page, btrfs will not bother reading the page, just like what XFS and EXT4
+do.
+
+But on 64K page sized systems, although the 4K sized write is still block
+aligned, it's not page aligned anymore, thus btrfs will read the full
+page, which will be accounted by cgroup and fail the test.
+
+As the test case itself expects such 4K block aligned write should not
+trigger any read.
+
+Such expected behavior is an optimization to reduce folio reads when
+possible, and unfortunately btrfs does not implement such optimization.
+
+[FIX]
+To skip the full page read, we need to do the following modification:
+
+- Do not trigger full page read as long as the buffered write is block
+ aligned
+ This is pretty simple by modifying the check inside
+ prepare_uptodate_page().
+
+- Skip already uptodate blocks during full page read
+ Or we can lead to the following data corruption:
+
+ 0 32K 64K
+ |///////| |
+
+ Where the file range [0, 32K) is dirtied by buffered write, the
+ remaining range [32K, 64K) is not.
+
+ When reading the full page, since [0,32K) is only dirtied but not
+ written back, there is no data extent map for it, but a hole covering
+ [0, 64k).
+
+ If we continue reading the full page range [0, 64K), the dirtied range
+ will be filled with 0 (since there is only a hole covering the whole
+ range).
+ This causes the dirtied range to get lost.
+
+With this optimization, btrfs can pass generic/563 even if the page size
+is larger than fs block size.
+
+Reviewed-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/extent_io.c | 4 ++++
+ fs/btrfs/file.c | 5 +++--
+ 2 files changed, 7 insertions(+), 2 deletions(-)
+
+diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
+index 06922529f19dc..13b5359ea1b77 100644
+--- a/fs/btrfs/extent_io.c
++++ b/fs/btrfs/extent_io.c
+@@ -974,6 +974,10 @@ static int btrfs_do_readpage(struct folio *folio, struct extent_map **em_cached,
+ end_folio_read(folio, true, cur, iosize);
+ break;
+ }
++ if (btrfs_folio_test_uptodate(fs_info, folio, cur, blocksize)) {
++ end_folio_read(folio, true, cur, blocksize);
++ continue;
++ }
+ em = get_extent_map(BTRFS_I(inode), folio, cur, end - cur + 1, em_cached);
+ if (IS_ERR(em)) {
+ end_folio_read(folio, false, cur, end + 1 - cur);
+diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
+index cd4e40a719186..61ad1a79e5698 100644
+--- a/fs/btrfs/file.c
++++ b/fs/btrfs/file.c
+@@ -804,14 +804,15 @@ static int prepare_uptodate_folio(struct inode *inode, struct folio *folio, u64
+ {
+ u64 clamp_start = max_t(u64, pos, folio_pos(folio));
+ u64 clamp_end = min_t(u64, pos + len, folio_pos(folio) + folio_size(folio));
++ const u32 blocksize = inode_to_fs_info(inode)->sectorsize;
+ int ret = 0;
+
+ if (folio_test_uptodate(folio))
+ return 0;
+
+ if (!force_uptodate &&
+- IS_ALIGNED(clamp_start, PAGE_SIZE) &&
+- IS_ALIGNED(clamp_end, PAGE_SIZE))
++ IS_ALIGNED(clamp_start, blocksize) &&
++ IS_ALIGNED(clamp_end, blocksize))
+ return 0;
+
+ ret = btrfs_read_folio(NULL, folio);
+--
+2.39.5
+
--- /dev/null
+From abd9d431df5dd3f2f8a8dba68c14a5baaf54937a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Mar 2025 10:58:46 +0000
+Subject: btrfs: avoid linker error in btrfs_find_create_tree_block()
+
+From: Mark Harmstone <maharmstone@fb.com>
+
+[ Upstream commit 7ef3cbf17d2734ca66c4ed8573be45f4e461e7ee ]
+
+The inline function btrfs_is_testing() is hardcoded to return 0 if
+CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set. Currently we're relying on
+the compiler optimizing out the call to alloc_test_extent_buffer() in
+btrfs_find_create_tree_block(), as it's not been defined (it's behind an
+ #ifdef).
+
+Add a stub version of alloc_test_extent_buffer() to avoid linker errors
+on non-standard optimization levels. This problem was seen on GCC 14
+with -O0 and is helps to see symbols that would be otherwise optimized
+out.
+
+Reviewed-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: Mark Harmstone <maharmstone@fb.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/extent_io.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
+index c021aae8875eb..06922529f19dc 100644
+--- a/fs/btrfs/extent_io.c
++++ b/fs/btrfs/extent_io.c
+@@ -2842,10 +2842,10 @@ struct extent_buffer *find_extent_buffer(struct btrfs_fs_info *fs_info,
+ return eb;
+ }
+
+-#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
+ struct extent_buffer *alloc_test_extent_buffer(struct btrfs_fs_info *fs_info,
+ u64 start)
+ {
++#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
+ struct extent_buffer *eb, *exists = NULL;
+ int ret;
+
+@@ -2881,8 +2881,11 @@ struct extent_buffer *alloc_test_extent_buffer(struct btrfs_fs_info *fs_info,
+ free_eb:
+ btrfs_release_extent_buffer(eb);
+ return exists;
+-}
++#else
++ /* Stub to avoid linker error when compiled with optimizations turned off. */
++ return NULL;
+ #endif
++}
+
+ static struct extent_buffer *grab_extent_buffer(struct btrfs_fs_info *fs_info,
+ struct folio *folio)
+--
+2.39.5
+
--- /dev/null
+From 20a2aed836f59b9e516ce116a4059fbc93299361 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 29 Apr 2025 15:17:50 +0930
+Subject: btrfs: avoid NULL pointer dereference if no valid csum tree
+
+From: Qu Wenruo <wqu@suse.com>
+
+[ Upstream commit f95d186255b319c48a365d47b69bd997fecb674e ]
+
+[BUG]
+When trying read-only scrub on a btrfs with rescue=idatacsums mount
+option, it will crash with the following call trace:
+
+ BUG: kernel NULL pointer dereference, address: 0000000000000208
+ #PF: supervisor read access in kernel mode
+ #PF: error_code(0x0000) - not-present page
+ CPU: 1 UID: 0 PID: 835 Comm: btrfs Tainted: G O 6.15.0-rc3-custom+ #236 PREEMPT(full)
+ Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS unknown 02/02/2022
+ RIP: 0010:btrfs_lookup_csums_bitmap+0x49/0x480 [btrfs]
+ Call Trace:
+ <TASK>
+ scrub_find_fill_first_stripe+0x35b/0x3d0 [btrfs]
+ scrub_simple_mirror+0x175/0x290 [btrfs]
+ scrub_stripe+0x5f7/0x6f0 [btrfs]
+ scrub_chunk+0x9a/0x150 [btrfs]
+ scrub_enumerate_chunks+0x333/0x660 [btrfs]
+ btrfs_scrub_dev+0x23e/0x600 [btrfs]
+ btrfs_ioctl+0x1dcf/0x2f80 [btrfs]
+ __x64_sys_ioctl+0x97/0xc0
+ do_syscall_64+0x4f/0x120
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+[CAUSE]
+Mount option "rescue=idatacsums" will completely skip loading the csum
+tree, so that any data read will not find any data csum thus we will
+ignore data checksum verification.
+
+Normally call sites utilizing csum tree will check the fs state flag
+NO_DATA_CSUMS bit, but unfortunately scrub does not check that bit at all.
+
+This results in scrub to call btrfs_search_slot() on a NULL pointer
+and triggered above crash.
+
+[FIX]
+Check both extent and csum tree root before doing any tree search.
+
+Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/scrub.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
+index 531312efee8df..5d0060eb8ff4c 100644
+--- a/fs/btrfs/scrub.c
++++ b/fs/btrfs/scrub.c
+@@ -1541,8 +1541,8 @@ static int scrub_find_fill_first_stripe(struct btrfs_block_group *bg,
+ u64 extent_gen;
+ int ret;
+
+- if (unlikely(!extent_root)) {
+- btrfs_err(fs_info, "no valid extent root for scrub");
++ if (unlikely(!extent_root || !csum_root)) {
++ btrfs_err(fs_info, "no valid extent or csum root for scrub");
+ return -EUCLEAN;
+ }
+ memset(stripe->sectors, 0, sizeof(struct scrub_sector_verification) *
+--
+2.39.5
+
--- /dev/null
+From 74eddc5ca0e4d2724897f9dc63213bdf2f6d3f6a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 25 Apr 2025 23:23:29 -0700
+Subject: btrfs: compression: adjust cb->compressed_folios allocation type
+
+From: Kees Cook <kees@kernel.org>
+
+[ Upstream commit 6f9a8ab796c6528d22de3c504c81fce7dde63d8a ]
+
+In preparation for making the kmalloc() family of allocators type aware,
+we need to make sure that the returned type from the allocation matches
+the type of the variable being assigned. (Before, the allocator would
+always return "void *", which can be implicitly cast to any pointer type.)
+
+The assigned type is "struct folio **" but the returned type will be
+"struct page **". These are the same allocation size (pointer size), but
+the types don't match. Adjust the allocation type to match the assignment.
+
+Reviewed-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: Kees Cook <kees@kernel.org>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/compression.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c
+index 0c4d486c3048d..18d2210dc7249 100644
+--- a/fs/btrfs/compression.c
++++ b/fs/btrfs/compression.c
+@@ -606,7 +606,7 @@ void btrfs_submit_compressed_read(struct btrfs_bio *bbio)
+ free_extent_map(em);
+
+ cb->nr_folios = DIV_ROUND_UP(compressed_len, PAGE_SIZE);
+- cb->compressed_folios = kcalloc(cb->nr_folios, sizeof(struct page *), GFP_NOFS);
++ cb->compressed_folios = kcalloc(cb->nr_folios, sizeof(struct folio *), GFP_NOFS);
+ if (!cb->compressed_folios) {
+ ret = BLK_STS_RESOURCE;
+ goto out_free_bio;
+--
+2.39.5
+
--- /dev/null
+From 4709e0dfd837569e1b89c5769067da7a453ebafc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 25 Apr 2025 09:25:06 -0400
+Subject: btrfs: correct the order of prelim_ref arguments in btrfs__prelim_ref
+
+From: Goldwyn Rodrigues <rgoldwyn@suse.de>
+
+[ Upstream commit bc7e0975093567f51be8e1bdf4aa5900a3cf0b1e ]
+
+btrfs_prelim_ref() calls the old and new reference variables in the
+incorrect order. This causes a NULL pointer dereference because oldref
+is passed as NULL to trace_btrfs_prelim_ref_insert().
+
+Note, trace_btrfs_prelim_ref_insert() is being called with newref as
+oldref (and oldref as NULL) on purpose in order to print out
+the values of newref.
+
+To reproduce:
+echo 1 > /sys/kernel/debug/tracing/events/btrfs/btrfs_prelim_ref_insert/enable
+
+Perform some writeback operations.
+
+Backtrace:
+BUG: kernel NULL pointer dereference, address: 0000000000000018
+ #PF: supervisor read access in kernel mode
+ #PF: error_code(0x0000) - not-present page
+ PGD 115949067 P4D 115949067 PUD 11594a067 PMD 0
+ Oops: Oops: 0000 [#1] SMP NOPTI
+ CPU: 1 UID: 0 PID: 1188 Comm: fsstress Not tainted 6.15.0-rc2-tester+ #47 PREEMPT(voluntary) 7ca2cef72d5e9c600f0c7718adb6462de8149622
+ Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.3-2-gc13ff2cd-prebuilt.qemu.org 04/01/2014
+ RIP: 0010:trace_event_raw_event_btrfs__prelim_ref+0x72/0x130
+ Code: e8 43 81 9f ff 48 85 c0 74 78 4d 85 e4 0f 84 8f 00 00 00 49 8b 94 24 c0 06 00 00 48 8b 0a 48 89 48 08 48 8b 52 08 48 89 50 10 <49> 8b 55 18 48 89 50 18 49 8b 55 20 48 89 50 20 41 0f b6 55 28 88
+ RSP: 0018:ffffce44820077a0 EFLAGS: 00010286
+ RAX: ffff8c6b403f9014 RBX: ffff8c6b55825730 RCX: 304994edf9cf506b
+ RDX: d8b11eb7f0fdb699 RSI: ffff8c6b403f9010 RDI: ffff8c6b403f9010
+ RBP: 0000000000000001 R08: 0000000000000001 R09: 0000000000000010
+ R10: 00000000ffffffff R11: 0000000000000000 R12: ffff8c6b4e8fb000
+ R13: 0000000000000000 R14: ffffce44820077a8 R15: ffff8c6b4abd1540
+ FS: 00007f4dc6813740(0000) GS:ffff8c6c1d378000(0000) knlGS:0000000000000000
+ CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+ CR2: 0000000000000018 CR3: 000000010eb42000 CR4: 0000000000750ef0
+ PKRU: 55555554
+ Call Trace:
+ <TASK>
+ prelim_ref_insert+0x1c1/0x270
+ find_parent_nodes+0x12a6/0x1ee0
+ ? __entry_text_end+0x101f06/0x101f09
+ ? srso_alias_return_thunk+0x5/0xfbef5
+ ? srso_alias_return_thunk+0x5/0xfbef5
+ ? srso_alias_return_thunk+0x5/0xfbef5
+ ? srso_alias_return_thunk+0x5/0xfbef5
+ btrfs_is_data_extent_shared+0x167/0x640
+ ? fiemap_process_hole+0xd0/0x2c0
+ extent_fiemap+0xa5c/0xbc0
+ ? __entry_text_end+0x101f05/0x101f09
+ btrfs_fiemap+0x7e/0xd0
+ do_vfs_ioctl+0x425/0x9d0
+ __x64_sys_ioctl+0x75/0xc0
+
+Signed-off-by: Goldwyn Rodrigues <rgoldwyn@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/trace/events/btrfs.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/include/trace/events/btrfs.h b/include/trace/events/btrfs.h
+index 549ab3b419618..3efc00cc1bcd2 100644
+--- a/include/trace/events/btrfs.h
++++ b/include/trace/events/btrfs.h
+@@ -1928,7 +1928,7 @@ DECLARE_EVENT_CLASS(btrfs__prelim_ref,
+ TP_PROTO(const struct btrfs_fs_info *fs_info,
+ const struct prelim_ref *oldref,
+ const struct prelim_ref *newref, u64 tree_size),
+- TP_ARGS(fs_info, newref, oldref, tree_size),
++ TP_ARGS(fs_info, oldref, newref, tree_size),
+
+ TP_STRUCT__entry_btrfs(
+ __field( u64, root_id )
+--
+2.39.5
+
--- /dev/null
+From 722828e75e3307e75867cb7f14a25db6d9f1a9d8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Mar 2025 14:25:38 +0000
+Subject: btrfs: fix non-empty delayed iputs list on unmount due to async
+ workers
+
+From: Filipe Manana <fdmanana@suse.com>
+
+[ Upstream commit cda76788f8b0f7de3171100e3164ec1ce702292e ]
+
+At close_ctree() after we have ran delayed iputs either explicitly through
+calling btrfs_run_delayed_iputs() or later during the call to
+btrfs_commit_super() or btrfs_error_commit_super(), we assert that the
+delayed iputs list is empty.
+
+We have (another) race where this assertion might fail because we have
+queued an async write into the fs_info->workers workqueue. Here's how it
+happens:
+
+1) We are submitting a data bio for an inode that is not the data
+ relocation inode, so we call btrfs_wq_submit_bio();
+
+2) btrfs_wq_submit_bio() submits a work for the fs_info->workers queue
+ that will run run_one_async_done();
+
+3) We enter close_ctree(), flush several work queues except
+ fs_info->workers, explicitly run delayed iputs with a call to
+ btrfs_run_delayed_iputs() and then again shortly after by calling
+ btrfs_commit_super() or btrfs_error_commit_super(), which also run
+ delayed iputs;
+
+4) run_one_async_done() is executed in the work queue, and because there
+ was an IO error (bio->bi_status is not 0) it calls btrfs_bio_end_io(),
+ which drops the final reference on the associated ordered extent by
+ calling btrfs_put_ordered_extent() - and that adds a delayed iput for
+ the inode;
+
+5) At close_ctree() we find that after stopping the cleaner and
+ transaction kthreads the delayed iputs list is not empty, failing the
+ following assertion:
+
+ ASSERT(list_empty(&fs_info->delayed_iputs));
+
+Fix this by flushing the fs_info->workers workqueue before running delayed
+iputs at close_ctree().
+
+David reported this when running generic/648, which exercises IO error
+paths by using the DM error table.
+
+Reported-by: David Sterba <dsterba@suse.com>
+Reviewed-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/disk-io.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
+index e4eda8b0f9381..cc8d736937012 100644
+--- a/fs/btrfs/disk-io.c
++++ b/fs/btrfs/disk-io.c
+@@ -4356,6 +4356,19 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info)
+ */
+ btrfs_flush_workqueue(fs_info->delalloc_workers);
+
++ /*
++ * We can have ordered extents getting their last reference dropped from
++ * the fs_info->workers queue because for async writes for data bios we
++ * queue a work for that queue, at btrfs_wq_submit_bio(), that runs
++ * run_one_async_done() which calls btrfs_bio_end_io() in case the bio
++ * has an error, and that later function can do the final
++ * btrfs_put_ordered_extent() on the ordered extent attached to the bio,
++ * which adds a delayed iput for the inode. So we must flush the queue
++ * so that we don't have delayed iputs after committing the current
++ * transaction below and stopping the cleaner and transaction kthreads.
++ */
++ btrfs_flush_workqueue(fs_info->workers);
++
+ /*
+ * When finishing a compressed write bio we schedule a work queue item
+ * to finish an ordered extent - btrfs_finish_compressed_write_work()
+--
+2.39.5
+
--- /dev/null
+From 36608c3c5c389dd40cb9e5a4c1c1147204c62374 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 21 Feb 2025 16:12:15 +0000
+Subject: btrfs: get zone unusable bytes while holding lock at
+ btrfs_reclaim_bgs_work()
+
+From: Filipe Manana <fdmanana@suse.com>
+
+[ Upstream commit 1283b8c125a83bf7a7dbe90c33d3472b6d7bf612 ]
+
+At btrfs_reclaim_bgs_work(), we are grabbing a block group's zone unusable
+bytes while not under the protection of the block group's spinlock, so
+this can trigger race reports from KCSAN (or similar tools) since that
+field is typically updated while holding the lock, such as at
+__btrfs_add_free_space_zoned() for example.
+
+Fix this by grabbing the zone unusable bytes while we are still in the
+critical section holding the block group's spinlock, which is right above
+where we are currently grabbing it.
+
+Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/block-group.c | 18 +++++++++++-------
+ 1 file changed, 11 insertions(+), 7 deletions(-)
+
+diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c
+index b96b235943344..b14faa1d57b8c 100644
+--- a/fs/btrfs/block-group.c
++++ b/fs/btrfs/block-group.c
+@@ -1888,6 +1888,17 @@ void btrfs_reclaim_bgs_work(struct work_struct *work)
+ up_write(&space_info->groups_sem);
+ goto next;
+ }
++
++ /*
++ * Cache the zone_unusable value before turning the block group
++ * to read only. As soon as the block group is read only it's
++ * zone_unusable value gets moved to the block group's read-only
++ * bytes and isn't available for calculations anymore. We also
++ * cache it before unlocking the block group, to prevent races
++ * (reports from KCSAN and such tools) with tasks updating it.
++ */
++ zone_unusable = bg->zone_unusable;
++
+ spin_unlock(&bg->lock);
+ spin_unlock(&space_info->lock);
+
+@@ -1904,13 +1915,6 @@ void btrfs_reclaim_bgs_work(struct work_struct *work)
+ goto next;
+ }
+
+- /*
+- * Cache the zone_unusable value before turning the block group
+- * to read only. As soon as the blog group is read only it's
+- * zone_unusable value gets moved to the block group's read-only
+- * bytes and isn't available for calculations anymore.
+- */
+- zone_unusable = bg->zone_unusable;
+ ret = inc_block_group_ro(bg, 0);
+ up_write(&space_info->groups_sem);
+ if (ret < 0)
+--
+2.39.5
+
--- /dev/null
+From 7db5ab545e46d9ee68658adac32d2164c6297f91 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 25 Apr 2025 12:47:50 -0700
+Subject: btrfs: handle empty eb->folios in num_extent_folios()
+
+From: Boris Burkov <boris@bur.io>
+
+[ Upstream commit d6fe0c69b3aa5c985380b794bdf8e6e9b1811e60 ]
+
+num_extent_folios() unconditionally calls folio_order() on
+eb->folios[0]. If that is NULL this will be a segfault. It is reasonable
+for it to return 0 as the number of folios in the eb when the first
+entry is NULL, so do that instead.
+
+Reviewed-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: Boris Burkov <boris@bur.io>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/extent_io.h | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h
+index 6c5328bfabc22..2aefc64cdd295 100644
+--- a/fs/btrfs/extent_io.h
++++ b/fs/btrfs/extent_io.h
+@@ -297,6 +297,8 @@ static inline int num_extent_pages(const struct extent_buffer *eb)
+ */
+ static inline int num_extent_folios(const struct extent_buffer *eb)
+ {
++ if (!eb->folios[0])
++ return 0;
+ if (folio_order(eb->folios[0]))
+ return 1;
+ return num_extent_pages(eb);
+--
+2.39.5
+
--- /dev/null
+From e9dd737ab199bd7a989845fb9ed3b9f5d9938caf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Mar 2025 15:01:05 -0800
+Subject: btrfs: make btrfs_discard_workfn() block_group ref explicit
+
+From: Boris Burkov <boris@bur.io>
+
+[ Upstream commit 895c6721d310c036dcfebb5ab845822229fa35eb ]
+
+Currently, the async discard machinery owns a ref to the block_group
+when the block_group is queued on a discard list. However, to handle
+races with discard cancellation and the discard workfn, we have a
+specific logic to detect that the block_group is *currently* running in
+the workfn, to protect the workfn's usage amidst cancellation.
+
+As far as I can tell, this doesn't have any overt bugs (though
+finish_discard_pass() and remove_from_discard_list() racing can have a
+surprising outcome for the caller of remove_from_discard_list() in that
+it is again added at the end).
+
+But it is needlessly complicated to rely on locking and the nullity of
+discard_ctl->block_group. Simplify this significantly by just taking a
+refcount while we are in the workfn and unconditionally drop it in both
+the remove and workfn paths, regardless of if they race.
+
+Reviewed-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: Boris Burkov <boris@bur.io>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/discard.c | 34 ++++++++++++++++------------------
+ 1 file changed, 16 insertions(+), 18 deletions(-)
+
+diff --git a/fs/btrfs/discard.c b/fs/btrfs/discard.c
+index e9cdc1759dada..de23c4b3515e5 100644
+--- a/fs/btrfs/discard.c
++++ b/fs/btrfs/discard.c
+@@ -168,13 +168,7 @@ static bool remove_from_discard_list(struct btrfs_discard_ctl *discard_ctl,
+ block_group->discard_eligible_time = 0;
+ queued = !list_empty(&block_group->discard_list);
+ list_del_init(&block_group->discard_list);
+- /*
+- * If the block group is currently running in the discard workfn, we
+- * don't want to deref it, since it's still being used by the workfn.
+- * The workfn will notice this case and deref the block group when it is
+- * finished.
+- */
+- if (queued && !running)
++ if (queued)
+ btrfs_put_block_group(block_group);
+
+ spin_unlock(&discard_ctl->lock);
+@@ -273,9 +267,10 @@ static struct btrfs_block_group *peek_discard_list(
+ block_group->discard_cursor = block_group->start;
+ block_group->discard_state = BTRFS_DISCARD_EXTENTS;
+ }
+- discard_ctl->block_group = block_group;
+ }
+ if (block_group) {
++ btrfs_get_block_group(block_group);
++ discard_ctl->block_group = block_group;
+ *discard_state = block_group->discard_state;
+ *discard_index = block_group->discard_index;
+ }
+@@ -506,9 +501,20 @@ static void btrfs_discard_workfn(struct work_struct *work)
+
+ block_group = peek_discard_list(discard_ctl, &discard_state,
+ &discard_index, now);
+- if (!block_group || !btrfs_run_discard_work(discard_ctl))
++ if (!block_group)
+ return;
++ if (!btrfs_run_discard_work(discard_ctl)) {
++ spin_lock(&discard_ctl->lock);
++ btrfs_put_block_group(block_group);
++ discard_ctl->block_group = NULL;
++ spin_unlock(&discard_ctl->lock);
++ return;
++ }
+ if (now < block_group->discard_eligible_time) {
++ spin_lock(&discard_ctl->lock);
++ btrfs_put_block_group(block_group);
++ discard_ctl->block_group = NULL;
++ spin_unlock(&discard_ctl->lock);
+ btrfs_discard_schedule_work(discard_ctl, false);
+ return;
+ }
+@@ -560,15 +566,7 @@ static void btrfs_discard_workfn(struct work_struct *work)
+ spin_lock(&discard_ctl->lock);
+ discard_ctl->prev_discard = trimmed;
+ discard_ctl->prev_discard_time = now;
+- /*
+- * If the block group was removed from the discard list while it was
+- * running in this workfn, then we didn't deref it, since this function
+- * still owned that reference. But we set the discard_ctl->block_group
+- * back to NULL, so we can use that condition to know that now we need
+- * to deref the block_group.
+- */
+- if (discard_ctl->block_group == NULL)
+- btrfs_put_block_group(block_group);
++ btrfs_put_block_group(block_group);
+ discard_ctl->block_group = NULL;
+ __btrfs_discard_schedule_work(discard_ctl, now, false);
+ spin_unlock(&discard_ctl->lock);
+--
+2.39.5
+
--- /dev/null
+From 6a2d904623a8d1711b6b5065845d52cb3f2be60a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 15 Nov 2024 19:15:34 +1030
+Subject: btrfs: prevent inline data extents read from touching blocks beyond
+ its range
+
+From: Qu Wenruo <wqu@suse.com>
+
+[ Upstream commit 1a5b5668d711d3d1ef447446beab920826decec3 ]
+
+Currently reading an inline data extent will zero out the remaining
+range in the page.
+
+This is not yet causing problems even for block size < page size
+(subpage) cases because:
+
+1) An inline data extent always starts at file offset 0
+ Meaning at page read, we always read the inline extent first, before
+ any other blocks in the page. Then later blocks are properly read out
+ and re-fill the zeroed out ranges.
+
+2) Currently btrfs will read out the whole page if a buffered write is
+ not page aligned
+ So a page is either fully uptodate at buffered write time (covers the
+ whole page), or we will read out the whole page first.
+ Meaning there is nothing to lose for such an inline extent read.
+
+But it's still not ideal:
+
+- We're zeroing out the page twice
+ Once done by read_inline_extent()/uncompress_inline(), once done by
+ btrfs_do_readpage() for ranges beyond i_size.
+
+- We're touching blocks that don't belong to the inline extent
+ In the incoming patches, we can have a partial uptodate folio, of
+ which some dirty blocks can exist while the page is not fully uptodate:
+
+ The page size is 16K and block size is 4K:
+
+ 0 4K 8K 12K 16K
+ | | |/////////| |
+
+ And range [8K, 12K) is dirtied by a buffered write, the remaining
+ blocks are not uptodate.
+
+ If range [0, 4K) contains an inline data extent, and we try to read
+ the whole page, the current behavior will overwrite range [8K, 12K)
+ with zero and cause data loss.
+
+So to make the behavior more consistent and in preparation for future
+changes, limit the inline data extents read to only zero out the range
+inside the first block, not the whole page.
+
+Reviewed-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/inode.c | 14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
+index 9a648fb130230..a7136311a13c6 100644
+--- a/fs/btrfs/inode.c
++++ b/fs/btrfs/inode.c
+@@ -6779,6 +6779,7 @@ static noinline int uncompress_inline(struct btrfs_path *path,
+ {
+ int ret;
+ struct extent_buffer *leaf = path->nodes[0];
++ const u32 blocksize = leaf->fs_info->sectorsize;
+ char *tmp;
+ size_t max_size;
+ unsigned long inline_size;
+@@ -6795,7 +6796,7 @@ static noinline int uncompress_inline(struct btrfs_path *path,
+
+ read_extent_buffer(leaf, tmp, ptr, inline_size);
+
+- max_size = min_t(unsigned long, PAGE_SIZE, max_size);
++ max_size = min_t(unsigned long, blocksize, max_size);
+ ret = btrfs_decompress(compress_type, tmp, folio, 0, inline_size,
+ max_size);
+
+@@ -6807,14 +6808,15 @@ static noinline int uncompress_inline(struct btrfs_path *path,
+ * cover that region here.
+ */
+
+- if (max_size < PAGE_SIZE)
+- folio_zero_range(folio, max_size, PAGE_SIZE - max_size);
++ if (max_size < blocksize)
++ folio_zero_range(folio, max_size, blocksize - max_size);
+ kfree(tmp);
+ return ret;
+ }
+
+ static int read_inline_extent(struct btrfs_path *path, struct folio *folio)
+ {
++ const u32 blocksize = path->nodes[0]->fs_info->sectorsize;
+ struct btrfs_file_extent_item *fi;
+ void *kaddr;
+ size_t copy_size;
+@@ -6829,14 +6831,14 @@ static int read_inline_extent(struct btrfs_path *path, struct folio *folio)
+ if (btrfs_file_extent_compression(path->nodes[0], fi) != BTRFS_COMPRESS_NONE)
+ return uncompress_inline(path, folio, fi);
+
+- copy_size = min_t(u64, PAGE_SIZE,
++ copy_size = min_t(u64, blocksize,
+ btrfs_file_extent_ram_bytes(path->nodes[0], fi));
+ kaddr = kmap_local_folio(folio, 0);
+ read_extent_buffer(path->nodes[0], kaddr,
+ btrfs_file_extent_inline_start(fi), copy_size);
+ kunmap_local(kaddr);
+- if (copy_size < PAGE_SIZE)
+- folio_zero_range(folio, copy_size, PAGE_SIZE - copy_size);
++ if (copy_size < blocksize)
++ folio_zero_range(folio, copy_size, blocksize - copy_size);
+ return 0;
+ }
+
+--
+2.39.5
+
--- /dev/null
+From ec02842137bdccb74ed331a1b0a335ee22eb179c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 25 Feb 2025 14:30:44 +1030
+Subject: btrfs: properly limit inline data extent according to block size
+
+From: Qu Wenruo <wqu@suse.com>
+
+[ Upstream commit 23019d3e6617a8ec99a8d2f5947aa3dd8a74a1b8 ]
+
+Btrfs utilizes inline data extent for the following cases:
+
+- Regular small files
+- Symlinks
+
+And "btrfs check" detects any file extents that are too large as an
+error.
+
+It's not a problem for 4K block size, but for the incoming smaller
+block sizes (2K), it can cause problems due to bad limits:
+
+- Non-compressed inline data extents
+ We do not allow a non-compressed inline data extent to be as large as
+ block size.
+
+- Symlinks
+ Currently the only real limit on symlinks are 4K, which can be larger
+ than 2K block size.
+
+These will result btrfs-check to report too large file extents.
+
+Fix it by adding proper size checks for the above cases.
+
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/inode.c | 11 ++++++++++-
+ 1 file changed, 10 insertions(+), 1 deletion(-)
+
+diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
+index a06fca7934d55..9a648fb130230 100644
+--- a/fs/btrfs/inode.c
++++ b/fs/btrfs/inode.c
+@@ -583,6 +583,10 @@ static bool can_cow_file_range_inline(struct btrfs_inode *inode,
+ if (size > fs_info->sectorsize)
+ return false;
+
++ /* We do not allow a non-compressed extent to be as large as block size. */
++ if (data_len >= fs_info->sectorsize)
++ return false;
++
+ /* We cannot exceed the maximum inline data size. */
+ if (data_len > BTRFS_MAX_INLINE_DATA_SIZE(fs_info))
+ return false;
+@@ -8671,7 +8675,12 @@ static int btrfs_symlink(struct mnt_idmap *idmap, struct inode *dir,
+ struct extent_buffer *leaf;
+
+ name_len = strlen(symname);
+- if (name_len > BTRFS_MAX_INLINE_DATA_SIZE(fs_info))
++ /*
++ * Symlinks utilize uncompressed inline extent data, which should not
++ * reach block size.
++ */
++ if (name_len > BTRFS_MAX_INLINE_DATA_SIZE(fs_info) ||
++ name_len >= fs_info->sectorsize)
+ return -ENAMETOOLONG;
+
+ inode = new_inode(dir->i_sb);
+--
+2.39.5
+
--- /dev/null
+From 92b4068394e97e1a7647cdfd139395727c70b526 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 7 Mar 2025 14:36:10 +1030
+Subject: btrfs: run btrfs_error_commit_super() early
+
+From: Qu Wenruo <wqu@suse.com>
+
+[ Upstream commit df94a342efb451deb0e32b495d1d6cd4bb3a1648 ]
+
+[BUG]
+Even after all the error fixes related the
+"ASSERT(list_empty(&fs_info->delayed_iputs));" in close_ctree(), I can
+still hit it reliably with my experimental 2K block size.
+
+[CAUSE]
+In my case, all the error is triggered after the fs is already in error
+status.
+
+I find the following call trace to be the cause of race:
+
+ Main thread | endio_write_workers
+---------------------------------------------+---------------------------
+close_ctree() |
+|- btrfs_error_commit_super() |
+| |- btrfs_cleanup_transaction() |
+| | |- btrfs_destroy_all_ordered_extents() |
+| | |- btrfs_wait_ordered_roots() |
+| |- btrfs_run_delayed_iputs() |
+| | btrfs_finish_ordered_io()
+| | |- btrfs_put_ordered_extent()
+| | |- btrfs_add_delayed_iput()
+|- ASSERT(list_empty(delayed_iputs)) |
+ !!! Triggered !!!
+
+The root cause is that, btrfs_wait_ordered_roots() only wait for
+ordered extents to finish their IOs, not to wait for them to finish and
+removed.
+
+[FIX]
+Since btrfs_error_commit_super() will flush and wait for all ordered
+extents, it should be executed early, before we start flushing the
+workqueues.
+
+And since btrfs_error_commit_super() now runs early, there is no need to
+run btrfs_run_delayed_iputs() inside it, so just remove the
+btrfs_run_delayed_iputs() call from btrfs_error_commit_super().
+
+Reviewed-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/disk-io.c | 15 ++++++++-------
+ 1 file changed, 8 insertions(+), 7 deletions(-)
+
+diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
+index ca821e5966bd3..e4eda8b0f9381 100644
+--- a/fs/btrfs/disk-io.c
++++ b/fs/btrfs/disk-io.c
+@@ -4328,6 +4328,14 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info)
+ /* clear out the rbtree of defraggable inodes */
+ btrfs_cleanup_defrag_inodes(fs_info);
+
++ /*
++ * Handle the error fs first, as it will flush and wait for all ordered
++ * extents. This will generate delayed iputs, thus we want to handle
++ * it first.
++ */
++ if (unlikely(BTRFS_FS_ERROR(fs_info)))
++ btrfs_error_commit_super(fs_info);
++
+ /*
+ * Wait for any fixup workers to complete.
+ * If we don't wait for them here and they are still running by the time
+@@ -4418,9 +4426,6 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info)
+ btrfs_err(fs_info, "commit super ret %d", ret);
+ }
+
+- if (BTRFS_FS_ERROR(fs_info))
+- btrfs_error_commit_super(fs_info);
+-
+ kthread_stop(fs_info->transaction_kthread);
+ kthread_stop(fs_info->cleaner_kthread);
+
+@@ -4543,10 +4548,6 @@ static void btrfs_error_commit_super(struct btrfs_fs_info *fs_info)
+ /* cleanup FS via transaction */
+ btrfs_cleanup_transaction(fs_info);
+
+- mutex_lock(&fs_info->cleaner_mutex);
+- btrfs_run_delayed_iputs(fs_info);
+- mutex_unlock(&fs_info->cleaner_mutex);
+-
+ down_write(&fs_info->cleanup_work_sem);
+ up_write(&fs_info->cleanup_work_sem);
+ }
+--
+2.39.5
+
--- /dev/null
+From 2d6a6727aa46abc99e5caa90478efe96eace8f86 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Feb 2025 13:09:25 +0000
+Subject: btrfs: send: return -ENAMETOOLONG when attempting a path that is too
+ long
+
+From: Filipe Manana <fdmanana@suse.com>
+
+[ Upstream commit a77749b3e21813566cea050bbb3414ae74562eba ]
+
+When attempting to build a too long path we are currently returning
+-ENOMEM, which is very odd and misleading. So update fs_path_ensure_buf()
+to return -ENAMETOOLONG instead. Also, while at it, move the WARN_ON()
+into the if statement's expression, as it makes it clear what is being
+tested and also has the effect of adding 'unlikely' to the statement,
+which allows the compiler to generate better code as this condition is
+never expected to happen.
+
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/send.c | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
+index f437138fefbc5..bb8a0945b0fd3 100644
+--- a/fs/btrfs/send.c
++++ b/fs/btrfs/send.c
+@@ -487,10 +487,8 @@ static int fs_path_ensure_buf(struct fs_path *p, int len)
+ if (p->buf_len >= len)
+ return 0;
+
+- if (len > PATH_MAX) {
+- WARN_ON(1);
+- return -ENOMEM;
+- }
++ if (WARN_ON(len > PATH_MAX))
++ return -ENAMETOOLONG;
+
+ path_len = p->end - p->start;
+ old_buf_len = p->buf_len;
+--
+2.39.5
+
--- /dev/null
+From fe0bd02d7a5156ff8edc67af7f606637ec353ef4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 4 Apr 2025 20:19:41 +0200
+Subject: btrfs: tree-checker: adjust error code for header level check
+
+From: David Sterba <dsterba@suse.com>
+
+[ Upstream commit f1ab0171e9be96fd530329fa54761cff5e09ea95 ]
+
+The whole tree checker returns EUCLEAN, except the one check in
+btrfs_verify_level_key(). This was inherited from the function that was
+moved from disk-io.c in 2cac5af16537 ("btrfs: move
+btrfs_verify_level_key into tree-checker.c") but this should be unified
+with the rest.
+
+Reviewed-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/tree-checker.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
+index 43979891f7c89..2b66a6130269a 100644
+--- a/fs/btrfs/tree-checker.c
++++ b/fs/btrfs/tree-checker.c
+@@ -2235,7 +2235,7 @@ int btrfs_verify_level_key(struct extent_buffer *eb,
+ btrfs_err(fs_info,
+ "tree level mismatch detected, bytenr=%llu level expected=%u has=%u",
+ eb->start, check->level, found_level);
+- return -EIO;
++ return -EUCLEAN;
+ }
+
+ if (!check->has_first_key)
+--
+2.39.5
+
--- /dev/null
+From 1136d333d91088ecf2d5189367540a84e60449a0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 12 Feb 2025 15:05:00 +0100
+Subject: btrfs: zoned: exit btrfs_can_activate_zone if
+ BTRFS_FS_NEED_ZONE_FINISH is set
+
+From: Johannes Thumshirn <johannes.thumshirn@wdc.com>
+
+[ Upstream commit 26b38e28162ef4ceb1e0482299820fbbd7dbcd92 ]
+
+If BTRFS_FS_NEED_ZONE_FINISH is already set for the whole filesystem, exit
+early in btrfs_can_activate_zone(). There's no need to check if
+BTRFS_FS_NEED_ZONE_FINISH needs to be set if it is already set.
+
+Reviewed-by: Naohiro Aota <naohiro.aota@wdc.com>
+Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/zoned.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c
+index f39656668967c..4a3e02b49f295 100644
+--- a/fs/btrfs/zoned.c
++++ b/fs/btrfs/zoned.c
+@@ -2344,6 +2344,9 @@ bool btrfs_can_activate_zone(struct btrfs_fs_devices *fs_devices, u64 flags)
+ if (!btrfs_is_zoned(fs_info))
+ return true;
+
++ if (test_bit(BTRFS_FS_NEED_ZONE_FINISH, &fs_info->flags))
++ return false;
++
+ /* Check if there is a device with active zones left */
+ mutex_lock(&fs_info->chunk_mutex);
+ spin_lock(&fs_info->zone_active_bgs_lock);
+--
+2.39.5
+
--- /dev/null
+From 746254ec92f6b9f536016342522ce0be0451ca6f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 12 Feb 2025 21:23:14 +0100
+Subject: can: c_can: Use of_property_present() to test existence of DT
+ property
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+[ Upstream commit ab1bc2290fd8311d49b87c29f1eb123fcb581bee ]
+
+of_property_read_bool() should be used only on boolean properties.
+
+Cc: Rob Herring <robh@kernel.org>
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Reviewed-by: Vincent Mailhol <mailhol.vincent@wanadoo.fr>
+Link: https://patch.msgid.link/20250212-syscon-phandle-args-can-v2-3-ac9a1253396b@linaro.org
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/can/c_can/c_can_platform.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/can/c_can/c_can_platform.c b/drivers/net/can/c_can/c_can_platform.c
+index 399844809bbea..bb6071a758f36 100644
+--- a/drivers/net/can/c_can/c_can_platform.c
++++ b/drivers/net/can/c_can/c_can_platform.c
+@@ -324,7 +324,7 @@ static int c_can_plat_probe(struct platform_device *pdev)
+ /* Check if we need custom RAMINIT via syscon. Mostly for TI
+ * platforms. Only supported with DT boot.
+ */
+- if (np && of_property_read_bool(np, "syscon-raminit")) {
++ if (np && of_property_present(np, "syscon-raminit")) {
+ u32 id;
+ struct c_can_raminit *raminit = &priv->raminit_sys;
+
+--
+2.39.5
+
--- /dev/null
+From b995b20e853ec049933bcef95531354cee783bb3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 17 Apr 2025 07:30:00 +0000
+Subject: cgroup: Fix compilation issue due to cgroup_mutex not being exported
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: gaoxu <gaoxu2@honor.com>
+
+[ Upstream commit 87c259a7a359e73e6c52c68fcbec79988999b4e6 ]
+
+When adding folio_memcg function call in the zram module for
+Android16-6.12, the following error occurs during compilation:
+ERROR: modpost: "cgroup_mutex" [../soc-repo/zram.ko] undefined!
+
+This error is caused by the indirect call to lockdep_is_held(&cgroup_mutex)
+within folio_memcg. The export setting for cgroup_mutex is controlled by
+the CONFIG_PROVE_RCU macro. If CONFIG_LOCKDEP is enabled while
+CONFIG_PROVE_RCU is not, this compilation error will occur.
+
+To resolve this issue, add a parallel macro CONFIG_LOCKDEP control to
+ensure cgroup_mutex is properly exported when needed.
+
+Signed-off-by: gao xu <gaoxu2@honor.com>
+Acked-by: Michal Koutný <mkoutny@suse.com>
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/cgroup/cgroup.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
+index 68d58753c75c3..660d27a0cb3d4 100644
+--- a/kernel/cgroup/cgroup.c
++++ b/kernel/cgroup/cgroup.c
+@@ -90,7 +90,7 @@
+ DEFINE_MUTEX(cgroup_mutex);
+ DEFINE_SPINLOCK(css_set_lock);
+
+-#ifdef CONFIG_PROVE_RCU
++#if (defined CONFIG_PROVE_RCU || defined CONFIG_LOCKDEP)
+ EXPORT_SYMBOL_GPL(cgroup_mutex);
+ EXPORT_SYMBOL_GPL(css_set_lock);
+ #endif
+--
+2.39.5
+
--- /dev/null
+From b13fe3febaa9ce6e118034d99e829f0052b5317d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 19 Mar 2025 00:13:30 -0700
+Subject: cgroup/rstat: avoid disabling irqs for O(num_cpu)
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit 0efc297a3c4974dbd609ee36fc6345720b6ca735 ]
+
+cgroup_rstat_flush_locked() grabs the irq safe cgroup_rstat_lock while
+iterating all possible cpus. It only drops the lock if there is
+scheduler or spin lock contention. If neither, then interrupts can be
+disabled for a long time. On large machines this can disable interrupts
+for a long enough time to drop network packets. On 400+ CPU machines
+I've seen interrupt disabled for over 40 msec.
+
+Prevent rstat from disabling interrupts while processing all possible
+cpus. Instead drop and reacquire cgroup_rstat_lock for each cpu. This
+approach was previously discussed in
+https://lore.kernel.org/lkml/ZBz%2FV5a7%2F6PZeM7S@slm.duckdns.org/,
+though this was in the context of an non-irq rstat spin lock.
+
+Benchmark this change with:
+1) a single stat_reader process with 400 threads, each reading a test
+ memcg's memory.stat repeatedly for 10 seconds.
+2) 400 memory hog processes running in the test memcg and repeatedly
+ charging memory until oom killed. Then they repeat charging and oom
+ killing.
+
+v6.14-rc6 with CONFIG_IRQSOFF_TRACER with stat_reader and hogs, finds
+interrupts are disabled by rstat for 45341 usec:
+ # => started at: _raw_spin_lock_irq
+ # => ended at: cgroup_rstat_flush
+ #
+ #
+ # _------=> CPU#
+ # / _-----=> irqs-off/BH-disabled
+ # | / _----=> need-resched
+ # || / _---=> hardirq/softirq
+ # ||| / _--=> preempt-depth
+ # |||| / _-=> migrate-disable
+ # ||||| / delay
+ # cmd pid |||||| time | caller
+ # \ / |||||| \ | /
+ stat_rea-96532 52d.... 0us*: _raw_spin_lock_irq
+ stat_rea-96532 52d.... 45342us : cgroup_rstat_flush
+ stat_rea-96532 52d.... 45342us : tracer_hardirqs_on <-cgroup_rstat_flush
+ stat_rea-96532 52d.... 45343us : <stack trace>
+ => memcg1_stat_format
+ => memory_stat_format
+ => memory_stat_show
+ => seq_read_iter
+ => vfs_read
+ => ksys_read
+ => do_syscall_64
+ => entry_SYSCALL_64_after_hwframe
+
+With this patch the CONFIG_IRQSOFF_TRACER doesn't find rstat to be the
+longest holder. The longest irqs-off holder has irqs disabled for
+4142 usec, a huge reduction from previous 45341 usec rstat finding.
+
+Running stat_reader memory.stat reader for 10 seconds:
+- without memory hogs: 9.84M accesses => 12.7M accesses
+- with memory hogs: 9.46M accesses => 11.1M accesses
+The throughput of memory.stat access improves.
+
+The mode of memory.stat access latency after grouping by of 2 buckets:
+- without memory hogs: 64 usec => 16 usec
+- with memory hogs: 64 usec => 8 usec
+The memory.stat latency improves.
+
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Signed-off-by: Greg Thelen <gthelen@google.com>
+Tested-by: Greg Thelen <gthelen@google.com>
+Acked-by: Michal Koutný <mkoutny@suse.com>
+Reviewed-by: Yosry Ahmed <yosry.ahmed@linux.dev>
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/cgroup/rstat.c | 12 +++++-------
+ 1 file changed, 5 insertions(+), 7 deletions(-)
+
+diff --git a/kernel/cgroup/rstat.c b/kernel/cgroup/rstat.c
+index 3e01781aeb7bd..c4ce2f5a9745f 100644
+--- a/kernel/cgroup/rstat.c
++++ b/kernel/cgroup/rstat.c
+@@ -323,13 +323,11 @@ static void cgroup_rstat_flush_locked(struct cgroup *cgrp)
+ rcu_read_unlock();
+ }
+
+- /* play nice and yield if necessary */
+- if (need_resched() || spin_needbreak(&cgroup_rstat_lock)) {
+- __cgroup_rstat_unlock(cgrp, cpu);
+- if (!cond_resched())
+- cpu_relax();
+- __cgroup_rstat_lock(cgrp, cpu);
+- }
++ /* play nice and avoid disabling interrupts for a long time */
++ __cgroup_rstat_unlock(cgrp, cpu);
++ if (!cond_resched())
++ cpu_relax();
++ __cgroup_rstat_lock(cgrp, cpu);
+ }
+ }
+
+--
+2.39.5
+
--- /dev/null
+From c229d8ebe8717878fecdedfc30ccefa904523f0c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 9 Dec 2024 20:44:23 +0100
+Subject: cifs: Add fallback for SMB2 CREATE without FILE_READ_ATTRIBUTES
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Pali Rohár <pali@kernel.org>
+
+[ Upstream commit e255612b5ed9f179abe8196df7c2ba09dd227900 ]
+
+Some operations, like WRITE, does not require FILE_READ_ATTRIBUTES access.
+
+So when FILE_READ_ATTRIBUTES is not explicitly requested for
+smb2_open_file() then first try to do SMB2 CREATE with FILE_READ_ATTRIBUTES
+access (like it was before) and then fallback to SMB2 CREATE without
+FILE_READ_ATTRIBUTES access (less common case).
+
+This change allows to complete WRITE operation to a file when it does not
+grant FILE_READ_ATTRIBUTES permission and its parent directory does not
+grant READ_DATA permission (parent directory READ_DATA is implicit grant of
+child FILE_READ_ATTRIBUTES permission).
+
+Signed-off-by: Pali Rohár <pali@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/client/smb2file.c | 11 ++++++++++-
+ 1 file changed, 10 insertions(+), 1 deletion(-)
+
+diff --git a/fs/smb/client/smb2file.c b/fs/smb/client/smb2file.c
+index d609a20fb98a9..2d726e9b950cf 100644
+--- a/fs/smb/client/smb2file.c
++++ b/fs/smb/client/smb2file.c
+@@ -152,16 +152,25 @@ int smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, __u32
+ int err_buftype = CIFS_NO_BUFFER;
+ struct cifs_fid *fid = oparms->fid;
+ struct network_resiliency_req nr_ioctl_req;
++ bool retry_without_read_attributes = false;
+
+ smb2_path = cifs_convert_path_to_utf16(oparms->path, oparms->cifs_sb);
+ if (smb2_path == NULL)
+ return -ENOMEM;
+
+- oparms->desired_access |= FILE_READ_ATTRIBUTES;
++ if (!(oparms->desired_access & FILE_READ_ATTRIBUTES)) {
++ oparms->desired_access |= FILE_READ_ATTRIBUTES;
++ retry_without_read_attributes = true;
++ }
+ smb2_oplock = SMB2_OPLOCK_LEVEL_BATCH;
+
+ rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, smb2_data, NULL, &err_iov,
+ &err_buftype);
++ if (rc == -EACCES && retry_without_read_attributes) {
++ oparms->desired_access &= ~FILE_READ_ATTRIBUTES;
++ rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, smb2_data, NULL, &err_iov,
++ &err_buftype);
++ }
+ if (rc && data) {
+ struct smb2_hdr *hdr = err_iov.iov_base;
+
+--
+2.39.5
+
--- /dev/null
+From 8da7c0a2c40b8465a0460f463748009216f92eb7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 12 Feb 2025 17:52:19 +0900
+Subject: cifs: add validation check for the fields in smb_aces
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit eeb827f2922eb07ffbf7d53569cc95b38272646f ]
+
+cifs.ko is missing validation check when accessing smb_aces.
+This patch add validation check for the fields in smb_aces.
+
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/client/cifsacl.c | 17 ++++++++++++++++-
+ 1 file changed, 16 insertions(+), 1 deletion(-)
+
+diff --git a/fs/smb/client/cifsacl.c b/fs/smb/client/cifsacl.c
+index 64bd68f750f84..f9d577f2d59bb 100644
+--- a/fs/smb/client/cifsacl.c
++++ b/fs/smb/client/cifsacl.c
+@@ -811,7 +811,23 @@ static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl,
+ return;
+
+ for (i = 0; i < num_aces; ++i) {
++ if (end_of_acl - acl_base < acl_size)
++ break;
++
+ ppace[i] = (struct smb_ace *) (acl_base + acl_size);
++ acl_base = (char *)ppace[i];
++ acl_size = offsetof(struct smb_ace, sid) +
++ offsetof(struct smb_sid, sub_auth);
++
++ if (end_of_acl - acl_base < acl_size ||
++ ppace[i]->sid.num_subauth == 0 ||
++ ppace[i]->sid.num_subauth > SID_MAX_SUB_AUTHORITIES ||
++ (end_of_acl - acl_base <
++ acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth) ||
++ (le16_to_cpu(ppace[i]->size) <
++ acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth))
++ break;
++
+ #ifdef CONFIG_CIFS_DEBUG2
+ dump_ace(ppace[i], end_of_acl);
+ #endif
+@@ -855,7 +871,6 @@ static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl,
+ (void *)ppace[i],
+ sizeof(struct smb_ace)); */
+
+- acl_base = (char *)ppace[i];
+ acl_size = le16_to_cpu(ppace[i]->size);
+ }
+
+--
+2.39.5
+
--- /dev/null
+From 6bd7988657340114d49927daacb198b872fcbe69 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 19 Oct 2024 13:34:18 +0200
+Subject: cifs: Check if server supports reparse points before using them
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Pali Rohár <pali@kernel.org>
+
+[ Upstream commit 6c06be908ca190e2d8feae1cf452d78598cd0b94 ]
+
+Do not attempt to query or create reparse point when server fs does not
+support it. This will prevent creating unusable empty object on the server.
+
+Signed-off-by: Pali Rohár <pali@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/client/cifssmb.c | 3 +++
+ fs/smb/client/link.c | 3 ++-
+ fs/smb/client/smb2inode.c | 8 ++++++++
+ fs/smb/client/smb2ops.c | 4 ++--
+ 4 files changed, 15 insertions(+), 3 deletions(-)
+
+diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c
+index e90811f321944..53e3e8282cb2a 100644
+--- a/fs/smb/client/cifssmb.c
++++ b/fs/smb/client/cifssmb.c
+@@ -2725,6 +2725,9 @@ int cifs_query_reparse_point(const unsigned int xid,
+ if (cap_unix(tcon->ses))
+ return -EOPNOTSUPP;
+
++ if (!(le32_to_cpu(tcon->fsAttrInfo.Attributes) & FILE_SUPPORTS_REPARSE_POINTS))
++ return -EOPNOTSUPP;
++
+ oparms = (struct cifs_open_parms) {
+ .tcon = tcon,
+ .cifs_sb = cifs_sb,
+diff --git a/fs/smb/client/link.c b/fs/smb/client/link.c
+index 34a026243287f..769752ad2c5ce 100644
+--- a/fs/smb/client/link.c
++++ b/fs/smb/client/link.c
+@@ -643,7 +643,8 @@ cifs_symlink(struct mnt_idmap *idmap, struct inode *inode,
+ case CIFS_SYMLINK_TYPE_NATIVE:
+ case CIFS_SYMLINK_TYPE_NFS:
+ case CIFS_SYMLINK_TYPE_WSL:
+- if (server->ops->create_reparse_symlink) {
++ if (server->ops->create_reparse_symlink &&
++ (le32_to_cpu(pTcon->fsAttrInfo.Attributes) & FILE_SUPPORTS_REPARSE_POINTS)) {
+ rc = server->ops->create_reparse_symlink(xid, inode,
+ direntry,
+ pTcon,
+diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c
+index 826b57a5a2a8d..e9fd3e204a6f4 100644
+--- a/fs/smb/client/smb2inode.c
++++ b/fs/smb/client/smb2inode.c
+@@ -1273,6 +1273,14 @@ struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data,
+ int rc;
+ int i;
+
++ /*
++ * If server filesystem does not support reparse points then do not
++ * attempt to create reparse point. This will prevent creating unusable
++ * empty object on the server.
++ */
++ if (!(le32_to_cpu(tcon->fsAttrInfo.Attributes) & FILE_SUPPORTS_REPARSE_POINTS))
++ return ERR_PTR(-EOPNOTSUPP);
++
+ oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
+ SYNCHRONIZE | DELETE |
+ FILE_READ_ATTRIBUTES |
+diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
+index 6795970d4de6e..fbb3686292134 100644
+--- a/fs/smb/client/smb2ops.c
++++ b/fs/smb/client/smb2ops.c
+@@ -5237,7 +5237,7 @@ static int smb2_make_node(unsigned int xid, struct inode *inode,
+ const char *full_path, umode_t mode, dev_t dev)
+ {
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+- int rc;
++ int rc = -EOPNOTSUPP;
+
+ /*
+ * Check if mounted with mount parm 'sfu' mount parm.
+@@ -5248,7 +5248,7 @@ static int smb2_make_node(unsigned int xid, struct inode *inode,
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
+ rc = cifs_sfu_make_node(xid, inode, dentry, tcon,
+ full_path, mode, dev);
+- } else {
++ } else if (le32_to_cpu(tcon->fsAttrInfo.Attributes) & FILE_SUPPORTS_REPARSE_POINTS) {
+ rc = smb2_mknod_reparse(xid, inode, dentry, tcon,
+ full_path, mode, dev);
+ }
+--
+2.39.5
+
--- /dev/null
+From f3854f7e9d4f1136b16f3327fa1ac3bda34a2e9e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 17 Nov 2024 11:50:18 +0100
+Subject: cifs: Fix access_flags_to_smbopen_mode
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Pali Rohár <pali@kernel.org>
+
+[ Upstream commit 6aa9f1c9cd09c1c39a35da4fe5f43446ec18ce1e ]
+
+When converting access_flags to SMBOPEN mode, check for all possible access
+flags, not only GENERIC_READ and GENERIC_WRITE flags.
+
+Signed-off-by: Pali Rohár <pali@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/client/cifssmb.c | 32 ++++++++++++++++++++++++--------
+ 1 file changed, 24 insertions(+), 8 deletions(-)
+
+diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c
+index 4fc9485c5d91a..c2abe79f0dd3b 100644
+--- a/fs/smb/client/cifssmb.c
++++ b/fs/smb/client/cifssmb.c
+@@ -1038,15 +1038,31 @@ static __u16 convert_disposition(int disposition)
+ static int
+ access_flags_to_smbopen_mode(const int access_flags)
+ {
+- int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
+-
+- if (masked_flags == GENERIC_READ)
+- return SMBOPEN_READ;
+- else if (masked_flags == GENERIC_WRITE)
++ /*
++ * SYSTEM_SECURITY grants both read and write access to SACL, treat is as read/write.
++ * MAXIMUM_ALLOWED grants as many access as possible, so treat it as read/write too.
++ * SYNCHRONIZE as is does not grant any specific access, so do not check its mask.
++ * If only SYNCHRONIZE bit is specified then fallback to read access.
++ */
++ bool with_write_flags = access_flags & (FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_WRITE_EA |
++ FILE_DELETE_CHILD | FILE_WRITE_ATTRIBUTES | DELETE |
++ WRITE_DAC | WRITE_OWNER | SYSTEM_SECURITY |
++ MAXIMUM_ALLOWED | GENERIC_WRITE | GENERIC_ALL);
++ bool with_read_flags = access_flags & (FILE_READ_DATA | FILE_READ_EA | FILE_EXECUTE |
++ FILE_READ_ATTRIBUTES | READ_CONTROL |
++ SYSTEM_SECURITY | MAXIMUM_ALLOWED | GENERIC_ALL |
++ GENERIC_EXECUTE | GENERIC_READ);
++ bool with_execute_flags = access_flags & (FILE_EXECUTE | MAXIMUM_ALLOWED | GENERIC_ALL |
++ GENERIC_EXECUTE);
++
++ if (with_write_flags && with_read_flags)
++ return SMBOPEN_READWRITE;
++ else if (with_write_flags)
+ return SMBOPEN_WRITE;
+-
+- /* just go for read/write */
+- return SMBOPEN_READWRITE;
++ else if (with_execute_flags)
++ return SMBOPEN_EXECUTE;
++ else
++ return SMBOPEN_READ;
+ }
+
+ int
+--
+2.39.5
+
--- /dev/null
+From 394091d87f4b52b7c33c8043cbd90467f1c4e9cb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Dec 2024 20:34:18 +0100
+Subject: cifs: Fix and improve cifs_query_path_info() and
+ cifs_query_file_info()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Pali Rohár <pali@kernel.org>
+
+[ Upstream commit 1041c117a2c33cdffc4f695ac4b469e9124d24d5 ]
+
+When CAP_NT_SMBS was not negotiated then do not issue CIFSSMBQPathInfo()
+and CIFSSMBQFileInfo() commands. CIFSSMBQPathInfo() is not supported by
+non-NT Win9x SMB server and CIFSSMBQFileInfo() returns from Win9x SMB
+server bogus data in Attributes field (for example lot of files are marked
+as reparse points, even Win9x does not support them and read-only bit is
+not marked for read-only files). Correct information is returned by
+CIFSFindFirst() or SMBQueryInformation() command.
+
+So as a fallback in cifs_query_path_info() function use CIFSFindFirst()
+with SMB_FIND_FILE_FULL_DIRECTORY_INFO level which is supported by both NT
+and non-NT servers and as a last option use SMBQueryInformation() as it was
+before.
+
+And in function cifs_query_file_info() immediately returns -EOPNOTSUPP when
+not communicating with NT server. Client then revalidate inode entry by the
+cifs_query_path_info() call, which is working fine. So fstat() syscall on
+already opened file will receive correct information.
+
+Note that both fallback functions in non-UNICODE mode expands wildcards.
+Therefore those fallback functions cannot be used on paths which contain
+SMB wildcard characters (* ? " > <).
+
+CIFSFindFirst() returns all 4 time attributes as opposite of
+SMBQueryInformation() which returns only one.
+
+With this change it is possible to query all 4 times attributes from Win9x
+server and at the same time, client minimize sending of unsupported
+commands to server.
+
+Signed-off-by: Pali Rohár <pali@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/client/smb1ops.c | 103 ++++++++++++++++++++++++++++++++++++----
+ 1 file changed, 95 insertions(+), 8 deletions(-)
+
+diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c
+index 73a689b4ccdff..98f52f705cf6d 100644
+--- a/fs/smb/client/smb1ops.c
++++ b/fs/smb/client/smb1ops.c
+@@ -541,24 +541,104 @@ static int cifs_query_path_info(const unsigned int xid,
+ const char *full_path,
+ struct cifs_open_info_data *data)
+ {
+- int rc;
++ int rc = -EOPNOTSUPP;
+ FILE_ALL_INFO fi = {};
++ struct cifs_search_info search_info = {};
++ bool non_unicode_wildcard = false;
+
+ data->reparse_point = false;
+ data->adjust_tz = false;
+
+- /* could do find first instead but this returns more info */
+- rc = CIFSSMBQPathInfo(xid, tcon, full_path, &fi, 0 /* not legacy */, cifs_sb->local_nls,
+- cifs_remap(cifs_sb));
+ /*
+- * BB optimize code so we do not make the above call when server claims
+- * no NT SMB support and the above call failed at least once - set flag
+- * in tcon or mount.
++ * First try CIFSSMBQPathInfo() function which returns more info
++ * (NumberOfLinks) than CIFSFindFirst() fallback function.
++ * Some servers like Win9x do not support SMB_QUERY_FILE_ALL_INFO over
++ * TRANS2_QUERY_PATH_INFORMATION, but supports it with filehandle over
++ * TRANS2_QUERY_FILE_INFORMATION (function CIFSSMBQFileInfo(). But SMB
++ * Open command on non-NT servers works only for files, does not work
++ * for directories. And moreover Win9x SMB server returns bogus data in
++ * SMB_QUERY_FILE_ALL_INFO Attributes field. So for non-NT servers,
++ * do not even use CIFSSMBQPathInfo() or CIFSSMBQFileInfo() function.
++ */
++ if (tcon->ses->capabilities & CAP_NT_SMBS)
++ rc = CIFSSMBQPathInfo(xid, tcon, full_path, &fi, 0 /* not legacy */,
++ cifs_sb->local_nls, cifs_remap(cifs_sb));
++
++ /*
++ * Non-UNICODE variant of fallback functions below expands wildcards,
++ * so they cannot be used for querying paths with wildcard characters.
+ */
+- if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
++ if (rc && !(tcon->ses->capabilities & CAP_UNICODE) && strpbrk(full_path, "*?\"><"))
++ non_unicode_wildcard = true;
++
++ /*
++ * Then fallback to CIFSFindFirst() which works also with non-NT servers
++ * but does not does not provide NumberOfLinks.
++ */
++ if ((rc == -EOPNOTSUPP || rc == -EINVAL) &&
++ !non_unicode_wildcard) {
++ if (!(tcon->ses->capabilities & tcon->ses->server->vals->cap_nt_find))
++ search_info.info_level = SMB_FIND_FILE_INFO_STANDARD;
++ else
++ search_info.info_level = SMB_FIND_FILE_FULL_DIRECTORY_INFO;
++ rc = CIFSFindFirst(xid, tcon, full_path, cifs_sb, NULL,
++ CIFS_SEARCH_CLOSE_ALWAYS | CIFS_SEARCH_CLOSE_AT_END,
++ &search_info, false);
++ if (rc == 0) {
++ if (!(tcon->ses->capabilities & tcon->ses->server->vals->cap_nt_find)) {
++ FIND_FILE_STANDARD_INFO *di;
++ int offset = tcon->ses->server->timeAdj;
++
++ di = (FIND_FILE_STANDARD_INFO *)search_info.srch_entries_start;
++ fi.CreationTime = cpu_to_le64(cifs_UnixTimeToNT(cnvrtDosUnixTm(
++ di->CreationDate, di->CreationTime, offset)));
++ fi.LastAccessTime = cpu_to_le64(cifs_UnixTimeToNT(cnvrtDosUnixTm(
++ di->LastAccessDate, di->LastAccessTime, offset)));
++ fi.LastWriteTime = cpu_to_le64(cifs_UnixTimeToNT(cnvrtDosUnixTm(
++ di->LastWriteDate, di->LastWriteTime, offset)));
++ fi.ChangeTime = fi.LastWriteTime;
++ fi.Attributes = cpu_to_le32(le16_to_cpu(di->Attributes));
++ fi.AllocationSize = cpu_to_le64(le32_to_cpu(di->AllocationSize));
++ fi.EndOfFile = cpu_to_le64(le32_to_cpu(di->DataSize));
++ } else {
++ FILE_FULL_DIRECTORY_INFO *di;
++
++ di = (FILE_FULL_DIRECTORY_INFO *)search_info.srch_entries_start;
++ fi.CreationTime = di->CreationTime;
++ fi.LastAccessTime = di->LastAccessTime;
++ fi.LastWriteTime = di->LastWriteTime;
++ fi.ChangeTime = di->ChangeTime;
++ fi.Attributes = di->ExtFileAttributes;
++ fi.AllocationSize = di->AllocationSize;
++ fi.EndOfFile = di->EndOfFile;
++ fi.EASize = di->EaSize;
++ }
++ fi.NumberOfLinks = cpu_to_le32(1);
++ fi.DeletePending = 0;
++ fi.Directory = !!(le32_to_cpu(fi.Attributes) & ATTR_DIRECTORY);
++ cifs_buf_release(search_info.ntwrk_buf_start);
++ } else if (!full_path[0]) {
++ /*
++ * CIFSFindFirst() does not work on root path if the
++ * root path was exported on the server from the top
++ * level path (drive letter).
++ */
++ rc = -EOPNOTSUPP;
++ }
++ }
++
++ /*
++ * If everything failed then fallback to the legacy SMB command
++ * SMB_COM_QUERY_INFORMATION which works with all servers, but
++ * provide just few information.
++ */
++ if ((rc == -EOPNOTSUPP || rc == -EINVAL) && !non_unicode_wildcard) {
+ rc = SMBQueryInformation(xid, tcon, full_path, &fi, cifs_sb->local_nls,
+ cifs_remap(cifs_sb));
+ data->adjust_tz = true;
++ } else if ((rc == -EOPNOTSUPP || rc == -EINVAL) && non_unicode_wildcard) {
++ /* Path with non-UNICODE wildcard character cannot exist. */
++ rc = -ENOENT;
+ }
+
+ if (!rc) {
+@@ -637,6 +717,13 @@ static int cifs_query_file_info(const unsigned int xid, struct cifs_tcon *tcon,
+ int rc;
+ FILE_ALL_INFO fi = {};
+
++ /*
++ * CIFSSMBQFileInfo() for non-NT servers returns bogus data in
++ * Attributes fields. So do not use this command for non-NT servers.
++ */
++ if (!(tcon->ses->capabilities & CAP_NT_SMBS))
++ return -EOPNOTSUPP;
++
+ if (cfile->symlink_target) {
+ data->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
+ if (!data->symlink_target)
+--
+2.39.5
+
--- /dev/null
+From a869d57f7a2aae1be05417bed98262fd2799d01a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Dec 2024 21:32:39 +0100
+Subject: cifs: Fix changing times and read-only attr over SMB1
+ smb_set_file_info() function
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Pali Rohár <pali@kernel.org>
+
+[ Upstream commit f122121796f91168d0894c2710b8dd71330a34f8 ]
+
+Function CIFSSMBSetPathInfo() is not supported by non-NT servers and
+returns error. Fallback code via open filehandle and CIFSSMBSetFileInfo()
+does not work neither because CIFS_open() works also only on NT server.
+
+Therefore currently the whole smb_set_file_info() function as a SMB1
+callback for the ->set_file_info() does not work with older non-NT SMB
+servers, like Win9x and others.
+
+This change implements fallback code in smb_set_file_info() which will
+works with any server and allows to change time values and also to set or
+clear read-only attributes.
+
+To make existing fallback code via CIFSSMBSetFileInfo() working with also
+non-NT servers, it is needed to change open function from CIFS_open()
+(which is NT specific) to cifs_open_file() which works with any server
+(this is just a open wrapper function which choose the correct open
+function supported by the server).
+
+CIFSSMBSetFileInfo() is working also on non-NT servers, but zero time
+values are not treated specially. So first it is needed to fill all time
+values if some of them are missing, via cifs_query_path_info() call.
+
+There is another issue, opening file in write-mode (needed for changing
+attributes) is not possible when the file has read-only attribute set.
+The only option how to clear read-only attribute is via SMB_COM_SETATTR
+command. And opening directory is not possible neither and here the
+SMB_COM_SETATTR command is the only option how to change attributes.
+And CIFSSMBSetFileInfo() does not honor setting read-only attribute, so
+for setting is also needed to use SMB_COM_SETATTR command.
+
+Existing code in cifs_query_path_info() is already using SMB_COM_GETATTR as
+a fallback code path (function SMBQueryInformation()), so introduce a new
+function SMBSetInformation which will implement SMB_COM_SETATTR command.
+
+My testing showed that Windows XP SMB1 client is also using SMB_COM_SETATTR
+command for setting or clearing read-only attribute against non-NT server.
+So this can prove that this is the correct way how to do it.
+
+With this change it is possible set all 4 time values and all attributes,
+including clearing and setting read-only bit on non-NT SMB servers.
+Tested against Win98 SMB1 server.
+
+This change fixes "touch" command which was failing when called on existing
+file. And fixes also "chmod +w" and "chmod -w" commands which were also
+failing (as they are changing read-only attribute).
+
+Note that this change depends on following change
+"cifs: Improve cifs_query_path_info() and cifs_query_file_info()"
+as it require to query all 4 time attribute values.
+
+Signed-off-by: Pali Rohár <pali@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/client/cifspdu.h | 5 +-
+ fs/smb/client/cifsproto.h | 4 ++
+ fs/smb/client/cifssmb.c | 57 +++++++++++++++++++
+ fs/smb/client/smb1ops.c | 112 +++++++++++++++++++++++++++++++++++---
+ 4 files changed, 166 insertions(+), 12 deletions(-)
+
+diff --git a/fs/smb/client/cifspdu.h b/fs/smb/client/cifspdu.h
+index 48d0d6f439cf4..cf9ca7e49b8bc 100644
+--- a/fs/smb/client/cifspdu.h
++++ b/fs/smb/client/cifspdu.h
+@@ -1266,10 +1266,9 @@ typedef struct smb_com_query_information_rsp {
+ typedef struct smb_com_setattr_req {
+ struct smb_hdr hdr; /* wct = 8 */
+ __le16 attr;
+- __le16 time_low;
+- __le16 time_high;
++ __le32 last_write_time;
+ __le16 reserved[5]; /* must be zero */
+- __u16 ByteCount;
++ __le16 ByteCount;
+ __u8 BufferFormat; /* 4 = ASCII */
+ unsigned char fileName[];
+ } __attribute__((packed)) SETATTR_REQ;
+diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h
+index 1609ca825d825..2dd5a485a1e04 100644
+--- a/fs/smb/client/cifsproto.h
++++ b/fs/smb/client/cifsproto.h
+@@ -395,6 +395,10 @@ extern int CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon);
+ extern int CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
+ struct kstatfs *FSData);
+
++extern int SMBSetInformation(const unsigned int xid, struct cifs_tcon *tcon,
++ const char *fileName, __le32 attributes, __le64 write_time,
++ const struct nls_table *nls_codepage,
++ struct cifs_sb_info *cifs_sb);
+ extern int CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *fileName, const FILE_BASIC_INFO *data,
+ const struct nls_table *nls_codepage,
+diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c
+index 53e3e8282cb2a..4059550859a9b 100644
+--- a/fs/smb/client/cifssmb.c
++++ b/fs/smb/client/cifssmb.c
+@@ -5168,6 +5168,63 @@ CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
+ return rc;
+ }
+
++int
++SMBSetInformation(const unsigned int xid, struct cifs_tcon *tcon,
++ const char *fileName, __le32 attributes, __le64 write_time,
++ const struct nls_table *nls_codepage,
++ struct cifs_sb_info *cifs_sb)
++{
++ SETATTR_REQ *pSMB;
++ SETATTR_RSP *pSMBr;
++ struct timespec64 ts;
++ int bytes_returned;
++ int name_len;
++ int rc;
++
++ cifs_dbg(FYI, "In %s path %s\n", __func__, fileName);
++
++retry:
++ rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
++ (void **) &pSMBr);
++ if (rc)
++ return rc;
++
++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
++ name_len =
++ cifsConvertToUTF16((__le16 *) pSMB->fileName,
++ fileName, PATH_MAX, nls_codepage,
++ cifs_remap(cifs_sb));
++ name_len++; /* trailing null */
++ name_len *= 2;
++ } else {
++ name_len = copy_path_name(pSMB->fileName, fileName);
++ }
++ /* Only few attributes can be set by this command, others are not accepted by Win9x. */
++ pSMB->attr = cpu_to_le16(le32_to_cpu(attributes) &
++ (ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_ARCHIVE));
++ /* Zero write time value (in both NT and SETATTR formats) means to not change it. */
++ if (le64_to_cpu(write_time) != 0) {
++ ts = cifs_NTtimeToUnix(write_time);
++ pSMB->last_write_time = cpu_to_le32(ts.tv_sec);
++ }
++ pSMB->BufferFormat = 0x04;
++ name_len++; /* account for buffer type byte */
++ inc_rfc1001_len(pSMB, (__u16)name_len);
++ pSMB->ByteCount = cpu_to_le16(name_len);
++
++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
++ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
++ if (rc)
++ cifs_dbg(FYI, "Send error in %s = %d\n", __func__, rc);
++
++ cifs_buf_release(pSMB);
++
++ if (rc == -EAGAIN)
++ goto retry;
++
++ return rc;
++}
++
+ /* Some legacy servers such as NT4 require that the file times be set on
+ an open handle, rather than by pathname - this is awkward due to
+ potential access conflicts on the open, but it is unavoidable for these
+diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c
+index 98f52f705cf6d..47c815f34bc36 100644
+--- a/fs/smb/client/smb1ops.c
++++ b/fs/smb/client/smb1ops.c
+@@ -894,6 +894,9 @@ smb_set_file_info(struct inode *inode, const char *full_path,
+ struct cifs_fid fid;
+ struct cifs_open_parms oparms;
+ struct cifsFileInfo *open_file;
++ FILE_BASIC_INFO new_buf;
++ struct cifs_open_info_data query_data;
++ __le64 write_time = buf->LastWriteTime;
+ struct cifsInodeInfo *cinode = CIFS_I(inode);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ struct tcon_link *tlink = NULL;
+@@ -901,20 +904,58 @@ smb_set_file_info(struct inode *inode, const char *full_path,
+
+ /* if the file is already open for write, just use that fileid */
+ open_file = find_writable_file(cinode, FIND_WR_FSUID_ONLY);
++
+ if (open_file) {
+ fid.netfid = open_file->fid.netfid;
+ netpid = open_file->pid;
+ tcon = tlink_tcon(open_file->tlink);
+- goto set_via_filehandle;
++ } else {
++ tlink = cifs_sb_tlink(cifs_sb);
++ if (IS_ERR(tlink)) {
++ rc = PTR_ERR(tlink);
++ tlink = NULL;
++ goto out;
++ }
++ tcon = tlink_tcon(tlink);
+ }
+
+- tlink = cifs_sb_tlink(cifs_sb);
+- if (IS_ERR(tlink)) {
+- rc = PTR_ERR(tlink);
+- tlink = NULL;
+- goto out;
++ /*
++ * Non-NT servers interprets zero time value in SMB_SET_FILE_BASIC_INFO
++ * over TRANS2_SET_FILE_INFORMATION as a valid time value. NT servers
++ * interprets zero time value as do not change existing value on server.
++ * API of ->set_file_info() callback expects that zero time value has
++ * the NT meaning - do not change. Therefore if server is non-NT and
++ * some time values in "buf" are zero, then fetch missing time values.
++ */
++ if (!(tcon->ses->capabilities & CAP_NT_SMBS) &&
++ (!buf->CreationTime || !buf->LastAccessTime ||
++ !buf->LastWriteTime || !buf->ChangeTime)) {
++ rc = cifs_query_path_info(xid, tcon, cifs_sb, full_path, &query_data);
++ if (rc) {
++ if (open_file) {
++ cifsFileInfo_put(open_file);
++ open_file = NULL;
++ }
++ goto out;
++ }
++ /*
++ * Original write_time from buf->LastWriteTime is preserved
++ * as SMBSetInformation() interprets zero as do not change.
++ */
++ new_buf = *buf;
++ buf = &new_buf;
++ if (!buf->CreationTime)
++ buf->CreationTime = query_data.fi.CreationTime;
++ if (!buf->LastAccessTime)
++ buf->LastAccessTime = query_data.fi.LastAccessTime;
++ if (!buf->LastWriteTime)
++ buf->LastWriteTime = query_data.fi.LastWriteTime;
++ if (!buf->ChangeTime)
++ buf->ChangeTime = query_data.fi.ChangeTime;
+ }
+- tcon = tlink_tcon(tlink);
++
++ if (open_file)
++ goto set_via_filehandle;
+
+ rc = CIFSSMBSetPathInfo(xid, tcon, full_path, buf, cifs_sb->local_nls,
+ cifs_sb);
+@@ -935,8 +976,45 @@ smb_set_file_info(struct inode *inode, const char *full_path,
+ .fid = &fid,
+ };
+
+- cifs_dbg(FYI, "calling SetFileInfo since SetPathInfo for times not supported by this server\n");
+- rc = CIFS_open(xid, &oparms, &oplock, NULL);
++ if (S_ISDIR(inode->i_mode) && !(tcon->ses->capabilities & CAP_NT_SMBS)) {
++ /* Opening directory path is not possible on non-NT servers. */
++ rc = -EOPNOTSUPP;
++ } else {
++ /*
++ * Use cifs_open_file() instead of CIFS_open() as the
++ * cifs_open_file() selects the correct function which
++ * works also on non-NT servers.
++ */
++ rc = cifs_open_file(xid, &oparms, &oplock, NULL);
++ /*
++ * Opening path for writing on non-NT servers is not
++ * possible when the read-only attribute is already set.
++ * Non-NT server in this case returns -EACCES. For those
++ * servers the only possible way how to clear the read-only
++ * bit is via SMB_COM_SETATTR command.
++ */
++ if (rc == -EACCES &&
++ (cinode->cifsAttrs & ATTR_READONLY) &&
++ le32_to_cpu(buf->Attributes) != 0 && /* 0 = do not change attrs */
++ !(le32_to_cpu(buf->Attributes) & ATTR_READONLY) &&
++ !(tcon->ses->capabilities & CAP_NT_SMBS))
++ rc = -EOPNOTSUPP;
++ }
++
++ /* Fallback to SMB_COM_SETATTR command when absolutelty needed. */
++ if (rc == -EOPNOTSUPP) {
++ cifs_dbg(FYI, "calling SetInformation since SetPathInfo for attrs/times not supported by this server\n");
++ rc = SMBSetInformation(xid, tcon, full_path,
++ buf->Attributes != 0 ? buf->Attributes : cpu_to_le32(cinode->cifsAttrs),
++ write_time,
++ cifs_sb->local_nls, cifs_sb);
++ if (rc == 0)
++ cinode->cifsAttrs = le32_to_cpu(buf->Attributes);
++ else
++ rc = -EACCES;
++ goto out;
++ }
++
+ if (rc != 0) {
+ if (rc == -EIO)
+ rc = -EINVAL;
+@@ -944,6 +1022,7 @@ smb_set_file_info(struct inode *inode, const char *full_path,
+ }
+
+ netpid = current->tgid;
++ cifs_dbg(FYI, "calling SetFileInfo since SetPathInfo for attrs/times not supported by this server\n");
+
+ set_via_filehandle:
+ rc = CIFSSMBSetFileInfo(xid, tcon, buf, fid.netfid, netpid);
+@@ -954,6 +1033,21 @@ smb_set_file_info(struct inode *inode, const char *full_path,
+ CIFSSMBClose(xid, tcon, fid.netfid);
+ else
+ cifsFileInfo_put(open_file);
++
++ /*
++ * Setting the read-only bit is not honered on non-NT servers when done
++ * via open-semantics. So for setting it, use SMB_COM_SETATTR command.
++ * This command works only after the file is closed, so use it only when
++ * operation was called without the filehandle.
++ */
++ if (open_file == NULL &&
++ !(tcon->ses->capabilities & CAP_NT_SMBS) &&
++ le32_to_cpu(buf->Attributes) & ATTR_READONLY) {
++ SMBSetInformation(xid, tcon, full_path,
++ buf->Attributes,
++ 0 /* do not change write time */,
++ cifs_sb->local_nls, cifs_sb);
++ }
+ out:
+ if (tlink != NULL)
+ cifs_put_tlink(tlink);
+--
+2.39.5
+
--- /dev/null
+From 6a97dfe0fba87dea589c74a6f355d7ec02fc063c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 30 Oct 2024 22:46:20 +0100
+Subject: cifs: Fix establishing NetBIOS session for SMB2+ connection
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Pali Rohár <pali@kernel.org>
+
+[ Upstream commit 781802aa5a5950f99899f13ff9d760f5db81d36d ]
+
+Function ip_rfc1001_connect() which establish NetBIOS session for SMB
+connections, currently uses smb_send() function for sending NetBIOS Session
+Request packet. This function expects that the passed buffer is SMB packet
+and for SMB2+ connections it mangles packet header, which breaks prepared
+NetBIOS Session Request packet. Result is that this function send garbage
+packet for SMB2+ connection, which SMB2+ server cannot parse. That function
+is not mangling packets for SMB1 connections, so it somehow works for SMB1.
+
+Fix this problem and instead of smb_send(), use smb_send_kvec() function
+which does not mangle prepared packet, this function send them as is. Just
+API of this function takes struct msghdr (kvec) instead of packet buffer.
+
+[MS-SMB2] specification allows SMB2 protocol to use NetBIOS as a transport
+protocol. NetBIOS can be used over TCP via port 139. So this is a valid
+configuration, just not so common. And even recent Windows versions (e.g.
+Windows Server 2022) still supports this configuration: SMB over TCP port
+139, including for modern SMB2 and SMB3 dialects.
+
+This change fixes SMB2 and SMB3 connections over TCP port 139 which
+requires establishing of NetBIOS session. Tested that this change fixes
+establishing of SMB2 and SMB3 connections with Windows Server 2022.
+
+Signed-off-by: Pali Rohár <pali@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/client/cifsproto.h | 3 +++
+ fs/smb/client/connect.c | 20 +++++++++++++++-----
+ fs/smb/client/transport.c | 2 +-
+ 3 files changed, 19 insertions(+), 6 deletions(-)
+
+diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h
+index 278092a15f890..1609ca825d825 100644
+--- a/fs/smb/client/cifsproto.h
++++ b/fs/smb/client/cifsproto.h
+@@ -31,6 +31,9 @@ extern void cifs_small_buf_release(void *);
+ extern void free_rsp_buf(int, void *);
+ extern int smb_send(struct TCP_Server_Info *, struct smb_hdr *,
+ unsigned int /* length */);
++extern int smb_send_kvec(struct TCP_Server_Info *server,
++ struct msghdr *msg,
++ size_t *sent);
+ extern unsigned int _get_xid(void);
+ extern void _free_xid(unsigned int);
+ #define get_xid() \
+diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
+index 92685fc675b59..22f29d2725928 100644
+--- a/fs/smb/client/connect.c
++++ b/fs/smb/client/connect.c
+@@ -3028,8 +3028,10 @@ ip_rfc1001_connect(struct TCP_Server_Info *server)
+ * sessinit is sent but no second negprot
+ */
+ struct rfc1002_session_packet req = {};
+- struct smb_hdr *smb_buf = (struct smb_hdr *)&req;
++ struct msghdr msg = {};
++ struct kvec iov = {};
+ unsigned int len;
++ size_t sent;
+
+ req.trailer.session_req.called_len = sizeof(req.trailer.session_req.called_name);
+
+@@ -3058,10 +3060,18 @@ ip_rfc1001_connect(struct TCP_Server_Info *server)
+ * As per rfc1002, @len must be the number of bytes that follows the
+ * length field of a rfc1002 session request payload.
+ */
+- len = sizeof(req) - offsetof(struct rfc1002_session_packet, trailer.session_req);
++ len = sizeof(req.trailer.session_req);
++ req.type = RFC1002_SESSION_REQUEST;
++ req.flags = 0;
++ req.length = cpu_to_be16(len);
++ len += offsetof(typeof(req), trailer.session_req);
++ iov.iov_base = &req;
++ iov.iov_len = len;
++ iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, &iov, 1, len);
++ rc = smb_send_kvec(server, &msg, &sent);
++ if (rc < 0 || len != sent)
++ return (rc == -EINTR || rc == -EAGAIN) ? rc : -ECONNABORTED;
+
+- smb_buf->smb_buf_length = cpu_to_be32((RFC1002_SESSION_REQUEST << 24) | len);
+- rc = smb_send(server, smb_buf, len);
+ /*
+ * RFC1001 layer in at least one server requires very short break before
+ * negprot presumably because not expecting negprot to follow so fast.
+@@ -3070,7 +3080,7 @@ ip_rfc1001_connect(struct TCP_Server_Info *server)
+ */
+ usleep_range(1000, 2000);
+
+- return rc;
++ return 0;
+ }
+
+ static int
+diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c
+index 0dc80959ce488..03434dbe9374c 100644
+--- a/fs/smb/client/transport.c
++++ b/fs/smb/client/transport.c
+@@ -179,7 +179,7 @@ delete_mid(struct mid_q_entry *mid)
+ * Our basic "send data to server" function. Should be called with srv_mutex
+ * held. The caller is responsible for handling the results.
+ */
+-static int
++int
+ smb_send_kvec(struct TCP_Server_Info *server, struct msghdr *smb_msg,
+ size_t *sent)
+ {
+--
+2.39.5
+
--- /dev/null
+From 63b82974ec2080d666dc79e223853ae9f0098327 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 14 Oct 2024 13:47:04 +0200
+Subject: cifs: Fix getting DACL-only xattr system.cifs_acl and system.smb3_acl
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Pali Rohár <pali@kernel.org>
+
+[ Upstream commit ad9364a6835c45c52f47587ffbe0577bb7cd4c5b ]
+
+Currently ->get_acl() callback always create request for OWNER, GROUP and
+DACL, even when only DACLs was requested by user. Change API callback to
+request only information for which the caller asked. Therefore when only
+DACLs requested, then SMB client will prepare and send DACL-only request.
+
+This change fixes retrieving of "system.cifs_acl" and "system.smb3_acl"
+xattrs to contain only DACL structure as documented.
+
+Note that setting/changing of "system.cifs_acl" and "system.smb3_acl"
+xattrs already takes only DACL structure and ignores all other fields.
+
+Signed-off-by: Pali Rohár <pali@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/client/cifsacl.c | 4 ++--
+ fs/smb/client/cifssmb.c | 3 +--
+ fs/smb/client/smb2pdu.c | 4 +---
+ fs/smb/client/xattr.c | 15 +++++++++++----
+ 4 files changed, 15 insertions(+), 11 deletions(-)
+
+diff --git a/fs/smb/client/cifsacl.c b/fs/smb/client/cifsacl.c
+index f9d577f2d59bb..63b3b1290bed2 100644
+--- a/fs/smb/client/cifsacl.c
++++ b/fs/smb/client/cifsacl.c
+@@ -1565,7 +1565,7 @@ cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
+ int rc = 0;
+ struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
+ struct smb_version_operations *ops;
+- const u32 info = 0;
++ const u32 info = OWNER_SECINFO | GROUP_SECINFO | DACL_SECINFO;
+
+ cifs_dbg(NOISY, "converting ACL to mode for %s\n", path);
+
+@@ -1619,7 +1619,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
+ struct tcon_link *tlink;
+ struct smb_version_operations *ops;
+ bool mode_from_sid, id_from_sid;
+- const u32 info = 0;
++ const u32 info = OWNER_SECINFO | GROUP_SECINFO | DACL_SECINFO;
+ bool posix;
+
+ tlink = cifs_sb_tlink(cifs_sb);
+diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c
+index c2abe79f0dd3b..e90811f321944 100644
+--- a/fs/smb/client/cifssmb.c
++++ b/fs/smb/client/cifssmb.c
+@@ -3416,8 +3416,7 @@ CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
+ /* BB TEST with big acls that might need to be e.g. larger than 16K */
+ pSMB->MaxSetupCount = 0;
+ pSMB->Fid = fid; /* file handle always le */
+- pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
+- CIFS_ACL_DACL | info);
++ pSMB->AclFlags = cpu_to_le32(info);
+ pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
+ inc_rfc1001_len(pSMB, 11);
+ iov[0].iov_base = (char *)pSMB;
+diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
+index ed3ffcb80aef0..d080c777906b4 100644
+--- a/fs/smb/client/smb2pdu.c
++++ b/fs/smb/client/smb2pdu.c
+@@ -3910,12 +3910,10 @@ SMB2_query_acl(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_fid, u64 volatile_fid,
+ void **data, u32 *plen, u32 extra_info)
+ {
+- __u32 additional_info = OWNER_SECINFO | GROUP_SECINFO | DACL_SECINFO |
+- extra_info;
+ *plen = 0;
+
+ return query_info(xid, tcon, persistent_fid, volatile_fid,
+- 0, SMB2_O_INFO_SECURITY, additional_info,
++ 0, SMB2_O_INFO_SECURITY, extra_info,
+ SMB2_MAX_BUFFER_SIZE, MIN_SEC_DESC_LEN, data, plen);
+ }
+
+diff --git a/fs/smb/client/xattr.c b/fs/smb/client/xattr.c
+index 58a584f0b27e9..7d49f38f01f3e 100644
+--- a/fs/smb/client/xattr.c
++++ b/fs/smb/client/xattr.c
+@@ -320,10 +320,17 @@ static int cifs_xattr_get(const struct xattr_handler *handler,
+ if (pTcon->ses->server->ops->get_acl == NULL)
+ goto out; /* rc already EOPNOTSUPP */
+
+- if (handler->flags == XATTR_CIFS_NTSD_FULL) {
+- extra_info = SACL_SECINFO;
+- } else {
+- extra_info = 0;
++ switch (handler->flags) {
++ case XATTR_CIFS_NTSD_FULL:
++ extra_info = OWNER_SECINFO | GROUP_SECINFO | DACL_SECINFO | SACL_SECINFO;
++ break;
++ case XATTR_CIFS_NTSD:
++ extra_info = OWNER_SECINFO | GROUP_SECINFO | DACL_SECINFO;
++ break;
++ case XATTR_CIFS_ACL:
++ default:
++ extra_info = DACL_SECINFO;
++ break;
+ }
+ pacl = pTcon->ses->server->ops->get_acl(cifs_sb,
+ inode, full_path, &acllen, extra_info);
+--
+2.39.5
+
--- /dev/null
+From b320205ffd2b21bf54054fa2a02597c26f7369ae Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 2 Nov 2024 20:06:50 +0100
+Subject: cifs: Fix negotiate retry functionality
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Pali Rohár <pali@kernel.org>
+
+[ Upstream commit e94e882a6d69525c07589222cf3a6ff57ad12b5b ]
+
+SMB negotiate retry functionality in cifs_negotiate() is currently broken
+and does not work when doing socket reconnect. Caller of this function,
+which is cifs_negotiate_protocol() requires that tcpStatus after successful
+execution of negotiate callback stay in CifsInNegotiate. But if the
+CIFSSMBNegotiate() called from cifs_negotiate() fails due to connection
+issues then tcpStatus is changed as so repeated CIFSSMBNegotiate() call
+does not help.
+
+Fix this problem by moving retrying code from negotiate callback (which is
+either cifs_negotiate() or smb2_negotiate()) to cifs_negotiate_protocol()
+which is caller of those callbacks. This allows to properly handle and
+implement correct transistions between tcpStatus states as function
+cifs_negotiate_protocol() already handles it.
+
+With this change, cifs_negotiate_protocol() now handles also -EAGAIN error
+set by the RFC1002_NEGATIVE_SESSION_RESPONSE processing after reconnecting
+with NetBIOS session.
+
+Signed-off-by: Pali Rohár <pali@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/client/connect.c | 10 ++++++++++
+ fs/smb/client/smb1ops.c | 7 -------
+ fs/smb/client/smb2ops.c | 3 ---
+ 3 files changed, 10 insertions(+), 10 deletions(-)
+
+diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
+index cc9c912db8def..92685fc675b59 100644
+--- a/fs/smb/client/connect.c
++++ b/fs/smb/client/connect.c
+@@ -3922,11 +3922,13 @@ int
+ cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses,
+ struct TCP_Server_Info *server)
+ {
++ bool in_retry = false;
+ int rc = 0;
+
+ if (!server->ops->need_neg || !server->ops->negotiate)
+ return -ENOSYS;
+
++retry:
+ /* only send once per connect */
+ spin_lock(&server->srv_lock);
+ if (server->tcpStatus != CifsGood &&
+@@ -3946,6 +3948,14 @@ cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses,
+ spin_unlock(&server->srv_lock);
+
+ rc = server->ops->negotiate(xid, ses, server);
++ if (rc == -EAGAIN) {
++ /* Allow one retry attempt */
++ if (!in_retry) {
++ in_retry = true;
++ goto retry;
++ }
++ rc = -EHOSTDOWN;
++ }
+ if (rc == 0) {
+ spin_lock(&server->srv_lock);
+ if (server->tcpStatus == CifsInNegotiate)
+diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c
+index 808970e4a7142..e28cdaca47e12 100644
+--- a/fs/smb/client/smb1ops.c
++++ b/fs/smb/client/smb1ops.c
+@@ -426,13 +426,6 @@ cifs_negotiate(const unsigned int xid,
+ {
+ int rc;
+ rc = CIFSSMBNegotiate(xid, ses, server);
+- if (rc == -EAGAIN) {
+- /* retry only once on 1st time connection */
+- set_credits(server, 1);
+- rc = CIFSSMBNegotiate(xid, ses, server);
+- if (rc == -EAGAIN)
+- rc = -EHOSTDOWN;
+- }
+ return rc;
+ }
+
+diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
+index 7aeac8dd9a1d1..6f89e087629fe 100644
+--- a/fs/smb/client/smb2ops.c
++++ b/fs/smb/client/smb2ops.c
+@@ -464,9 +464,6 @@ smb2_negotiate(const unsigned int xid,
+ server->CurrentMid = 0;
+ spin_unlock(&server->mid_lock);
+ rc = SMB2_negotiate(xid, ses, server);
+- /* BB we probably don't need to retry with modern servers */
+- if (rc == -EAGAIN)
+- rc = -EHOSTDOWN;
+ return rc;
+ }
+
+--
+2.39.5
+
--- /dev/null
+From 613ab6a850103ba8fc664e9be0a6bd36307cbf2f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 28 Dec 2024 21:09:54 +0100
+Subject: cifs: Fix querying and creating MF symlinks over SMB1
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Pali Rohár <pali@kernel.org>
+
+[ Upstream commit 4236ac9fe5b8b42756070d4abfb76fed718e87c2 ]
+
+Old SMB1 servers without CAP_NT_SMBS do not support CIFS_open() function
+and instead SMBLegacyOpen() needs to be used. This logic is already handled
+in cifs_open_file() function, which is server->ops->open callback function.
+
+So for querying and creating MF symlinks use open callback function instead
+of CIFS_open() function directly.
+
+This change fixes querying and creating new MF symlinks on Windows 98.
+Currently cifs_query_mf_symlink() is not able to detect MF symlink and
+cifs_create_mf_symlink() is failing with EIO error.
+
+Signed-off-by: Pali Rohár <pali@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/client/link.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/fs/smb/client/link.c b/fs/smb/client/link.c
+index 6e6c09cc5ce7a..34a026243287f 100644
+--- a/fs/smb/client/link.c
++++ b/fs/smb/client/link.c
+@@ -258,7 +258,7 @@ cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
+ struct cifs_open_parms oparms;
+ struct cifs_io_parms io_parms = {0};
+ int buf_type = CIFS_NO_BUFFER;
+- FILE_ALL_INFO file_info;
++ struct cifs_open_info_data query_data;
+
+ oparms = (struct cifs_open_parms) {
+ .tcon = tcon,
+@@ -270,11 +270,11 @@ cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
+ .fid = &fid,
+ };
+
+- rc = CIFS_open(xid, &oparms, &oplock, &file_info);
++ rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, &query_data);
+ if (rc)
+ return rc;
+
+- if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
++ if (query_data.fi.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
+ rc = -ENOENT;
+ /* it's not a symlink */
+ goto out;
+@@ -313,7 +313,7 @@ cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
+ .fid = &fid,
+ };
+
+- rc = CIFS_open(xid, &oparms, &oplock, NULL);
++ rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, NULL);
+ if (rc)
+ return rc;
+
+--
+2.39.5
+
--- /dev/null
+From c890a6f48b5ebdfc88efa08c90dbb4b8379ed127 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 27 Oct 2024 12:10:52 +0100
+Subject: cifs: Set default Netbios RFC1001 server name to hostname in UNC
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Pali Rohár <pali@kernel.org>
+
+[ Upstream commit be786e509c1af9b2dcf25c3d601f05c8c251f482 ]
+
+Windows SMB servers (including SMB2+) which are working over RFC1001
+require that Netbios server name specified in RFC1001 Session Request
+packet is same as the UNC host name. Netbios server name can be already
+specified manually via -o servern= option.
+
+With this change the RFC1001 server name is set automatically by extracting
+the hostname from the mount source.
+
+Signed-off-by: Pali Rohár <pali@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/client/fs_context.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c
+index 00af8dd5aa689..b877def5a3664 100644
+--- a/fs/smb/client/fs_context.c
++++ b/fs/smb/client/fs_context.c
+@@ -1118,6 +1118,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
+ int i, opt;
+ bool is_smb3 = !strcmp(fc->fs_type->name, "smb3");
+ bool skip_parsing = false;
++ char *hostname;
+
+ cifs_dbg(FYI, "CIFS: parsing cifs mount option '%s'\n", param->key);
+
+@@ -1450,6 +1451,16 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
+ cifs_errorf(fc, "OOM when copying UNC string\n");
+ goto cifs_parse_mount_err;
+ }
++ hostname = extract_hostname(ctx->UNC);
++ if (IS_ERR(hostname)) {
++ cifs_errorf(fc, "Cannot extract hostname from UNC string\n");
++ goto cifs_parse_mount_err;
++ }
++ /* last byte, type, is 0x20 for servr type */
++ memset(ctx->target_rfc1001_name, 0x20, RFC1001_NAME_LEN_WITH_NULL);
++ for (i = 0; i < RFC1001_NAME_LEN && hostname[i] != 0; i++)
++ ctx->target_rfc1001_name[i] = toupper(hostname[i]);
++ kfree(hostname);
+ break;
+ case Opt_user:
+ kfree(ctx->username);
+--
+2.39.5
+
--- /dev/null
+From 905858e4e7c12e9521daf1135adccb22fa07bfc9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Feb 2025 19:26:46 +0100
+Subject: clk: imx8mp: inform CCF of maximum frequency of clocks
+
+From: Ahmad Fatoum <a.fatoum@pengutronix.de>
+
+[ Upstream commit 06a61b5cb6a8638fa8823cd09b17233b29696fa2 ]
+
+The IMX8MPCEC datasheet lists maximum frequencies allowed for different
+modules. Some of these limits are universal, but some depend on
+whether the SoC is operating in nominal or in overdrive mode.
+
+The imx8mp.dtsi currently assumes overdrive mode and configures some
+clocks in accordance with this. Boards wishing to make use of nominal
+mode will need to override some of the clock rates manually.
+
+As operating the clocks outside of their allowed range can lead to
+difficult to debug issues, it makes sense to register the maximum rates
+allowed in the driver, so the CCF can take them into account.
+
+Reviewed-by: Peng Fan <peng.fan@nxp.com>
+Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
+Link: https://lore.kernel.org/r/20250218-imx8m-clk-v4-6-b7697dc2dcd0@pengutronix.de
+Signed-off-by: Abel Vesa <abel.vesa@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/clk/imx/clk-imx8mp.c | 151 +++++++++++++++++++++++++++++++++++
+ 1 file changed, 151 insertions(+)
+
+diff --git a/drivers/clk/imx/clk-imx8mp.c b/drivers/clk/imx/clk-imx8mp.c
+index fb18f507f1213..fe6dac70f1a15 100644
+--- a/drivers/clk/imx/clk-imx8mp.c
++++ b/drivers/clk/imx/clk-imx8mp.c
+@@ -8,6 +8,7 @@
+ #include <linux/err.h>
+ #include <linux/io.h>
+ #include <linux/module.h>
++#include <linux/units.h>
+ #include <linux/of_address.h>
+ #include <linux/platform_device.h>
+ #include <linux/slab.h>
+@@ -406,11 +407,151 @@ static const char * const imx8mp_clkout_sels[] = {"audio_pll1_out", "audio_pll2_
+ static struct clk_hw **hws;
+ static struct clk_hw_onecell_data *clk_hw_data;
+
++struct imx8mp_clock_constraints {
++ unsigned int clkid;
++ u32 maxrate;
++};
++
++/*
++ * Below tables are taken from IMX8MPCEC Rev. 2.1, 07/2023
++ * Table 13. Maximum frequency of modules.
++ * Probable typos fixed are marked with a comment.
++ */
++static const struct imx8mp_clock_constraints imx8mp_clock_common_constraints[] = {
++ { IMX8MP_CLK_A53_DIV, 1000 * HZ_PER_MHZ },
++ { IMX8MP_CLK_ENET_AXI, 266666667 }, /* Datasheet claims 266MHz */
++ { IMX8MP_CLK_NAND_USDHC_BUS, 266666667 }, /* Datasheet claims 266MHz */
++ { IMX8MP_CLK_MEDIA_APB, 200 * HZ_PER_MHZ },
++ { IMX8MP_CLK_HDMI_APB, 133333333 }, /* Datasheet claims 133MHz */
++ { IMX8MP_CLK_ML_AXI, 800 * HZ_PER_MHZ },
++ { IMX8MP_CLK_AHB, 133333333 },
++ { IMX8MP_CLK_IPG_ROOT, 66666667 },
++ { IMX8MP_CLK_AUDIO_AHB, 400 * HZ_PER_MHZ },
++ { IMX8MP_CLK_MEDIA_DISP2_PIX, 170 * HZ_PER_MHZ },
++ { IMX8MP_CLK_DRAM_ALT, 666666667 },
++ { IMX8MP_CLK_DRAM_APB, 200 * HZ_PER_MHZ },
++ { IMX8MP_CLK_CAN1, 80 * HZ_PER_MHZ },
++ { IMX8MP_CLK_CAN2, 80 * HZ_PER_MHZ },
++ { IMX8MP_CLK_PCIE_AUX, 10 * HZ_PER_MHZ },
++ { IMX8MP_CLK_I2C5, 66666667 }, /* Datasheet claims 66MHz */
++ { IMX8MP_CLK_I2C6, 66666667 }, /* Datasheet claims 66MHz */
++ { IMX8MP_CLK_SAI1, 66666667 }, /* Datasheet claims 66MHz */
++ { IMX8MP_CLK_SAI2, 66666667 }, /* Datasheet claims 66MHz */
++ { IMX8MP_CLK_SAI3, 66666667 }, /* Datasheet claims 66MHz */
++ { IMX8MP_CLK_SAI5, 66666667 }, /* Datasheet claims 66MHz */
++ { IMX8MP_CLK_SAI6, 66666667 }, /* Datasheet claims 66MHz */
++ { IMX8MP_CLK_ENET_QOS, 125 * HZ_PER_MHZ },
++ { IMX8MP_CLK_ENET_QOS_TIMER, 200 * HZ_PER_MHZ },
++ { IMX8MP_CLK_ENET_REF, 125 * HZ_PER_MHZ },
++ { IMX8MP_CLK_ENET_TIMER, 125 * HZ_PER_MHZ },
++ { IMX8MP_CLK_ENET_PHY_REF, 125 * HZ_PER_MHZ },
++ { IMX8MP_CLK_NAND, 500 * HZ_PER_MHZ },
++ { IMX8MP_CLK_QSPI, 400 * HZ_PER_MHZ },
++ { IMX8MP_CLK_USDHC1, 400 * HZ_PER_MHZ },
++ { IMX8MP_CLK_USDHC2, 400 * HZ_PER_MHZ },
++ { IMX8MP_CLK_I2C1, 66666667 }, /* Datasheet claims 66MHz */
++ { IMX8MP_CLK_I2C2, 66666667 }, /* Datasheet claims 66MHz */
++ { IMX8MP_CLK_I2C3, 66666667 }, /* Datasheet claims 66MHz */
++ { IMX8MP_CLK_I2C4, 66666667 }, /* Datasheet claims 66MHz */
++ { IMX8MP_CLK_UART1, 80 * HZ_PER_MHZ },
++ { IMX8MP_CLK_UART2, 80 * HZ_PER_MHZ },
++ { IMX8MP_CLK_UART3, 80 * HZ_PER_MHZ },
++ { IMX8MP_CLK_UART4, 80 * HZ_PER_MHZ },
++ { IMX8MP_CLK_ECSPI1, 80 * HZ_PER_MHZ },
++ { IMX8MP_CLK_ECSPI2, 80 * HZ_PER_MHZ },
++ { IMX8MP_CLK_PWM1, 66666667 }, /* Datasheet claims 66MHz */
++ { IMX8MP_CLK_PWM2, 66666667 }, /* Datasheet claims 66MHz */
++ { IMX8MP_CLK_PWM3, 66666667 }, /* Datasheet claims 66MHz */
++ { IMX8MP_CLK_PWM4, 66666667 }, /* Datasheet claims 66MHz */
++ { IMX8MP_CLK_GPT1, 100 * HZ_PER_MHZ },
++ { IMX8MP_CLK_GPT2, 100 * HZ_PER_MHZ },
++ { IMX8MP_CLK_GPT3, 100 * HZ_PER_MHZ },
++ { IMX8MP_CLK_GPT4, 100 * HZ_PER_MHZ },
++ { IMX8MP_CLK_GPT5, 100 * HZ_PER_MHZ },
++ { IMX8MP_CLK_GPT6, 100 * HZ_PER_MHZ },
++ { IMX8MP_CLK_WDOG, 66666667 }, /* Datasheet claims 66MHz */
++ { IMX8MP_CLK_IPP_DO_CLKO1, 200 * HZ_PER_MHZ },
++ { IMX8MP_CLK_IPP_DO_CLKO2, 200 * HZ_PER_MHZ },
++ { IMX8MP_CLK_HDMI_REF_266M, 266 * HZ_PER_MHZ },
++ { IMX8MP_CLK_USDHC3, 400 * HZ_PER_MHZ },
++ { IMX8MP_CLK_MEDIA_MIPI_PHY1_REF, 300 * HZ_PER_MHZ },
++ { IMX8MP_CLK_MEDIA_DISP1_PIX, 250 * HZ_PER_MHZ },
++ { IMX8MP_CLK_MEDIA_CAM2_PIX, 277 * HZ_PER_MHZ },
++ { IMX8MP_CLK_MEDIA_LDB, 595 * HZ_PER_MHZ },
++ { IMX8MP_CLK_MEDIA_MIPI_TEST_BYTE, 200 * HZ_PER_MHZ },
++ { IMX8MP_CLK_ECSPI3, 80 * HZ_PER_MHZ },
++ { IMX8MP_CLK_PDM, 200 * HZ_PER_MHZ },
++ { IMX8MP_CLK_SAI7, 66666667 }, /* Datasheet claims 66MHz */
++ { IMX8MP_CLK_MAIN_AXI, 400 * HZ_PER_MHZ },
++ { /* Sentinel */ }
++};
++
++static const struct imx8mp_clock_constraints imx8mp_clock_nominal_constraints[] = {
++ { IMX8MP_CLK_M7_CORE, 600 * HZ_PER_MHZ },
++ { IMX8MP_CLK_ML_CORE, 800 * HZ_PER_MHZ },
++ { IMX8MP_CLK_GPU3D_CORE, 800 * HZ_PER_MHZ },
++ { IMX8MP_CLK_GPU3D_SHADER_CORE, 800 * HZ_PER_MHZ },
++ { IMX8MP_CLK_GPU2D_CORE, 800 * HZ_PER_MHZ },
++ { IMX8MP_CLK_AUDIO_AXI_SRC, 600 * HZ_PER_MHZ },
++ { IMX8MP_CLK_HSIO_AXI, 400 * HZ_PER_MHZ },
++ { IMX8MP_CLK_MEDIA_ISP, 400 * HZ_PER_MHZ },
++ { IMX8MP_CLK_VPU_BUS, 600 * HZ_PER_MHZ },
++ { IMX8MP_CLK_MEDIA_AXI, 400 * HZ_PER_MHZ },
++ { IMX8MP_CLK_HDMI_AXI, 400 * HZ_PER_MHZ },
++ { IMX8MP_CLK_GPU_AXI, 600 * HZ_PER_MHZ },
++ { IMX8MP_CLK_GPU_AHB, 300 * HZ_PER_MHZ },
++ { IMX8MP_CLK_NOC, 800 * HZ_PER_MHZ },
++ { IMX8MP_CLK_NOC_IO, 600 * HZ_PER_MHZ },
++ { IMX8MP_CLK_ML_AHB, 300 * HZ_PER_MHZ },
++ { IMX8MP_CLK_VPU_G1, 600 * HZ_PER_MHZ },
++ { IMX8MP_CLK_VPU_G2, 500 * HZ_PER_MHZ },
++ { IMX8MP_CLK_MEDIA_CAM1_PIX, 400 * HZ_PER_MHZ },
++ { IMX8MP_CLK_VPU_VC8000E, 400 * HZ_PER_MHZ }, /* Datasheet claims 500MHz */
++ { IMX8MP_CLK_DRAM_CORE, 800 * HZ_PER_MHZ },
++ { IMX8MP_CLK_GIC, 400 * HZ_PER_MHZ },
++ { /* Sentinel */ }
++};
++
++static const struct imx8mp_clock_constraints imx8mp_clock_overdrive_constraints[] = {
++ { IMX8MP_CLK_M7_CORE, 800 * HZ_PER_MHZ},
++ { IMX8MP_CLK_ML_CORE, 1000 * HZ_PER_MHZ },
++ { IMX8MP_CLK_GPU3D_CORE, 1000 * HZ_PER_MHZ },
++ { IMX8MP_CLK_GPU3D_SHADER_CORE, 1000 * HZ_PER_MHZ },
++ { IMX8MP_CLK_GPU2D_CORE, 1000 * HZ_PER_MHZ },
++ { IMX8MP_CLK_AUDIO_AXI_SRC, 800 * HZ_PER_MHZ },
++ { IMX8MP_CLK_HSIO_AXI, 500 * HZ_PER_MHZ },
++ { IMX8MP_CLK_MEDIA_ISP, 500 * HZ_PER_MHZ },
++ { IMX8MP_CLK_VPU_BUS, 800 * HZ_PER_MHZ },
++ { IMX8MP_CLK_MEDIA_AXI, 500 * HZ_PER_MHZ },
++ { IMX8MP_CLK_HDMI_AXI, 500 * HZ_PER_MHZ },
++ { IMX8MP_CLK_GPU_AXI, 800 * HZ_PER_MHZ },
++ { IMX8MP_CLK_GPU_AHB, 400 * HZ_PER_MHZ },
++ { IMX8MP_CLK_NOC, 1000 * HZ_PER_MHZ },
++ { IMX8MP_CLK_NOC_IO, 800 * HZ_PER_MHZ },
++ { IMX8MP_CLK_ML_AHB, 400 * HZ_PER_MHZ },
++ { IMX8MP_CLK_VPU_G1, 800 * HZ_PER_MHZ },
++ { IMX8MP_CLK_VPU_G2, 700 * HZ_PER_MHZ },
++ { IMX8MP_CLK_MEDIA_CAM1_PIX, 500 * HZ_PER_MHZ },
++ { IMX8MP_CLK_VPU_VC8000E, 500 * HZ_PER_MHZ }, /* Datasheet claims 400MHz */
++ { IMX8MP_CLK_DRAM_CORE, 1000 * HZ_PER_MHZ },
++ { IMX8MP_CLK_GIC, 500 * HZ_PER_MHZ },
++ { /* Sentinel */ }
++};
++
++static void imx8mp_clocks_apply_constraints(const struct imx8mp_clock_constraints constraints[])
++{
++ const struct imx8mp_clock_constraints *constr;
++
++ for (constr = constraints; constr->clkid; constr++)
++ clk_hw_set_rate_range(hws[constr->clkid], 0, constr->maxrate);
++}
++
+ static int imx8mp_clocks_probe(struct platform_device *pdev)
+ {
+ struct device *dev = &pdev->dev;
+ struct device_node *np;
+ void __iomem *anatop_base, *ccm_base;
++ const char *opmode;
+ int err;
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx8mp-anatop");
+@@ -715,6 +856,16 @@ static int imx8mp_clocks_probe(struct platform_device *pdev)
+
+ imx_check_clk_hws(hws, IMX8MP_CLK_END);
+
++ imx8mp_clocks_apply_constraints(imx8mp_clock_common_constraints);
++
++ err = of_property_read_string(np, "fsl,operating-mode", &opmode);
++ if (!err) {
++ if (!strcmp(opmode, "nominal"))
++ imx8mp_clocks_apply_constraints(imx8mp_clock_nominal_constraints);
++ else if (!strcmp(opmode, "overdrive"))
++ imx8mp_clocks_apply_constraints(imx8mp_clock_overdrive_constraints);
++ }
++
+ err = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
+ if (err < 0) {
+ dev_err(dev, "failed to register hws for i.MX8MP\n");
+--
+2.39.5
+
--- /dev/null
+From e0ef362fb30fa3291d57394a846097145482e044 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 22 Jan 2025 22:26:12 +0000
+Subject: clk: qcom: camcc-sm8250: Use clk_rcg2_shared_ops for some RCGs
+
+From: Jordan Crouse <jorcrous@amazon.com>
+
+[ Upstream commit 52b10b591f83dc6d9a1d6c2dc89433470a787ecd ]
+
+Update some RCGs on the sm8250 camera clock controller to use
+clk_rcg2_shared_ops. The shared_ops ensure the RCGs get parked
+to the XO during clock disable to prevent the clocks from locking up
+when the GDSC is enabled. These mirror similar fixes for other controllers
+such as commit e5c359f70e4b ("clk: qcom: camcc: Update the clock ops for
+the SC7180").
+
+Signed-off-by: Jordan Crouse <jorcrous@amazon.com>
+Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Reviewed-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
+Link: https://lore.kernel.org/r/20250122222612.32351-1-jorcrous@amazon.com
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/clk/qcom/camcc-sm8250.c | 56 ++++++++++++++++-----------------
+ 1 file changed, 28 insertions(+), 28 deletions(-)
+
+diff --git a/drivers/clk/qcom/camcc-sm8250.c b/drivers/clk/qcom/camcc-sm8250.c
+index 34d2f17520dcc..450ddbebd35f2 100644
+--- a/drivers/clk/qcom/camcc-sm8250.c
++++ b/drivers/clk/qcom/camcc-sm8250.c
+@@ -411,7 +411,7 @@ static struct clk_rcg2 cam_cc_bps_clk_src = {
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+- .ops = &clk_rcg2_ops,
++ .ops = &clk_rcg2_shared_ops,
+ },
+ };
+
+@@ -433,7 +433,7 @@ static struct clk_rcg2 cam_cc_camnoc_axi_clk_src = {
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+- .ops = &clk_rcg2_ops,
++ .ops = &clk_rcg2_shared_ops,
+ },
+ };
+
+@@ -454,7 +454,7 @@ static struct clk_rcg2 cam_cc_cci_0_clk_src = {
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+- .ops = &clk_rcg2_ops,
++ .ops = &clk_rcg2_shared_ops,
+ },
+ };
+
+@@ -469,7 +469,7 @@ static struct clk_rcg2 cam_cc_cci_1_clk_src = {
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+- .ops = &clk_rcg2_ops,
++ .ops = &clk_rcg2_shared_ops,
+ },
+ };
+
+@@ -490,7 +490,7 @@ static struct clk_rcg2 cam_cc_cphy_rx_clk_src = {
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+- .ops = &clk_rcg2_ops,
++ .ops = &clk_rcg2_shared_ops,
+ },
+ };
+
+@@ -511,7 +511,7 @@ static struct clk_rcg2 cam_cc_csi0phytimer_clk_src = {
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+- .ops = &clk_rcg2_ops,
++ .ops = &clk_rcg2_shared_ops,
+ },
+ };
+
+@@ -526,7 +526,7 @@ static struct clk_rcg2 cam_cc_csi1phytimer_clk_src = {
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+- .ops = &clk_rcg2_ops,
++ .ops = &clk_rcg2_shared_ops,
+ },
+ };
+
+@@ -556,7 +556,7 @@ static struct clk_rcg2 cam_cc_csi3phytimer_clk_src = {
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+- .ops = &clk_rcg2_ops,
++ .ops = &clk_rcg2_shared_ops,
+ },
+ };
+
+@@ -571,7 +571,7 @@ static struct clk_rcg2 cam_cc_csi4phytimer_clk_src = {
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+- .ops = &clk_rcg2_ops,
++ .ops = &clk_rcg2_shared_ops,
+ },
+ };
+
+@@ -586,7 +586,7 @@ static struct clk_rcg2 cam_cc_csi5phytimer_clk_src = {
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+- .ops = &clk_rcg2_ops,
++ .ops = &clk_rcg2_shared_ops,
+ },
+ };
+
+@@ -611,7 +611,7 @@ static struct clk_rcg2 cam_cc_fast_ahb_clk_src = {
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+- .ops = &clk_rcg2_ops,
++ .ops = &clk_rcg2_shared_ops,
+ },
+ };
+
+@@ -634,7 +634,7 @@ static struct clk_rcg2 cam_cc_fd_core_clk_src = {
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+- .ops = &clk_rcg2_ops,
++ .ops = &clk_rcg2_shared_ops,
+ },
+ };
+
+@@ -649,7 +649,7 @@ static struct clk_rcg2 cam_cc_icp_clk_src = {
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+- .ops = &clk_rcg2_ops,
++ .ops = &clk_rcg2_shared_ops,
+ },
+ };
+
+@@ -673,7 +673,7 @@ static struct clk_rcg2 cam_cc_ife_0_clk_src = {
+ .parent_data = cam_cc_parent_data_2,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_2),
+ .flags = CLK_SET_RATE_PARENT,
+- .ops = &clk_rcg2_ops,
++ .ops = &clk_rcg2_shared_ops,
+ },
+ };
+
+@@ -710,7 +710,7 @@ static struct clk_rcg2 cam_cc_ife_0_csid_clk_src = {
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+- .ops = &clk_rcg2_ops,
++ .ops = &clk_rcg2_shared_ops,
+ },
+ };
+
+@@ -734,7 +734,7 @@ static struct clk_rcg2 cam_cc_ife_1_clk_src = {
+ .parent_data = cam_cc_parent_data_3,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_3),
+ .flags = CLK_SET_RATE_PARENT,
+- .ops = &clk_rcg2_ops,
++ .ops = &clk_rcg2_shared_ops,
+ },
+ };
+
+@@ -749,7 +749,7 @@ static struct clk_rcg2 cam_cc_ife_1_csid_clk_src = {
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+- .ops = &clk_rcg2_ops,
++ .ops = &clk_rcg2_shared_ops,
+ },
+ };
+
+@@ -771,7 +771,7 @@ static struct clk_rcg2 cam_cc_ife_lite_clk_src = {
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+- .ops = &clk_rcg2_ops,
++ .ops = &clk_rcg2_shared_ops,
+ },
+ };
+
+@@ -786,7 +786,7 @@ static struct clk_rcg2 cam_cc_ife_lite_csid_clk_src = {
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+- .ops = &clk_rcg2_ops,
++ .ops = &clk_rcg2_shared_ops,
+ },
+ };
+
+@@ -810,7 +810,7 @@ static struct clk_rcg2 cam_cc_ipe_0_clk_src = {
+ .parent_data = cam_cc_parent_data_4,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_4),
+ .flags = CLK_SET_RATE_PARENT,
+- .ops = &clk_rcg2_ops,
++ .ops = &clk_rcg2_shared_ops,
+ },
+ };
+
+@@ -825,7 +825,7 @@ static struct clk_rcg2 cam_cc_jpeg_clk_src = {
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+- .ops = &clk_rcg2_ops,
++ .ops = &clk_rcg2_shared_ops,
+ },
+ };
+
+@@ -847,7 +847,7 @@ static struct clk_rcg2 cam_cc_mclk0_clk_src = {
+ .parent_data = cam_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+- .ops = &clk_rcg2_ops,
++ .ops = &clk_rcg2_shared_ops,
+ },
+ };
+
+@@ -862,7 +862,7 @@ static struct clk_rcg2 cam_cc_mclk1_clk_src = {
+ .parent_data = cam_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+- .ops = &clk_rcg2_ops,
++ .ops = &clk_rcg2_shared_ops,
+ },
+ };
+
+@@ -877,7 +877,7 @@ static struct clk_rcg2 cam_cc_mclk2_clk_src = {
+ .parent_data = cam_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+- .ops = &clk_rcg2_ops,
++ .ops = &clk_rcg2_shared_ops,
+ },
+ };
+
+@@ -892,7 +892,7 @@ static struct clk_rcg2 cam_cc_mclk3_clk_src = {
+ .parent_data = cam_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+- .ops = &clk_rcg2_ops,
++ .ops = &clk_rcg2_shared_ops,
+ },
+ };
+
+@@ -907,7 +907,7 @@ static struct clk_rcg2 cam_cc_mclk4_clk_src = {
+ .parent_data = cam_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+- .ops = &clk_rcg2_ops,
++ .ops = &clk_rcg2_shared_ops,
+ },
+ };
+
+@@ -922,7 +922,7 @@ static struct clk_rcg2 cam_cc_mclk5_clk_src = {
+ .parent_data = cam_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+- .ops = &clk_rcg2_ops,
++ .ops = &clk_rcg2_shared_ops,
+ },
+ };
+
+@@ -993,7 +993,7 @@ static struct clk_rcg2 cam_cc_slow_ahb_clk_src = {
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+- .ops = &clk_rcg2_ops,
++ .ops = &clk_rcg2_shared_ops,
+ },
+ };
+
+--
+2.39.5
+
--- /dev/null
+From 3f05998db340f3ce49dc46957aedd5bbebb198de Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 12 Feb 2025 21:01:35 +0100
+Subject: clk: qcom: clk-alpha-pll: Do not use random stack value for recalc
+ rate
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+[ Upstream commit 7a243e1b814a02ab40793026ef64223155d86395 ]
+
+If regmap_read() fails, random stack value was used in calculating new
+frequency in recalc_rate() callbacks. Such failure is really not
+expected as these are all MMIO reads, however code should be here
+correct and bail out. This also avoids possible warning on
+uninitialized value.
+
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Link: https://lore.kernel.org/r/20250212-b4-clk-qcom-clean-v3-1-499f37444f5d@linaro.org
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/clk/qcom/clk-alpha-pll.c | 52 ++++++++++++++++++++++----------
+ 1 file changed, 36 insertions(+), 16 deletions(-)
+
+diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c
+index 9a65d14acf71c..cec0afea8e446 100644
+--- a/drivers/clk/qcom/clk-alpha-pll.c
++++ b/drivers/clk/qcom/clk-alpha-pll.c
+@@ -709,14 +709,19 @@ clk_alpha_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+ struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
+ u32 alpha_width = pll_alpha_width(pll);
+
+- regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l);
++ if (regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l))
++ return 0;
++
++ if (regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &ctl))
++ return 0;
+
+- regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &ctl);
+ if (ctl & PLL_ALPHA_EN) {
+- regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL(pll), &low);
++ if (regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL(pll), &low))
++ return 0;
+ if (alpha_width > 32) {
+- regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL_U(pll),
+- &high);
++ if (regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL_U(pll),
++ &high))
++ return 0;
+ a = (u64)high << 32 | low;
+ } else {
+ a = low & GENMASK(alpha_width - 1, 0);
+@@ -942,8 +947,11 @@ alpha_pll_huayra_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+ struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
+ u32 l, alpha = 0, ctl, alpha_m, alpha_n;
+
+- regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l);
+- regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &ctl);
++ if (regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l))
++ return 0;
++
++ if (regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &ctl))
++ return 0;
+
+ if (ctl & PLL_ALPHA_EN) {
+ regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL(pll), &alpha);
+@@ -1137,8 +1145,11 @@ clk_trion_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+ struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
+ u32 l, frac, alpha_width = pll_alpha_width(pll);
+
+- regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l);
+- regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL(pll), &frac);
++ if (regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l))
++ return 0;
++
++ if (regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL(pll), &frac))
++ return 0;
+
+ return alpha_pll_calc_rate(parent_rate, l, frac, alpha_width);
+ }
+@@ -1196,7 +1207,8 @@ clk_alpha_pll_postdiv_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+ struct clk_alpha_pll_postdiv *pll = to_clk_alpha_pll_postdiv(hw);
+ u32 ctl;
+
+- regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &ctl);
++ if (regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &ctl))
++ return 0;
+
+ ctl >>= PLL_POST_DIV_SHIFT;
+ ctl &= PLL_POST_DIV_MASK(pll);
+@@ -1412,8 +1424,11 @@ static unsigned long alpha_pll_fabia_recalc_rate(struct clk_hw *hw,
+ struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
+ u32 l, frac, alpha_width = pll_alpha_width(pll);
+
+- regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l);
+- regmap_read(pll->clkr.regmap, PLL_FRAC(pll), &frac);
++ if (regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l))
++ return 0;
++
++ if (regmap_read(pll->clkr.regmap, PLL_FRAC(pll), &frac))
++ return 0;
+
+ return alpha_pll_calc_rate(parent_rate, l, frac, alpha_width);
+ }
+@@ -1563,7 +1578,8 @@ clk_trion_pll_postdiv_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+ struct regmap *regmap = pll->clkr.regmap;
+ u32 i, div = 1, val;
+
+- regmap_read(regmap, PLL_USER_CTL(pll), &val);
++ if (regmap_read(regmap, PLL_USER_CTL(pll), &val))
++ return 0;
+
+ val >>= pll->post_div_shift;
+ val &= PLL_POST_DIV_MASK(pll);
+@@ -2484,9 +2500,12 @@ static unsigned long alpha_pll_lucid_evo_recalc_rate(struct clk_hw *hw,
+ struct regmap *regmap = pll->clkr.regmap;
+ u32 l, frac;
+
+- regmap_read(regmap, PLL_L_VAL(pll), &l);
++ if (regmap_read(regmap, PLL_L_VAL(pll), &l))
++ return 0;
+ l &= LUCID_EVO_PLL_L_VAL_MASK;
+- regmap_read(regmap, PLL_ALPHA_VAL(pll), &frac);
++
++ if (regmap_read(regmap, PLL_ALPHA_VAL(pll), &frac))
++ return 0;
+
+ return alpha_pll_calc_rate(parent_rate, l, frac, pll_alpha_width(pll));
+ }
+@@ -2699,7 +2718,8 @@ static unsigned long clk_rivian_evo_pll_recalc_rate(struct clk_hw *hw,
+ struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
+ u32 l;
+
+- regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l);
++ if (regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l))
++ return 0;
+
+ return parent_rate * l;
+ }
+--
+2.39.5
+
--- /dev/null
+From e28592b361b940858d6aee1459c15b7f642b43e7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 8 Oct 2024 00:34:12 +0800
+Subject: clk: qcom: ipq5018: allow it to be bulid on arm32
+
+From: Karl Chan <exxxxkc@getgoogleoff.me>
+
+[ Upstream commit 5d02941c83997b58e8fc15390290c7c6975acaff ]
+
+There are some ipq5018 based device's firmware only can able to boot
+arm32 but the clock driver dont allow it to be compiled on arm32.
+Therefore allow GCC for IPQ5018 to be selected when building ARM32
+kernel
+
+Signed-off-by: Karl Chan <exxxxkc@getgoogleoff.me>
+Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Link: https://lore.kernel.org/r/20241007163414.32458-4-exxxxkc@getgoogleoff.me
+[bjorn: Updated commit message, per Dmitry's suggestion]
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/clk/qcom/Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
+index 69bbf62ba3cd7..d470ed007854c 100644
+--- a/drivers/clk/qcom/Kconfig
++++ b/drivers/clk/qcom/Kconfig
+@@ -217,7 +217,7 @@ config IPQ_GCC_4019
+
+ config IPQ_GCC_5018
+ tristate "IPQ5018 Global Clock Controller"
+- depends on ARM64 || COMPILE_TEST
++ depends on ARM || ARM64 || COMPILE_TEST
+ help
+ Support for global clock controller on ipq5018 devices.
+ Say Y if you want to use peripheral devices such as UART, SPI,
+--
+2.39.5
+
--- /dev/null
+From e1e21cc754be891f99d9af28b849888f7b83eba2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 21 Feb 2025 15:04:55 +0530
+Subject: clk: qcom: lpassaudiocc-sc7280: Add support for LPASS resets for
+ QCM6490
+
+From: Taniya Das <quic_tdas@quicinc.com>
+
+[ Upstream commit cdbbc480f4146cb659af97f4020601fde5fb65a7 ]
+
+On the QCM6490 boards, the LPASS firmware controls the complete clock
+controller functionalities and associated power domains. However, only
+the LPASS resets required to be controlled by the high level OS. Thus,
+add support for the resets in the clock driver to enable the Audio SW
+driver to assert/deassert the audio resets as needed.
+
+Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Signed-off-by: Taniya Das <quic_tdas@quicinc.com>
+Link: https://lore.kernel.org/r/20250221-lpass_qcm6490_resets-v5-2-6be0c0949a83@quicinc.com
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/clk/qcom/lpassaudiocc-sc7280.c | 23 +++++++++++++++++++----
+ 1 file changed, 19 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/clk/qcom/lpassaudiocc-sc7280.c b/drivers/clk/qcom/lpassaudiocc-sc7280.c
+index 45e7264770866..22169da08a51a 100644
+--- a/drivers/clk/qcom/lpassaudiocc-sc7280.c
++++ b/drivers/clk/qcom/lpassaudiocc-sc7280.c
+@@ -1,6 +1,7 @@
+ // SPDX-License-Identifier: GPL-2.0-only
+ /*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
++ * Copyright (c) 2025, Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+ #include <linux/clk-provider.h>
+@@ -713,14 +714,24 @@ static const struct qcom_reset_map lpass_audio_cc_sc7280_resets[] = {
+ [LPASS_AUDIO_SWR_WSA_CGCR] = { 0xb0, 1 },
+ };
+
++static const struct regmap_config lpass_audio_cc_sc7280_reset_regmap_config = {
++ .name = "lpassaudio_cc_reset",
++ .reg_bits = 32,
++ .reg_stride = 4,
++ .val_bits = 32,
++ .fast_io = true,
++ .max_register = 0xc8,
++};
++
+ static const struct qcom_cc_desc lpass_audio_cc_reset_sc7280_desc = {
+- .config = &lpass_audio_cc_sc7280_regmap_config,
++ .config = &lpass_audio_cc_sc7280_reset_regmap_config,
+ .resets = lpass_audio_cc_sc7280_resets,
+ .num_resets = ARRAY_SIZE(lpass_audio_cc_sc7280_resets),
+ };
+
+ static const struct of_device_id lpass_audio_cc_sc7280_match_table[] = {
+- { .compatible = "qcom,sc7280-lpassaudiocc" },
++ { .compatible = "qcom,qcm6490-lpassaudiocc", .data = &lpass_audio_cc_reset_sc7280_desc },
++ { .compatible = "qcom,sc7280-lpassaudiocc", .data = &lpass_audio_cc_sc7280_desc },
+ { }
+ };
+ MODULE_DEVICE_TABLE(of, lpass_audio_cc_sc7280_match_table);
+@@ -752,13 +763,17 @@ static int lpass_audio_cc_sc7280_probe(struct platform_device *pdev)
+ struct regmap *regmap;
+ int ret;
+
++ desc = device_get_match_data(&pdev->dev);
++
++ if (of_device_is_compatible(pdev->dev.of_node, "qcom,qcm6490-lpassaudiocc"))
++ return qcom_cc_probe_by_index(pdev, 1, desc);
++
+ ret = lpass_audio_setup_runtime_pm(pdev);
+ if (ret)
+ return ret;
+
+ lpass_audio_cc_sc7280_regmap_config.name = "lpassaudio_cc";
+ lpass_audio_cc_sc7280_regmap_config.max_register = 0x2f000;
+- desc = &lpass_audio_cc_sc7280_desc;
+
+ regmap = qcom_cc_map(pdev, desc);
+ if (IS_ERR(regmap)) {
+@@ -772,7 +787,7 @@ static int lpass_audio_cc_sc7280_probe(struct platform_device *pdev)
+ regmap_write(regmap, 0x4, 0x3b);
+ regmap_write(regmap, 0x8, 0xff05);
+
+- ret = qcom_cc_really_probe(&pdev->dev, &lpass_audio_cc_sc7280_desc, regmap);
++ ret = qcom_cc_really_probe(&pdev->dev, desc, regmap);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register LPASS AUDIO CC clocks\n");
+ goto exit;
+--
+2.39.5
+
--- /dev/null
+From dd7aded6545163b9011b481775bfabe916569497 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 16 Dec 2024 21:02:01 +0000
+Subject: clk: renesas: rzg2l-cpg: Refactor Runtime PM clock validation
+
+From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
+
+[ Upstream commit f6f73b891bf6beff069fcacc7b4a796e1009bf26 ]
+
+Refactor rzg2l_cpg_attach_dev to delegate clock validation for Runtime PM
+to the updated rzg2l_cpg_is_pm_clk function. Ensure validation of clocks
+associated with the power domain while excluding external and core clocks.
+Prevent incorrect Runtime PM management for clocks outside the domain's
+scope.
+
+Update rzg2l_cpg_is_pm_clk to operate on a per-power-domain basis. Verify
+clkspec.np against the domain's device node, check argument validity, and
+validate clock type (CPG_MOD). Use the no_pm_mod_clks array to exclude
+specific clocks from PM management.
+
+Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
+Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
+Link: https://lore.kernel.org/20241216210201.239855-1-prabhakar.mahadev-lad.rj@bp.renesas.com
+Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/clk/renesas/rzg2l-cpg.c | 102 +++++++++++++++++---------------
+ 1 file changed, 54 insertions(+), 48 deletions(-)
+
+diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c
+index 4bd8862dc82be..91928db411dcd 100644
+--- a/drivers/clk/renesas/rzg2l-cpg.c
++++ b/drivers/clk/renesas/rzg2l-cpg.c
+@@ -1549,28 +1549,6 @@ static int rzg2l_cpg_reset_controller_register(struct rzg2l_cpg_priv *priv)
+ return devm_reset_controller_register(priv->dev, &priv->rcdev);
+ }
+
+-static bool rzg2l_cpg_is_pm_clk(struct rzg2l_cpg_priv *priv,
+- const struct of_phandle_args *clkspec)
+-{
+- const struct rzg2l_cpg_info *info = priv->info;
+- unsigned int id;
+- unsigned int i;
+-
+- if (clkspec->args_count != 2)
+- return false;
+-
+- if (clkspec->args[0] != CPG_MOD)
+- return false;
+-
+- id = clkspec->args[1] + info->num_total_core_clks;
+- for (i = 0; i < info->num_no_pm_mod_clks; i++) {
+- if (info->no_pm_mod_clks[i] == id)
+- return false;
+- }
+-
+- return true;
+-}
+-
+ /**
+ * struct rzg2l_cpg_pm_domains - RZ/G2L PM domains data structure
+ * @onecell_data: cell data
+@@ -1595,45 +1573,73 @@ struct rzg2l_cpg_pd {
+ u16 id;
+ };
+
++static bool rzg2l_cpg_is_pm_clk(struct rzg2l_cpg_pd *pd,
++ const struct of_phandle_args *clkspec)
++{
++ if (clkspec->np != pd->genpd.dev.of_node || clkspec->args_count != 2)
++ return false;
++
++ switch (clkspec->args[0]) {
++ case CPG_MOD: {
++ struct rzg2l_cpg_priv *priv = pd->priv;
++ const struct rzg2l_cpg_info *info = priv->info;
++ unsigned int id = clkspec->args[1];
++
++ if (id >= priv->num_mod_clks)
++ return false;
++
++ id += info->num_total_core_clks;
++
++ for (unsigned int i = 0; i < info->num_no_pm_mod_clks; i++) {
++ if (info->no_pm_mod_clks[i] == id)
++ return false;
++ }
++
++ return true;
++ }
++
++ case CPG_CORE:
++ default:
++ return false;
++ }
++}
++
+ static int rzg2l_cpg_attach_dev(struct generic_pm_domain *domain, struct device *dev)
+ {
+ struct rzg2l_cpg_pd *pd = container_of(domain, struct rzg2l_cpg_pd, genpd);
+- struct rzg2l_cpg_priv *priv = pd->priv;
+ struct device_node *np = dev->of_node;
+ struct of_phandle_args clkspec;
+ bool once = true;
+ struct clk *clk;
++ unsigned int i;
+ int error;
+- int i = 0;
+-
+- while (!of_parse_phandle_with_args(np, "clocks", "#clock-cells", i,
+- &clkspec)) {
+- if (rzg2l_cpg_is_pm_clk(priv, &clkspec)) {
+- if (once) {
+- once = false;
+- error = pm_clk_create(dev);
+- if (error) {
+- of_node_put(clkspec.np);
+- goto err;
+- }
+- }
+- clk = of_clk_get_from_provider(&clkspec);
++
++ for (i = 0; !of_parse_phandle_with_args(np, "clocks", "#clock-cells", i, &clkspec); i++) {
++ if (!rzg2l_cpg_is_pm_clk(pd, &clkspec)) {
+ of_node_put(clkspec.np);
+- if (IS_ERR(clk)) {
+- error = PTR_ERR(clk);
+- goto fail_destroy;
+- }
++ continue;
++ }
+
+- error = pm_clk_add_clk(dev, clk);
++ if (once) {
++ once = false;
++ error = pm_clk_create(dev);
+ if (error) {
+- dev_err(dev, "pm_clk_add_clk failed %d\n",
+- error);
+- goto fail_put;
++ of_node_put(clkspec.np);
++ goto err;
+ }
+- } else {
+- of_node_put(clkspec.np);
+ }
+- i++;
++ clk = of_clk_get_from_provider(&clkspec);
++ of_node_put(clkspec.np);
++ if (IS_ERR(clk)) {
++ error = PTR_ERR(clk);
++ goto fail_destroy;
++ }
++
++ error = pm_clk_add_clk(dev, clk);
++ if (error) {
++ dev_err(dev, "pm_clk_add_clk failed %d\n", error);
++ goto fail_put;
++ }
+ }
+
+ return 0;
+--
+2.39.5
+
--- /dev/null
+From abf286553b07f40eaeb2f98f4f5d211142a31d42 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 20 Feb 2025 12:38:08 +0100
+Subject: clk: sunxi-ng: h616: Reparent GPU clock during frequency changes
+
+From: Philippe Simons <simons.philippe@gmail.com>
+
+[ Upstream commit eb963d7948ce6571939c6875424b557b25f16610 ]
+
+The H616 manual does not state that the GPU PLL supports
+dynamic frequency configuration, so we must take extra care when changing
+the frequency. Currently any attempt to do device DVFS on the GPU lead
+to panfrost various ooops, and GPU hangs.
+
+The manual describes the algorithm for changing the PLL
+frequency, which the CPU PLL notifier code already support, so we reuse
+that to reparent the GPU clock to GPU1 clock during frequency
+changes.
+
+Signed-off-by: Philippe Simons <simons.philippe@gmail.com>
+Reviewed-by: Andre Przywara <andre.przywara@arm.com>
+Reviewed-by: Jernej Skrabec <jernej.skrabec@gmail.com>
+Link: https://patch.msgid.link/20250220113808.1122414-2-simons.philippe@gmail.com
+Signed-off-by: Chen-Yu Tsai <wens@csie.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/clk/sunxi-ng/ccu-sun50i-h616.c | 36 +++++++++++++++++++++++++-
+ 1 file changed, 35 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h616.c b/drivers/clk/sunxi-ng/ccu-sun50i-h616.c
+index 190816c35da9f..6050cbfa922e2 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun50i-h616.c
++++ b/drivers/clk/sunxi-ng/ccu-sun50i-h616.c
+@@ -328,10 +328,16 @@ static SUNXI_CCU_M_WITH_MUX_GATE(gpu0_clk, "gpu0", gpu0_parents, 0x670,
+ 24, 1, /* mux */
+ BIT(31), /* gate */
+ CLK_SET_RATE_PARENT);
++
++/*
++ * This clk is needed as a temporary fall back during GPU PLL freq changes.
++ * Set CLK_IS_CRITICAL flag to prevent from being disabled.
++ */
++#define SUN50I_H616_GPU_CLK1_REG 0x674
+ static SUNXI_CCU_M_WITH_GATE(gpu1_clk, "gpu1", "pll-periph0-2x", 0x674,
+ 0, 2, /* M */
+ BIT(31),/* gate */
+- 0);
++ CLK_IS_CRITICAL);
+
+ static SUNXI_CCU_GATE(bus_gpu_clk, "bus-gpu", "psi-ahb1-ahb2",
+ 0x67c, BIT(0), 0);
+@@ -1120,6 +1126,19 @@ static struct ccu_pll_nb sun50i_h616_pll_cpu_nb = {
+ .lock = BIT(28),
+ };
+
++static struct ccu_mux_nb sun50i_h616_gpu_nb = {
++ .common = &gpu0_clk.common,
++ .cm = &gpu0_clk.mux,
++ .delay_us = 1, /* manual doesn't really say */
++ .bypass_index = 1, /* GPU_CLK1@400MHz */
++};
++
++static struct ccu_pll_nb sun50i_h616_pll_gpu_nb = {
++ .common = &pll_gpu_clk.common,
++ .enable = BIT(29), /* LOCK_ENABLE */
++ .lock = BIT(28),
++};
++
+ static int sun50i_h616_ccu_probe(struct platform_device *pdev)
+ {
+ void __iomem *reg;
+@@ -1170,6 +1189,14 @@ static int sun50i_h616_ccu_probe(struct platform_device *pdev)
+ val |= BIT(0);
+ writel(val, reg + SUN50I_H616_PLL_AUDIO_REG);
+
++ /*
++ * Set the input-divider for the gpu1 clock to 3, to reach a safe 400 MHz.
++ */
++ val = readl(reg + SUN50I_H616_GPU_CLK1_REG);
++ val &= ~GENMASK(1, 0);
++ val |= 2;
++ writel(val, reg + SUN50I_H616_GPU_CLK1_REG);
++
+ /*
+ * First clock parent (osc32K) is unusable for CEC. But since there
+ * is no good way to force parent switch (both run with same frequency),
+@@ -1190,6 +1217,13 @@ static int sun50i_h616_ccu_probe(struct platform_device *pdev)
+ /* Re-lock the CPU PLL after any rate changes */
+ ccu_pll_notifier_register(&sun50i_h616_pll_cpu_nb);
+
++ /* Reparent GPU during GPU PLL rate changes */
++ ccu_mux_notifier_register(pll_gpu_clk.common.hw.clk,
++ &sun50i_h616_gpu_nb);
++
++ /* Re-lock the GPU PLL after any rate changes */
++ ccu_pll_notifier_register(&sun50i_h616_pll_gpu_nb);
++
+ return 0;
+ }
+
+--
+2.39.5
+
--- /dev/null
+From 452f0251b89f2545a122cc9273211224b349d5b2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 19 Feb 2025 19:41:35 +0800
+Subject: clocksource/drivers/timer-riscv: Stop stimecmp when cpu hotplug
+
+From: Nick Hu <nick.hu@sifive.com>
+
+[ Upstream commit 70c93b026ed07078e933583591aa9ca6701cd9da ]
+
+Stop the timer when the cpu is going to be offline otherwise the
+timer interrupt may be pending while performing power-down.
+
+Suggested-by: Anup Patel <anup@brainfault.org>
+Link: https://lore.kernel.org/lkml/20240829033904.477200-3-nick.hu@sifive.com/T/#u
+Signed-off-by: Nick Hu <nick.hu@sifive.com>
+Reviewed-by: Anup Patel <anup@brainfault.org>
+Acked-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20250219114135.27764-3-nick.hu@sifive.com
+Signed-off-by: Alexandre Ghiti <alexghiti@rivosinc.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/clocksource/timer-riscv.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/drivers/clocksource/timer-riscv.c b/drivers/clocksource/timer-riscv.c
+index 48ce50c5f5e68..4d7cf338824a3 100644
+--- a/drivers/clocksource/timer-riscv.c
++++ b/drivers/clocksource/timer-riscv.c
+@@ -126,7 +126,13 @@ static int riscv_timer_starting_cpu(unsigned int cpu)
+
+ static int riscv_timer_dying_cpu(unsigned int cpu)
+ {
++ /*
++ * Stop the timer when the cpu is going to be offline otherwise
++ * the timer interrupt may be pending while performing power-down.
++ */
++ riscv_clock_event_stop();
+ disable_percpu_irq(riscv_clock_event_irq);
++
+ return 0;
+ }
+
+--
+2.39.5
+
--- /dev/null
+From ee8206dced1f1bb3c86cf8bf6aa0ade3c7bbc03b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jan 2025 13:32:47 +0100
+Subject: clocksource: mips-gic-timer: Enable counter when CPUs start
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Paul Burton <paulburton@kernel.org>
+
+[ Upstream commit 3128b0a2e0cf6e07aa78e5f8cf7dd9cd59dc8174 ]
+
+In multi-cluster MIPS I6500 systems there is a GIC in each cluster,
+each with its own counter. When a cluster powers up the counter will
+be stopped, with the COUNTSTOP bit set in the GIC_CONFIG register.
+
+In single cluster systems, it has been fine to clear COUNTSTOP once
+in gic_clocksource_of_init() to start the counter. In multi-cluster
+systems, this will only have started the counter in the boot cluster,
+and any CPUs in other clusters will find their counter stopped which
+will break the GIC clock_event_device.
+
+Resolve this by having CPUs clear the COUNTSTOP bit when they come
+online, using the existing gic_starting_cpu() CPU hotplug callback. This
+will allow CPUs in secondary clusters to ensure that the cluster's GIC
+counter is running as expected.
+
+Signed-off-by: Paul Burton <paulburton@kernel.org>
+Signed-off-by: Chao-ying Fu <cfu@wavecomp.com>
+Signed-off-by: Dragan Mladjenovic <dragan.mladjenovic@syrmia.com>
+Signed-off-by: Aleksandar Rikalo <arikalo@gmail.com>
+Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
+Tested-by: Serge Semin <fancer.lancer@gmail.com>
+Tested-by: Gregory CLEMENT <gregory.clement@bootlin.com>
+Acked-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/clocksource/mips-gic-timer.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c
+index 7907b740497a5..abb685a080a5b 100644
+--- a/drivers/clocksource/mips-gic-timer.c
++++ b/drivers/clocksource/mips-gic-timer.c
+@@ -115,6 +115,9 @@ static void gic_update_frequency(void *data)
+
+ static int gic_starting_cpu(unsigned int cpu)
+ {
++ /* Ensure the GIC counter is running */
++ clear_gic_config(GIC_CONFIG_COUNTSTOP);
++
+ gic_clockevent_cpu_init(cpu, this_cpu_ptr(&gic_clockevent_device));
+ return 0;
+ }
+@@ -288,9 +291,6 @@ static int __init gic_clocksource_of_init(struct device_node *node)
+ pr_warn("Unable to register clock notifier\n");
+ }
+
+- /* And finally start the counter */
+- clear_gic_config(GIC_CONFIG_COUNTSTOP);
+-
+ /*
+ * It's safe to use the MIPS GIC timer as a sched clock source only if
+ * its ticks are stable, which is true on either the platforms with
+--
+2.39.5
+
--- /dev/null
+From a7d4ef4a96f212a070eb5307084b91b68d82a792 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Mar 2025 12:11:04 +0000
+Subject: coresight: change coresight_trace_id_map's lock type to
+ raw_spinlock_t
+
+From: Yeoreum Yun <yeoreum.yun@arm.com>
+
+[ Upstream commit 4cf364ca57d851e192ce02e98d314d22fa514895 ]
+
+coresight_trace_id_map->lock can be acquired while coresight devices'
+drvdata_lock.
+
+But the drvdata_lock can be raw_spinlock_t (i.e) coresight-etm4x.
+
+To address this, change type of coresight_trace_id_map->lock to
+raw_spinlock_t
+
+Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
+Reviewed-by: James Clark <james.clark@linaro.org>
+Reviewed-by: Mike Leach <mike.leach@linaro.org>
+Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
+Link: https://lore.kernel.org/r/20250306121110.1647948-4-yeoreum.yun@arm.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwtracing/coresight/coresight-core.c | 2 +-
+ .../hwtracing/coresight/coresight-trace-id.c | 22 +++++++++----------
+ include/linux/coresight.h | 2 +-
+ 3 files changed, 13 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
+index 4936dc2f7a56b..4fe837b02e314 100644
+--- a/drivers/hwtracing/coresight/coresight-core.c
++++ b/drivers/hwtracing/coresight/coresight-core.c
+@@ -1249,7 +1249,7 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
+
+ if (csdev->type == CORESIGHT_DEV_TYPE_SINK ||
+ csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) {
+- spin_lock_init(&csdev->perf_sink_id_map.lock);
++ raw_spin_lock_init(&csdev->perf_sink_id_map.lock);
+ csdev->perf_sink_id_map.cpu_map = alloc_percpu(atomic_t);
+ if (!csdev->perf_sink_id_map.cpu_map) {
+ kfree(csdev);
+diff --git a/drivers/hwtracing/coresight/coresight-trace-id.c b/drivers/hwtracing/coresight/coresight-trace-id.c
+index 378af743be455..7ed337d54d3e3 100644
+--- a/drivers/hwtracing/coresight/coresight-trace-id.c
++++ b/drivers/hwtracing/coresight/coresight-trace-id.c
+@@ -22,7 +22,7 @@ enum trace_id_flags {
+ static DEFINE_PER_CPU(atomic_t, id_map_default_cpu_ids) = ATOMIC_INIT(0);
+ static struct coresight_trace_id_map id_map_default = {
+ .cpu_map = &id_map_default_cpu_ids,
+- .lock = __SPIN_LOCK_UNLOCKED(id_map_default.lock)
++ .lock = __RAW_SPIN_LOCK_UNLOCKED(id_map_default.lock)
+ };
+
+ /* #define TRACE_ID_DEBUG 1 */
+@@ -131,11 +131,11 @@ static void coresight_trace_id_release_all(struct coresight_trace_id_map *id_map
+ unsigned long flags;
+ int cpu;
+
+- spin_lock_irqsave(&id_map->lock, flags);
++ raw_spin_lock_irqsave(&id_map->lock, flags);
+ bitmap_zero(id_map->used_ids, CORESIGHT_TRACE_IDS_MAX);
+ for_each_possible_cpu(cpu)
+ atomic_set(per_cpu_ptr(id_map->cpu_map, cpu), 0);
+- spin_unlock_irqrestore(&id_map->lock, flags);
++ raw_spin_unlock_irqrestore(&id_map->lock, flags);
+ DUMP_ID_MAP(id_map);
+ }
+
+@@ -144,7 +144,7 @@ static int _coresight_trace_id_get_cpu_id(int cpu, struct coresight_trace_id_map
+ unsigned long flags;
+ int id;
+
+- spin_lock_irqsave(&id_map->lock, flags);
++ raw_spin_lock_irqsave(&id_map->lock, flags);
+
+ /* check for existing allocation for this CPU */
+ id = _coresight_trace_id_read_cpu_id(cpu, id_map);
+@@ -171,7 +171,7 @@ static int _coresight_trace_id_get_cpu_id(int cpu, struct coresight_trace_id_map
+ atomic_set(per_cpu_ptr(id_map->cpu_map, cpu), id);
+
+ get_cpu_id_out_unlock:
+- spin_unlock_irqrestore(&id_map->lock, flags);
++ raw_spin_unlock_irqrestore(&id_map->lock, flags);
+
+ DUMP_ID_CPU(cpu, id);
+ DUMP_ID_MAP(id_map);
+@@ -188,12 +188,12 @@ static void _coresight_trace_id_put_cpu_id(int cpu, struct coresight_trace_id_ma
+ if (!id)
+ return;
+
+- spin_lock_irqsave(&id_map->lock, flags);
++ raw_spin_lock_irqsave(&id_map->lock, flags);
+
+ coresight_trace_id_free(id, id_map);
+ atomic_set(per_cpu_ptr(id_map->cpu_map, cpu), 0);
+
+- spin_unlock_irqrestore(&id_map->lock, flags);
++ raw_spin_unlock_irqrestore(&id_map->lock, flags);
+ DUMP_ID_CPU(cpu, id);
+ DUMP_ID_MAP(id_map);
+ }
+@@ -204,9 +204,9 @@ static int coresight_trace_id_map_get_system_id(struct coresight_trace_id_map *i
+ unsigned long flags;
+ int id;
+
+- spin_lock_irqsave(&id_map->lock, flags);
++ raw_spin_lock_irqsave(&id_map->lock, flags);
+ id = coresight_trace_id_alloc_new_id(id_map, preferred_id, traceid_flags);
+- spin_unlock_irqrestore(&id_map->lock, flags);
++ raw_spin_unlock_irqrestore(&id_map->lock, flags);
+
+ DUMP_ID(id);
+ DUMP_ID_MAP(id_map);
+@@ -217,9 +217,9 @@ static void coresight_trace_id_map_put_system_id(struct coresight_trace_id_map *
+ {
+ unsigned long flags;
+
+- spin_lock_irqsave(&id_map->lock, flags);
++ raw_spin_lock_irqsave(&id_map->lock, flags);
+ coresight_trace_id_free(id, id_map);
+- spin_unlock_irqrestore(&id_map->lock, flags);
++ raw_spin_unlock_irqrestore(&id_map->lock, flags);
+
+ DUMP_ID(id);
+ DUMP_ID_MAP(id_map);
+diff --git a/include/linux/coresight.h b/include/linux/coresight.h
+index 6ddcbb8be5165..d5ca0292550b2 100644
+--- a/include/linux/coresight.h
++++ b/include/linux/coresight.h
+@@ -238,7 +238,7 @@ struct coresight_trace_id_map {
+ DECLARE_BITMAP(used_ids, CORESIGHT_TRACE_IDS_MAX);
+ atomic_t __percpu *cpu_map;
+ atomic_t perf_cs_etm_session_active;
+- spinlock_t lock;
++ raw_spinlock_t lock;
+ };
+
+ /**
+--
+2.39.5
+
--- /dev/null
+From c9dfeffe7703fb5208b8a73d1b276069bc018247 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Mar 2025 12:11:06 +0000
+Subject: coresight-etb10: change etb_drvdata spinlock's type to raw_spinlock_t
+
+From: Yeoreum Yun <yeoreum.yun@arm.com>
+
+[ Upstream commit 6b80c0abe475ed1017c5e862636049aa1cc17a1a ]
+
+In coresight-etb10 drivers, etb_drvdata->spinlock can be held
+during __schedule() by perf_event_task_sched_out()/in().
+
+Since etb_drvdata->spinlock type is spinlock_t and
+perf_event_task_sched_out()/in() is called after acquiring rq_lock,
+which is raw_spinlock_t (an unsleepable lock),
+this poses an issue in PREEMPT_RT kernel where spinlock_t is sleepable.
+
+To address this, change type etb_drvdata->spinlock in coresight-etb10 drivers,
+which can be called by perf_event_task_sched_out()/in(),
+from spinlock_t to raw_spinlock_t.
+
+Reviewed-by: James Clark <james.clark@linaro.org>
+Reviewed-by: Mike Leach <mike.leach@linaro.org>
+Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
+Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
+Link: https://lore.kernel.org/r/20250306121110.1647948-6-yeoreum.yun@arm.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwtracing/coresight/coresight-etb10.c | 26 +++++++++----------
+ 1 file changed, 13 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c
+index aea9ac9c4bd06..7948597d483d2 100644
+--- a/drivers/hwtracing/coresight/coresight-etb10.c
++++ b/drivers/hwtracing/coresight/coresight-etb10.c
+@@ -84,7 +84,7 @@ struct etb_drvdata {
+ struct clk *atclk;
+ struct coresight_device *csdev;
+ struct miscdevice miscdev;
+- spinlock_t spinlock;
++ raw_spinlock_t spinlock;
+ local_t reading;
+ pid_t pid;
+ u8 *buf;
+@@ -145,7 +145,7 @@ static int etb_enable_sysfs(struct coresight_device *csdev)
+ unsigned long flags;
+ struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+- spin_lock_irqsave(&drvdata->spinlock, flags);
++ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
+
+ /* Don't messup with perf sessions. */
+ if (coresight_get_mode(csdev) == CS_MODE_PERF) {
+@@ -163,7 +163,7 @@ static int etb_enable_sysfs(struct coresight_device *csdev)
+
+ csdev->refcnt++;
+ out:
+- spin_unlock_irqrestore(&drvdata->spinlock, flags);
++ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ return ret;
+ }
+
+@@ -176,7 +176,7 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data)
+ struct perf_output_handle *handle = data;
+ struct cs_buffers *buf = etm_perf_sink_config(handle);
+
+- spin_lock_irqsave(&drvdata->spinlock, flags);
++ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
+
+ /* No need to continue if the component is already in used by sysFS. */
+ if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) {
+@@ -219,7 +219,7 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data)
+ }
+
+ out:
+- spin_unlock_irqrestore(&drvdata->spinlock, flags);
++ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ return ret;
+ }
+
+@@ -352,11 +352,11 @@ static int etb_disable(struct coresight_device *csdev)
+ struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+ unsigned long flags;
+
+- spin_lock_irqsave(&drvdata->spinlock, flags);
++ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
+
+ csdev->refcnt--;
+ if (csdev->refcnt) {
+- spin_unlock_irqrestore(&drvdata->spinlock, flags);
++ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ return -EBUSY;
+ }
+
+@@ -366,7 +366,7 @@ static int etb_disable(struct coresight_device *csdev)
+ /* Dissociate from monitored process. */
+ drvdata->pid = -1;
+ coresight_set_mode(csdev, CS_MODE_DISABLED);
+- spin_unlock_irqrestore(&drvdata->spinlock, flags);
++ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+ dev_dbg(&csdev->dev, "ETB disabled\n");
+ return 0;
+@@ -443,7 +443,7 @@ static unsigned long etb_update_buffer(struct coresight_device *csdev,
+
+ capacity = drvdata->buffer_depth * ETB_FRAME_SIZE_WORDS;
+
+- spin_lock_irqsave(&drvdata->spinlock, flags);
++ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
+
+ /* Don't do anything if another tracer is using this sink */
+ if (csdev->refcnt != 1)
+@@ -566,7 +566,7 @@ static unsigned long etb_update_buffer(struct coresight_device *csdev,
+ __etb_enable_hw(drvdata);
+ CS_LOCK(drvdata->base);
+ out:
+- spin_unlock_irqrestore(&drvdata->spinlock, flags);
++ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+ return to_read;
+ }
+@@ -587,13 +587,13 @@ static void etb_dump(struct etb_drvdata *drvdata)
+ {
+ unsigned long flags;
+
+- spin_lock_irqsave(&drvdata->spinlock, flags);
++ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
+ if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) {
+ __etb_disable_hw(drvdata);
+ etb_dump_hw(drvdata);
+ __etb_enable_hw(drvdata);
+ }
+- spin_unlock_irqrestore(&drvdata->spinlock, flags);
++ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+ dev_dbg(&drvdata->csdev->dev, "ETB dumped\n");
+ }
+@@ -746,7 +746,7 @@ static int etb_probe(struct amba_device *adev, const struct amba_id *id)
+ drvdata->base = base;
+ desc.access = CSDEV_ACCESS_IOMEM(base);
+
+- spin_lock_init(&drvdata->spinlock);
++ raw_spin_lock_init(&drvdata->spinlock);
+
+ drvdata->buffer_depth = etb_get_buffer_depth(drvdata);
+
+--
+2.39.5
+
--- /dev/null
+From a96811ead052549039116ec90eca6f46b159880f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 5 Apr 2025 00:42:19 +0800
+Subject: cpufreq: Add SM8650 to cpufreq-dt-platdev blocklist
+
+From: Pengyu Luo <mitltlatltl@gmail.com>
+
+[ Upstream commit fc5414a4774e14e51a93499a6adfdc45f2de82e0 ]
+
+SM8650 have already been supported by qcom-cpufreq-hw driver, but
+never been added to cpufreq-dt-platdev. This makes noise
+
+[ 0.388525] cpufreq-dt cpufreq-dt: failed register driver: -17
+[ 0.388537] cpufreq-dt cpufreq-dt: probe with driver cpufreq-dt failed with error -17
+
+So adding it to the cpufreq-dt-platdev driver's blocklist to fix it.
+
+Signed-off-by: Pengyu Luo <mitltlatltl@gmail.com>
+Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/cpufreq/cpufreq-dt-platdev.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c
+index 2aa00769cf09d..a010da0f6337f 100644
+--- a/drivers/cpufreq/cpufreq-dt-platdev.c
++++ b/drivers/cpufreq/cpufreq-dt-platdev.c
+@@ -175,6 +175,7 @@ static const struct of_device_id blocklist[] __initconst = {
+ { .compatible = "qcom,sm8350", },
+ { .compatible = "qcom,sm8450", },
+ { .compatible = "qcom,sm8550", },
++ { .compatible = "qcom,sm8650", },
+
+ { .compatible = "st,stih407", },
+ { .compatible = "st,stih410", },
+--
+2.39.5
+
--- /dev/null
+From 32df8429ab52fedd70a6806300767b44d844c0de Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jan 2025 08:52:52 +0000
+Subject: cpufreq: amd-pstate: Remove unnecessary driver_lock in set_boost
+
+From: Dhananjay Ugwekar <dhananjay.ugwekar@amd.com>
+
+[ Upstream commit db1cafc77aaaf871509da06f4a864e9af6d6791f ]
+
+set_boost is a per-policy function call, hence a driver wide lock is
+unnecessary. Also this mutex_acquire can collide with the mutex_acquire
+from the mode-switch path in status_store(), which can lead to a
+deadlock. So, remove it.
+
+Signed-off-by: Dhananjay Ugwekar <dhananjay.ugwekar@amd.com>
+Acked-by: Mario Limonciello <mario.limonciello@amd.com>
+Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/cpufreq/amd-pstate.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
+index 1b26845703f68..a27749d948b46 100644
+--- a/drivers/cpufreq/amd-pstate.c
++++ b/drivers/cpufreq/amd-pstate.c
+@@ -746,7 +746,6 @@ static int amd_pstate_set_boost(struct cpufreq_policy *policy, int state)
+ pr_err("Boost mode is not supported by this processor or SBIOS\n");
+ return -EOPNOTSUPP;
+ }
+- guard(mutex)(&amd_pstate_driver_lock);
+
+ ret = amd_pstate_cpu_boost_update(policy, state);
+ refresh_frequency_limits(policy);
+--
+2.39.5
+
--- /dev/null
+From 29e00595bde32c56a6ea7eb2e3f58e59e7e6fabe Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 10 Mar 2025 00:28:48 -0500
+Subject: cpufreq: tegra186: Share policy per cluster
+
+From: Aaron Kling <luceoscutum@gmail.com>
+
+[ Upstream commit be4ae8c19492cd6d5de61ccb34ffb3f5ede5eec8 ]
+
+This functionally brings tegra186 in line with tegra210 and tegra194,
+sharing a cpufreq policy between all cores in a cluster.
+
+Reviewed-by: Sumit Gupta <sumitg@nvidia.com>
+Acked-by: Thierry Reding <treding@nvidia.com>
+Signed-off-by: Aaron Kling <webgeek1234@gmail.com>
+Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/cpufreq/tegra186-cpufreq.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/drivers/cpufreq/tegra186-cpufreq.c b/drivers/cpufreq/tegra186-cpufreq.c
+index c7761eb99f3cc..92aa50f016660 100644
+--- a/drivers/cpufreq/tegra186-cpufreq.c
++++ b/drivers/cpufreq/tegra186-cpufreq.c
+@@ -73,11 +73,18 @@ static int tegra186_cpufreq_init(struct cpufreq_policy *policy)
+ {
+ struct tegra186_cpufreq_data *data = cpufreq_get_driver_data();
+ unsigned int cluster = data->cpus[policy->cpu].bpmp_cluster_id;
++ u32 cpu;
+
+ policy->freq_table = data->clusters[cluster].table;
+ policy->cpuinfo.transition_latency = 300 * 1000;
+ policy->driver_data = NULL;
+
++ /* set same policy for all cpus in a cluster */
++ for (cpu = 0; cpu < ARRAY_SIZE(tegra186_cpus); cpu++) {
++ if (data->cpus[cpu].bpmp_cluster_id == cluster)
++ cpumask_set_cpu(cpu, policy->cpus);
++ }
++
+ return 0;
+ }
+
+--
+2.39.5
+
--- /dev/null
+From 4636aac1aa5e33108d0b70f6ea77c9e9cc973b59 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Feb 2025 15:29:05 +0100
+Subject: cpuidle: menu: Avoid discarding useful information
+
+From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+
+[ Upstream commit 85975daeaa4d6ec560bfcd354fc9c08ad7f38888 ]
+
+When giving up on making a high-confidence prediction,
+get_typical_interval() always returns UINT_MAX which means that the
+next idle interval prediction will be based entirely on the time till
+the next timer. However, the information represented by the most
+recent intervals may not be completely useless in those cases.
+
+Namely, the largest recent idle interval is an upper bound on the
+recently observed idle duration, so it is reasonable to assume that
+the next idle duration is unlikely to exceed it. Moreover, this is
+still true after eliminating the suspected outliers if the sample
+set still under consideration is at least as large as 50% of the
+maximum sample set size.
+
+Accordingly, make get_typical_interval() return the current maximum
+recent interval value in that case instead of UINT_MAX.
+
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Reported-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
+Tested-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
+Reviewed-by: Christian Loehle <christian.loehle@arm.com>
+Tested-by: Christian Loehle <christian.loehle@arm.com>
+Tested-by: Aboorva Devarajan <aboorvad@linux.ibm.com>
+Link: https://patch.msgid.link/7770672.EvYhyI6sBW@rjwysocki.net
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/cpuidle/governors/menu.c | 13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
+index 28363bfa3e4c9..42b77d820d0fb 100644
+--- a/drivers/cpuidle/governors/menu.c
++++ b/drivers/cpuidle/governors/menu.c
+@@ -192,8 +192,19 @@ static unsigned int get_typical_interval(struct menu_device *data)
+ * This can deal with workloads that have long pauses interspersed
+ * with sporadic activity with a bunch of short pauses.
+ */
+- if ((divisor * 4) <= INTERVALS * 3)
++ if (divisor * 4 <= INTERVALS * 3) {
++ /*
++ * If there are sufficiently many data points still under
++ * consideration after the outliers have been eliminated,
++ * returning without a prediction would be a mistake because it
++ * is likely that the next interval will not exceed the current
++ * maximum, so return the latter in that case.
++ */
++ if (divisor >= INTERVALS / 2)
++ return max;
++
+ return UINT_MAX;
++ }
+
+ thresh = max - 1;
+ goto again;
+--
+2.39.5
+
--- /dev/null
+From b78106c5c1af0c11c1df4f7957ba3ec9e1b76803 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 16 Feb 2025 11:07:24 +0800
+Subject: crypto: ahash - Set default reqsize from ahash_alg
+
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+[ Upstream commit 9e01aaa1033d6e40f8d7cf4f20931a61ce9e3f04 ]
+
+Add a reqsize field to struct ahash_alg and use it to set the
+default reqsize so that algorithms with a static reqsize are
+not forced to create an init_tfm function.
+
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ crypto/ahash.c | 4 ++++
+ include/crypto/hash.h | 3 +++
+ 2 files changed, 7 insertions(+)
+
+diff --git a/crypto/ahash.c b/crypto/ahash.c
+index b08b89ec26ec5..63960465eea17 100644
+--- a/crypto/ahash.c
++++ b/crypto/ahash.c
+@@ -489,6 +489,7 @@ static int crypto_ahash_init_tfm(struct crypto_tfm *tfm)
+ struct ahash_alg *alg = crypto_ahash_alg(hash);
+
+ crypto_ahash_set_statesize(hash, alg->halg.statesize);
++ crypto_ahash_set_reqsize(hash, alg->reqsize);
+
+ if (tfm->__crt_alg->cra_type == &crypto_shash_type)
+ return crypto_init_ahash_using_shash(tfm);
+@@ -654,6 +655,9 @@ static int ahash_prepare_alg(struct ahash_alg *alg)
+ if (alg->halg.statesize == 0)
+ return -EINVAL;
+
++ if (alg->reqsize && alg->reqsize < alg->halg.statesize)
++ return -EINVAL;
++
+ err = hash_prepare_alg(&alg->halg);
+ if (err)
+ return err;
+diff --git a/include/crypto/hash.h b/include/crypto/hash.h
+index 2d5ea9f9ff43e..6692253f0b5be 100644
+--- a/include/crypto/hash.h
++++ b/include/crypto/hash.h
+@@ -132,6 +132,7 @@ struct ahash_request {
+ * This is a counterpart to @init_tfm, used to remove
+ * various changes set in @init_tfm.
+ * @clone_tfm: Copy transform into new object, may allocate memory.
++ * @reqsize: Size of the request context.
+ * @halg: see struct hash_alg_common
+ */
+ struct ahash_alg {
+@@ -148,6 +149,8 @@ struct ahash_alg {
+ void (*exit_tfm)(struct crypto_ahash *tfm);
+ int (*clone_tfm)(struct crypto_ahash *dst, struct crypto_ahash *src);
+
++ unsigned int reqsize;
++
+ struct hash_alg_common halg;
+ };
+
+--
+2.39.5
+
--- /dev/null
+From 8fce077b224f582f53b70a8cae0cc28fdfaeb89b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Feb 2025 17:04:46 +0800
+Subject: crypto: lzo - Fix compression buffer overrun
+
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+[ Upstream commit cc47f07234f72cbd8e2c973cdbf2a6730660a463 ]
+
+Unlike the decompression code, the compression code in LZO never
+checked for output overruns. It instead assumes that the caller
+always provides enough buffer space, disregarding the buffer length
+provided by the caller.
+
+Add a safe compression interface that checks for the end of buffer
+before each write. Use the safe interface in crypto/lzo.
+
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ crypto/lzo-rle.c | 2 +-
+ crypto/lzo.c | 2 +-
+ include/linux/lzo.h | 8 +++
+ lib/lzo/Makefile | 2 +-
+ lib/lzo/lzo1x_compress.c | 102 +++++++++++++++++++++++++---------
+ lib/lzo/lzo1x_compress_safe.c | 18 ++++++
+ 6 files changed, 106 insertions(+), 28 deletions(-)
+ create mode 100644 lib/lzo/lzo1x_compress_safe.c
+
+diff --git a/crypto/lzo-rle.c b/crypto/lzo-rle.c
+index 0631d975bfac1..0abc2d87f0420 100644
+--- a/crypto/lzo-rle.c
++++ b/crypto/lzo-rle.c
+@@ -55,7 +55,7 @@ static int __lzorle_compress(const u8 *src, unsigned int slen,
+ size_t tmp_len = *dlen; /* size_t(ulong) <-> uint on 64 bit */
+ int err;
+
+- err = lzorle1x_1_compress(src, slen, dst, &tmp_len, ctx);
++ err = lzorle1x_1_compress_safe(src, slen, dst, &tmp_len, ctx);
+
+ if (err != LZO_E_OK)
+ return -EINVAL;
+diff --git a/crypto/lzo.c b/crypto/lzo.c
+index ebda132dd22bf..8338851c7406a 100644
+--- a/crypto/lzo.c
++++ b/crypto/lzo.c
+@@ -55,7 +55,7 @@ static int __lzo_compress(const u8 *src, unsigned int slen,
+ size_t tmp_len = *dlen; /* size_t(ulong) <-> uint on 64 bit */
+ int err;
+
+- err = lzo1x_1_compress(src, slen, dst, &tmp_len, ctx);
++ err = lzo1x_1_compress_safe(src, slen, dst, &tmp_len, ctx);
+
+ if (err != LZO_E_OK)
+ return -EINVAL;
+diff --git a/include/linux/lzo.h b/include/linux/lzo.h
+index e95c7d1092b28..4d30e3624acd2 100644
+--- a/include/linux/lzo.h
++++ b/include/linux/lzo.h
+@@ -24,10 +24,18 @@
+ int lzo1x_1_compress(const unsigned char *src, size_t src_len,
+ unsigned char *dst, size_t *dst_len, void *wrkmem);
+
++/* Same as above but does not write more than dst_len to dst. */
++int lzo1x_1_compress_safe(const unsigned char *src, size_t src_len,
++ unsigned char *dst, size_t *dst_len, void *wrkmem);
++
+ /* This requires 'wrkmem' of size LZO1X_1_MEM_COMPRESS */
+ int lzorle1x_1_compress(const unsigned char *src, size_t src_len,
+ unsigned char *dst, size_t *dst_len, void *wrkmem);
+
++/* Same as above but does not write more than dst_len to dst. */
++int lzorle1x_1_compress_safe(const unsigned char *src, size_t src_len,
++ unsigned char *dst, size_t *dst_len, void *wrkmem);
++
+ /* safe decompression with overrun testing */
+ int lzo1x_decompress_safe(const unsigned char *src, size_t src_len,
+ unsigned char *dst, size_t *dst_len);
+diff --git a/lib/lzo/Makefile b/lib/lzo/Makefile
+index 2f58fafbbdddc..fc7b2b7ef4b20 100644
+--- a/lib/lzo/Makefile
++++ b/lib/lzo/Makefile
+@@ -1,5 +1,5 @@
+ # SPDX-License-Identifier: GPL-2.0-only
+-lzo_compress-objs := lzo1x_compress.o
++lzo_compress-objs := lzo1x_compress.o lzo1x_compress_safe.o
+ lzo_decompress-objs := lzo1x_decompress_safe.o
+
+ obj-$(CONFIG_LZO_COMPRESS) += lzo_compress.o
+diff --git a/lib/lzo/lzo1x_compress.c b/lib/lzo/lzo1x_compress.c
+index 47d6d43ea9578..7b10ca86a8930 100644
+--- a/lib/lzo/lzo1x_compress.c
++++ b/lib/lzo/lzo1x_compress.c
+@@ -18,11 +18,22 @@
+ #include <linux/lzo.h>
+ #include "lzodefs.h"
+
+-static noinline size_t
+-lzo1x_1_do_compress(const unsigned char *in, size_t in_len,
+- unsigned char *out, size_t *out_len,
+- size_t ti, void *wrkmem, signed char *state_offset,
+- const unsigned char bitstream_version)
++#undef LZO_UNSAFE
++
++#ifndef LZO_SAFE
++#define LZO_UNSAFE 1
++#define LZO_SAFE(name) name
++#define HAVE_OP(x) 1
++#endif
++
++#define NEED_OP(x) if (!HAVE_OP(x)) goto output_overrun
++
++static noinline int
++LZO_SAFE(lzo1x_1_do_compress)(const unsigned char *in, size_t in_len,
++ unsigned char **out, unsigned char *op_end,
++ size_t *tp, void *wrkmem,
++ signed char *state_offset,
++ const unsigned char bitstream_version)
+ {
+ const unsigned char *ip;
+ unsigned char *op;
+@@ -30,8 +41,9 @@ lzo1x_1_do_compress(const unsigned char *in, size_t in_len,
+ const unsigned char * const ip_end = in + in_len - 20;
+ const unsigned char *ii;
+ lzo_dict_t * const dict = (lzo_dict_t *) wrkmem;
++ size_t ti = *tp;
+
+- op = out;
++ op = *out;
+ ip = in;
+ ii = ip;
+ ip += ti < 4 ? 4 - ti : 0;
+@@ -116,25 +128,32 @@ lzo1x_1_do_compress(const unsigned char *in, size_t in_len,
+ if (t != 0) {
+ if (t <= 3) {
+ op[*state_offset] |= t;
++ NEED_OP(4);
+ COPY4(op, ii);
+ op += t;
+ } else if (t <= 16) {
++ NEED_OP(17);
+ *op++ = (t - 3);
+ COPY8(op, ii);
+ COPY8(op + 8, ii + 8);
+ op += t;
+ } else {
+ if (t <= 18) {
++ NEED_OP(1);
+ *op++ = (t - 3);
+ } else {
+ size_t tt = t - 18;
++ NEED_OP(1);
+ *op++ = 0;
+ while (unlikely(tt > 255)) {
+ tt -= 255;
++ NEED_OP(1);
+ *op++ = 0;
+ }
++ NEED_OP(1);
+ *op++ = tt;
+ }
++ NEED_OP(t);
+ do {
+ COPY8(op, ii);
+ COPY8(op + 8, ii + 8);
+@@ -151,6 +170,7 @@ lzo1x_1_do_compress(const unsigned char *in, size_t in_len,
+ if (unlikely(run_length)) {
+ ip += run_length;
+ run_length -= MIN_ZERO_RUN_LENGTH;
++ NEED_OP(4);
+ put_unaligned_le32((run_length << 21) | 0xfffc18
+ | (run_length & 0x7), op);
+ op += 4;
+@@ -243,10 +263,12 @@ lzo1x_1_do_compress(const unsigned char *in, size_t in_len,
+ ip += m_len;
+ if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET) {
+ m_off -= 1;
++ NEED_OP(2);
+ *op++ = (((m_len - 1) << 5) | ((m_off & 7) << 2));
+ *op++ = (m_off >> 3);
+ } else if (m_off <= M3_MAX_OFFSET) {
+ m_off -= 1;
++ NEED_OP(1);
+ if (m_len <= M3_MAX_LEN)
+ *op++ = (M3_MARKER | (m_len - 2));
+ else {
+@@ -254,14 +276,18 @@ lzo1x_1_do_compress(const unsigned char *in, size_t in_len,
+ *op++ = M3_MARKER | 0;
+ while (unlikely(m_len > 255)) {
+ m_len -= 255;
++ NEED_OP(1);
+ *op++ = 0;
+ }
++ NEED_OP(1);
+ *op++ = (m_len);
+ }
++ NEED_OP(2);
+ *op++ = (m_off << 2);
+ *op++ = (m_off >> 6);
+ } else {
+ m_off -= 0x4000;
++ NEED_OP(1);
+ if (m_len <= M4_MAX_LEN)
+ *op++ = (M4_MARKER | ((m_off >> 11) & 8)
+ | (m_len - 2));
+@@ -282,11 +308,14 @@ lzo1x_1_do_compress(const unsigned char *in, size_t in_len,
+ m_len -= M4_MAX_LEN;
+ *op++ = (M4_MARKER | ((m_off >> 11) & 8));
+ while (unlikely(m_len > 255)) {
++ NEED_OP(1);
+ m_len -= 255;
+ *op++ = 0;
+ }
++ NEED_OP(1);
+ *op++ = (m_len);
+ }
++ NEED_OP(2);
+ *op++ = (m_off << 2);
+ *op++ = (m_off >> 6);
+ }
+@@ -295,14 +324,20 @@ lzo1x_1_do_compress(const unsigned char *in, size_t in_len,
+ ii = ip;
+ goto next;
+ }
+- *out_len = op - out;
+- return in_end - (ii - ti);
++ *out = op;
++ *tp = in_end - (ii - ti);
++ return LZO_E_OK;
++
++output_overrun:
++ return LZO_E_OUTPUT_OVERRUN;
+ }
+
+-static int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len,
+- unsigned char *out, size_t *out_len,
+- void *wrkmem, const unsigned char bitstream_version)
++static int LZO_SAFE(lzogeneric1x_1_compress)(
++ const unsigned char *in, size_t in_len,
++ unsigned char *out, size_t *out_len,
++ void *wrkmem, const unsigned char bitstream_version)
+ {
++ unsigned char * const op_end = out + *out_len;
+ const unsigned char *ip = in;
+ unsigned char *op = out;
+ unsigned char *data_start;
+@@ -326,14 +361,18 @@ static int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len,
+ while (l > 20) {
+ size_t ll = min_t(size_t, l, m4_max_offset + 1);
+ uintptr_t ll_end = (uintptr_t) ip + ll;
++ int err;
++
+ if ((ll_end + ((t + ll) >> 5)) <= ll_end)
+ break;
+ BUILD_BUG_ON(D_SIZE * sizeof(lzo_dict_t) > LZO1X_1_MEM_COMPRESS);
+ memset(wrkmem, 0, D_SIZE * sizeof(lzo_dict_t));
+- t = lzo1x_1_do_compress(ip, ll, op, out_len, t, wrkmem,
+- &state_offset, bitstream_version);
++ err = LZO_SAFE(lzo1x_1_do_compress)(
++ ip, ll, &op, op_end, &t, wrkmem,
++ &state_offset, bitstream_version);
++ if (err != LZO_E_OK)
++ return err;
+ ip += ll;
+- op += *out_len;
+ l -= ll;
+ }
+ t += l;
+@@ -342,20 +381,26 @@ static int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len,
+ const unsigned char *ii = in + in_len - t;
+
+ if (op == data_start && t <= 238) {
++ NEED_OP(1);
+ *op++ = (17 + t);
+ } else if (t <= 3) {
+ op[state_offset] |= t;
+ } else if (t <= 18) {
++ NEED_OP(1);
+ *op++ = (t - 3);
+ } else {
+ size_t tt = t - 18;
++ NEED_OP(1);
+ *op++ = 0;
+ while (tt > 255) {
+ tt -= 255;
++ NEED_OP(1);
+ *op++ = 0;
+ }
++ NEED_OP(1);
+ *op++ = tt;
+ }
++ NEED_OP(t);
+ if (t >= 16) do {
+ COPY8(op, ii);
+ COPY8(op + 8, ii + 8);
+@@ -368,31 +413,38 @@ static int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len,
+ } while (--t > 0);
+ }
+
++ NEED_OP(3);
+ *op++ = M4_MARKER | 1;
+ *op++ = 0;
+ *op++ = 0;
+
+ *out_len = op - out;
+ return LZO_E_OK;
++
++output_overrun:
++ return LZO_E_OUTPUT_OVERRUN;
+ }
+
+-int lzo1x_1_compress(const unsigned char *in, size_t in_len,
+- unsigned char *out, size_t *out_len,
+- void *wrkmem)
++int LZO_SAFE(lzo1x_1_compress)(const unsigned char *in, size_t in_len,
++ unsigned char *out, size_t *out_len,
++ void *wrkmem)
+ {
+- return lzogeneric1x_1_compress(in, in_len, out, out_len, wrkmem, 0);
++ return LZO_SAFE(lzogeneric1x_1_compress)(
++ in, in_len, out, out_len, wrkmem, 0);
+ }
+
+-int lzorle1x_1_compress(const unsigned char *in, size_t in_len,
+- unsigned char *out, size_t *out_len,
+- void *wrkmem)
++int LZO_SAFE(lzorle1x_1_compress)(const unsigned char *in, size_t in_len,
++ unsigned char *out, size_t *out_len,
++ void *wrkmem)
+ {
+- return lzogeneric1x_1_compress(in, in_len, out, out_len,
+- wrkmem, LZO_VERSION);
++ return LZO_SAFE(lzogeneric1x_1_compress)(
++ in, in_len, out, out_len, wrkmem, LZO_VERSION);
+ }
+
+-EXPORT_SYMBOL_GPL(lzo1x_1_compress);
+-EXPORT_SYMBOL_GPL(lzorle1x_1_compress);
++EXPORT_SYMBOL_GPL(LZO_SAFE(lzo1x_1_compress));
++EXPORT_SYMBOL_GPL(LZO_SAFE(lzorle1x_1_compress));
+
++#ifndef LZO_UNSAFE
+ MODULE_LICENSE("GPL");
+ MODULE_DESCRIPTION("LZO1X-1 Compressor");
++#endif
+diff --git a/lib/lzo/lzo1x_compress_safe.c b/lib/lzo/lzo1x_compress_safe.c
+new file mode 100644
+index 0000000000000..371c9f8494928
+--- /dev/null
++++ b/lib/lzo/lzo1x_compress_safe.c
+@@ -0,0 +1,18 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * LZO1X Compressor from LZO
++ *
++ * Copyright (C) 1996-2012 Markus F.X.J. Oberhumer <markus@oberhumer.com>
++ *
++ * The full LZO package can be found at:
++ * http://www.oberhumer.com/opensource/lzo/
++ *
++ * Changed for Linux kernel use by:
++ * Nitin Gupta <nitingupta910@gmail.com>
++ * Richard Purdie <rpurdie@openedhand.com>
++ */
++
++#define LZO_SAFE(name) name##_safe
++#define HAVE_OP(x) ((size_t)(op_end - op) >= (size_t)(x))
++
++#include "lzo1x_compress.c"
+--
+2.39.5
+
--- /dev/null
+From c2c6242e6031e34c0d4d0c273e6791f1ab7f5bd0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 24 Feb 2025 08:42:25 +0100
+Subject: crypto: mxs-dcp - Only set OTP_KEY bit for OTP key
+
+From: Sven Schwermer <sven@svenschwermer.de>
+
+[ Upstream commit caa9dbb76ff52ec848a57245062aaeaa07740adc ]
+
+While MXS_DCP_CONTROL0_OTP_KEY is set, the CRYPTO_KEY (DCP_PAES_KEY_OTP)
+is used even if the UNIQUE_KEY (DCP_PAES_KEY_UNIQUE) is selected. This
+is not clearly documented, but this implementation is consistent with
+NXP's downstream kernel fork and optee_os.
+
+Signed-off-by: Sven Schwermer <sven@svenschwermer.de>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/crypto/mxs-dcp.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/crypto/mxs-dcp.c b/drivers/crypto/mxs-dcp.c
+index d94a26c3541a0..133ebc9982362 100644
+--- a/drivers/crypto/mxs-dcp.c
++++ b/drivers/crypto/mxs-dcp.c
+@@ -265,12 +265,12 @@ static int mxs_dcp_run_aes(struct dcp_async_ctx *actx,
+ MXS_DCP_CONTROL0_INTERRUPT |
+ MXS_DCP_CONTROL0_ENABLE_CIPHER;
+
+- if (key_referenced)
+- /* Set OTP key bit to select the key via KEY_SELECT. */
+- desc->control0 |= MXS_DCP_CONTROL0_OTP_KEY;
+- else
++ if (!key_referenced)
+ /* Payload contains the key. */
+ desc->control0 |= MXS_DCP_CONTROL0_PAYLOAD_KEY;
++ else if (actx->key[0] == DCP_PAES_KEY_OTP)
++ /* Set OTP key bit to select the key via KEY_SELECT. */
++ desc->control0 |= MXS_DCP_CONTROL0_OTP_KEY;
+
+ if (rctx->enc)
+ desc->control0 |= MXS_DCP_CONTROL0_CIPHER_ENCRYPT;
+--
+2.39.5
+
--- /dev/null
+From 3a5be13db66f2cff9733a113ee32ec6d671c745d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Mar 2025 13:27:05 +0530
+Subject: crypto: octeontx2 - suppress auth failure screaming due to negative
+ tests
+
+From: Shashank Gupta <shashankg@marvell.com>
+
+[ Upstream commit 64b7871522a4cba99d092e1c849d6f9092868aaa ]
+
+This patch addresses an issue where authentication failures were being
+erroneously reported due to negative test failures in the "ccm(aes)"
+selftest.
+pr_debug suppress unnecessary screaming of these tests.
+
+Signed-off-by: Shashank Gupta <shashankg@marvell.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/crypto/marvell/octeontx2/otx2_cptvf_reqmgr.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptvf_reqmgr.c b/drivers/crypto/marvell/octeontx2/otx2_cptvf_reqmgr.c
+index 5387c68f3c9df..4262441070372 100644
+--- a/drivers/crypto/marvell/octeontx2/otx2_cptvf_reqmgr.c
++++ b/drivers/crypto/marvell/octeontx2/otx2_cptvf_reqmgr.c
+@@ -264,9 +264,10 @@ static int cpt_process_ccode(struct otx2_cptlfs_info *lfs,
+ break;
+ }
+
+- dev_err(&pdev->dev,
+- "Request failed with software error code 0x%x\n",
+- cpt_status->s.uc_compcode);
++ pr_debug("Request failed with software error code 0x%x: algo = %s driver = %s\n",
++ cpt_status->s.uc_compcode,
++ info->req->areq->tfm->__crt_alg->cra_name,
++ info->req->areq->tfm->__crt_alg->cra_driver_name);
+ otx2_cpt_dump_sg_list(pdev, info->req);
+ break;
+ }
+--
+2.39.5
+
--- /dev/null
+From aedd55876d9a1116ef17dab126e6b103b8500781 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 15 Feb 2025 08:57:51 +0800
+Subject: crypto: skcipher - Zap type in crypto_alloc_sync_skcipher
+
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+[ Upstream commit ee509efc74ddbc59bb5d6fd6e050f9ef25f74bff ]
+
+The type needs to be zeroed as otherwise the user could use it to
+allocate an asynchronous sync skcipher.
+
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ crypto/skcipher.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/crypto/skcipher.c b/crypto/skcipher.c
+index a9eb2dcf28982..2d2b1589a0097 100644
+--- a/crypto/skcipher.c
++++ b/crypto/skcipher.c
+@@ -681,6 +681,7 @@ struct crypto_sync_skcipher *crypto_alloc_sync_skcipher(
+
+ /* Only sync algorithms allowed. */
+ mask |= CRYPTO_ALG_ASYNC | CRYPTO_ALG_SKCIPHER_REQSIZE_LARGE;
++ type &= ~(CRYPTO_ALG_ASYNC | CRYPTO_ALG_SKCIPHER_REQSIZE_LARGE);
+
+ tfm = crypto_alloc_tfm(alg_name, &crypto_skcipher_type, type, mask);
+
+--
+2.39.5
+
--- /dev/null
+From a0f1a794b640c15fb298bf5dde189fba6e5d53fe Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 10 Mar 2025 15:36:21 +0800
+Subject: dlm: make tcp still work in multi-link env
+
+From: Heming Zhao <heming.zhao@suse.com>
+
+[ Upstream commit 03d2b62208a336a3bb984b9465ef6d89a046ea22 ]
+
+This patch bypasses multi-link errors in TCP mode, allowing dlm
+to operate on the first tcp link.
+
+Signed-off-by: Heming Zhao <heming.zhao@suse.com>
+Signed-off-by: David Teigland <teigland@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/dlm/lowcomms.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c
+index d28141829c051..70abd4da17a63 100644
+--- a/fs/dlm/lowcomms.c
++++ b/fs/dlm/lowcomms.c
+@@ -1826,8 +1826,8 @@ static int dlm_tcp_listen_validate(void)
+ {
+ /* We don't support multi-homed hosts */
+ if (dlm_local_count > 1) {
+- log_print("TCP protocol can't handle multi-homed hosts, try SCTP");
+- return -EINVAL;
++ log_print("Detect multi-homed hosts but use only the first IP address.");
++ log_print("Try SCTP, if you want to enable multi-link.");
+ }
+
+ return 0;
+--
+2.39.5
+
--- /dev/null
+From fdf782a38445155ff9f22039d1ae32cbd8a261a0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Mar 2025 16:41:50 +0800
+Subject: dm cache: prevent BUG_ON by blocking retries on failed device resumes
+
+From: Ming-Hung Tsai <mtsai@redhat.com>
+
+[ Upstream commit 5da692e2262b8f81993baa9592f57d12c2703dea ]
+
+A cache device failing to resume due to mapping errors should not be
+retried, as the failure leaves a partially initialized policy object.
+Repeating the resume operation risks triggering BUG_ON when reloading
+cache mappings into the incomplete policy object.
+
+Reproduce steps:
+
+1. create a cache metadata consisting of 512 or more cache blocks,
+ with some mappings stored in the first array block of the mapping
+ array. Here we use cache_restore v1.0 to build the metadata.
+
+cat <<EOF >> cmeta.xml
+<superblock uuid="" block_size="128" nr_cache_blocks="512" \
+policy="smq" hint_width="4">
+ <mappings>
+ <mapping cache_block="0" origin_block="0" dirty="false"/>
+ </mappings>
+</superblock>
+EOF
+dmsetup create cmeta --table "0 8192 linear /dev/sdc 0"
+cache_restore -i cmeta.xml -o /dev/mapper/cmeta --metadata-version=2
+dmsetup remove cmeta
+
+2. wipe the second array block of the mapping array to simulate
+ data degradations.
+
+mapping_root=$(dd if=/dev/sdc bs=1c count=8 skip=192 \
+2>/dev/null | hexdump -e '1/8 "%u\n"')
+ablock=$(dd if=/dev/sdc bs=1c count=8 skip=$((4096*mapping_root+2056)) \
+2>/dev/null | hexdump -e '1/8 "%u\n"')
+dd if=/dev/zero of=/dev/sdc bs=4k count=1 seek=$ablock
+
+3. try bringing up the cache device. The resume is expected to fail
+ due to the broken array block.
+
+dmsetup create cmeta --table "0 8192 linear /dev/sdc 0"
+dmsetup create cdata --table "0 65536 linear /dev/sdc 8192"
+dmsetup create corig --table "0 524288 linear /dev/sdc 262144"
+dmsetup create cache --notable
+dmsetup load cache --table "0 524288 cache /dev/mapper/cmeta \
+/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0"
+dmsetup resume cache
+
+4. try resuming the cache again. An unexpected BUG_ON is triggered
+ while loading cache mappings.
+
+dmsetup resume cache
+
+Kernel logs:
+
+(snip)
+------------[ cut here ]------------
+kernel BUG at drivers/md/dm-cache-policy-smq.c:752!
+Oops: invalid opcode: 0000 [#1] PREEMPT SMP KASAN NOPTI
+CPU: 0 UID: 0 PID: 332 Comm: dmsetup Not tainted 6.13.4 #3
+RIP: 0010:smq_load_mapping+0x3e5/0x570
+
+Fix by disallowing resume operations for devices that failed the
+initial attempt.
+
+Signed-off-by: Ming-Hung Tsai <mtsai@redhat.com>
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/md/dm-cache-target.c | 24 ++++++++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+
+diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c
+index 9cb797a561d6e..6cee5eac8b9e2 100644
+--- a/drivers/md/dm-cache-target.c
++++ b/drivers/md/dm-cache-target.c
+@@ -2899,6 +2899,27 @@ static dm_cblock_t get_cache_dev_size(struct cache *cache)
+ return to_cblock(size);
+ }
+
++static bool can_resume(struct cache *cache)
++{
++ /*
++ * Disallow retrying the resume operation for devices that failed the
++ * first resume attempt, as the failure leaves the policy object partially
++ * initialized. Retrying could trigger BUG_ON when loading cache mappings
++ * into the incomplete policy object.
++ */
++ if (cache->sized && !cache->loaded_mappings) {
++ if (get_cache_mode(cache) != CM_WRITE)
++ DMERR("%s: unable to resume a failed-loaded cache, please check metadata.",
++ cache_device_name(cache));
++ else
++ DMERR("%s: unable to resume cache due to missing proper cache table reload",
++ cache_device_name(cache));
++ return false;
++ }
++
++ return true;
++}
++
+ static bool can_resize(struct cache *cache, dm_cblock_t new_size)
+ {
+ if (from_cblock(new_size) > from_cblock(cache->cache_size)) {
+@@ -2947,6 +2968,9 @@ static int cache_preresume(struct dm_target *ti)
+ struct cache *cache = ti->private;
+ dm_cblock_t csize = get_cache_dev_size(cache);
+
++ if (!can_resume(cache))
++ return -EINVAL;
++
+ /*
+ * Check to see if the cache has resized.
+ */
+--
+2.39.5
+
--- /dev/null
+From ba646a5dba24e411a43c29c5387996d093cfc934 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 20 Feb 2025 19:20:14 +0800
+Subject: dm: fix unconditional IO throttle caused by REQ_PREFLUSH
+
+From: Jinliang Zheng <alexjlzheng@gmail.com>
+
+[ Upstream commit 88f7f56d16f568f19e1a695af34a7f4a6ce537a6 ]
+
+When a bio with REQ_PREFLUSH is submitted to dm, __send_empty_flush()
+generates a flush_bio with REQ_OP_WRITE | REQ_PREFLUSH | REQ_SYNC,
+which causes the flush_bio to be throttled by wbt_wait().
+
+An example from v5.4, similar problem also exists in upstream:
+
+ crash> bt 2091206
+ PID: 2091206 TASK: ffff2050df92a300 CPU: 109 COMMAND: "kworker/u260:0"
+ #0 [ffff800084a2f7f0] __switch_to at ffff80004008aeb8
+ #1 [ffff800084a2f820] __schedule at ffff800040bfa0c4
+ #2 [ffff800084a2f880] schedule at ffff800040bfa4b4
+ #3 [ffff800084a2f8a0] io_schedule at ffff800040bfa9c4
+ #4 [ffff800084a2f8c0] rq_qos_wait at ffff8000405925bc
+ #5 [ffff800084a2f940] wbt_wait at ffff8000405bb3a0
+ #6 [ffff800084a2f9a0] __rq_qos_throttle at ffff800040592254
+ #7 [ffff800084a2f9c0] blk_mq_make_request at ffff80004057cf38
+ #8 [ffff800084a2fa60] generic_make_request at ffff800040570138
+ #9 [ffff800084a2fae0] submit_bio at ffff8000405703b4
+ #10 [ffff800084a2fb50] xlog_write_iclog at ffff800001280834 [xfs]
+ #11 [ffff800084a2fbb0] xlog_sync at ffff800001280c3c [xfs]
+ #12 [ffff800084a2fbf0] xlog_state_release_iclog at ffff800001280df4 [xfs]
+ #13 [ffff800084a2fc10] xlog_write at ffff80000128203c [xfs]
+ #14 [ffff800084a2fcd0] xlog_cil_push at ffff8000012846dc [xfs]
+ #15 [ffff800084a2fda0] xlog_cil_push_work at ffff800001284a2c [xfs]
+ #16 [ffff800084a2fdb0] process_one_work at ffff800040111d08
+ #17 [ffff800084a2fe00] worker_thread at ffff8000401121cc
+ #18 [ffff800084a2fe70] kthread at ffff800040118de4
+
+After commit 2def2845cc33 ("xfs: don't allow log IO to be throttled"),
+the metadata submitted by xlog_write_iclog() should not be throttled.
+But due to the existence of the dm layer, throttling flush_bio indirectly
+causes the metadata bio to be throttled.
+
+Fix this by conditionally adding REQ_IDLE to flush_bio.bi_opf, which makes
+wbt_should_throttle() return false to avoid wbt_wait().
+
+Signed-off-by: Jinliang Zheng <alexjlzheng@tencent.com>
+Reviewed-by: Tianxiang Peng <txpeng@tencent.com>
+Reviewed-by: Hao Peng <flyingpeng@tencent.com>
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/md/dm.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/md/dm.c b/drivers/md/dm.c
+index 4d1e42891d246..5ab7574c0c76a 100644
+--- a/drivers/md/dm.c
++++ b/drivers/md/dm.c
+@@ -1540,14 +1540,18 @@ static void __send_empty_flush(struct clone_info *ci)
+ {
+ struct dm_table *t = ci->map;
+ struct bio flush_bio;
++ blk_opf_t opf = REQ_OP_WRITE | REQ_PREFLUSH | REQ_SYNC;
++
++ if ((ci->io->orig_bio->bi_opf & (REQ_IDLE | REQ_SYNC)) ==
++ (REQ_IDLE | REQ_SYNC))
++ opf |= REQ_IDLE;
+
+ /*
+ * Use an on-stack bio for this, it's safe since we don't
+ * need to reference it after submit. It's just used as
+ * the basis for the clone(s).
+ */
+- bio_init(&flush_bio, ci->io->md->disk->part0, NULL, 0,
+- REQ_OP_WRITE | REQ_PREFLUSH | REQ_SYNC);
++ bio_init(&flush_bio, ci->io->md->disk->part0, NULL, 0, opf);
+
+ ci->bio = &flush_bio;
+ ci->sector_count = 0;
+--
+2.39.5
+
--- /dev/null
+From 9844a31eed65a7e4b5eae44726683393f6583b9c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 14 Mar 2025 13:51:32 +0100
+Subject: dm: restrict dm device size to 2^63-512 bytes
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+[ Upstream commit 45fc728515c14f53f6205789de5bfd72a95af3b8 ]
+
+The devices with size >= 2^63 bytes can't be used reliably by userspace
+because the type off_t is a signed 64-bit integer.
+
+Therefore, we limit the maximum size of a device mapper device to
+2^63-512 bytes.
+
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/md/dm-table.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
+index efc6ec25e0c5d..4752966fdb3f4 100644
+--- a/drivers/md/dm-table.c
++++ b/drivers/md/dm-table.c
+@@ -698,6 +698,10 @@ int dm_table_add_target(struct dm_table *t, const char *type,
+ DMERR("%s: zero-length target", dm_device_name(t->md));
+ return -EINVAL;
+ }
++ if (start + len < start || start + len > LLONG_MAX >> SECTOR_SHIFT) {
++ DMERR("%s: too large device", dm_device_name(t->md));
++ return -EINVAL;
++ }
+
+ ti->type = dm_get_target_type(type);
+ if (!ti->type) {
+--
+2.39.5
+
--- /dev/null
+From 932aaded959c8a09440d6776db7b9e6207b5f68a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jan 2025 18:27:12 -0500
+Subject: dm vdo indexer: prevent unterminated string warning
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Chung Chung <cchung@redhat.com>
+
+[ Upstream commit f4e99b846c90163d350c69d6581ac38dd5818eb8 ]
+
+Fix array initialization that triggers a warning:
+
+error: initializer-string for array of ‘unsigned char’ is too long
+ [-Werror=unterminated-string-initialization]
+
+Signed-off-by: Chung Chung <cchung@redhat.com>
+Signed-off-by: Matthew Sakai <msakai@redhat.com>
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/md/dm-vdo/indexer/index-layout.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/md/dm-vdo/indexer/index-layout.c b/drivers/md/dm-vdo/indexer/index-layout.c
+index af8fab83b0f3e..61edf2b72427d 100644
+--- a/drivers/md/dm-vdo/indexer/index-layout.c
++++ b/drivers/md/dm-vdo/indexer/index-layout.c
+@@ -54,7 +54,6 @@
+ * Each save also has a unique nonce.
+ */
+
+-#define MAGIC_SIZE 32
+ #define NONCE_INFO_SIZE 32
+ #define MAX_SAVES 2
+
+@@ -98,9 +97,11 @@ enum region_type {
+ #define SUPER_VERSION_CURRENT 3
+ #define SUPER_VERSION_MAXIMUM 7
+
+-static const u8 LAYOUT_MAGIC[MAGIC_SIZE] = "*ALBIREO*SINGLE*FILE*LAYOUT*001*";
++static const u8 LAYOUT_MAGIC[] = "*ALBIREO*SINGLE*FILE*LAYOUT*001*";
+ static const u64 REGION_MAGIC = 0x416c6252676e3031; /* 'AlbRgn01' */
+
++#define MAGIC_SIZE (sizeof(LAYOUT_MAGIC) - 1)
++
+ struct region_header {
+ u64 magic;
+ u64 region_blocks;
+--
+2.39.5
+
--- /dev/null
+From 31cad9ec1911a586b4a74f901a1e5b84e7ff1279 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jan 2025 18:26:05 -0500
+Subject: dm vdo: use a short static string for thread name prefix
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Matthew Sakai <msakai@redhat.com>
+
+[ Upstream commit 3280c9313c9adce01550cc9f00edfb1dc7c744da ]
+
+Also remove MODULE_NAME and a BUG_ON check, both unneeded.
+
+This fixes a warning about string truncation in snprintf that
+will never happen in practice:
+
+drivers/md/dm-vdo/vdo.c: In function ‘vdo_make’:
+drivers/md/dm-vdo/vdo.c:564:5: error: ‘%s’ directive output may be truncated writing up to 55 bytes into a region of size 16 [-Werror=format-truncation=]
+ "%s%u", MODULE_NAME, instance);
+ ^~
+drivers/md/dm-vdo/vdo.c:563:2: note: ‘snprintf’ output between 2 and 66 bytes into a destination of size 16
+ snprintf(vdo->thread_name_prefix, sizeof(vdo->thread_name_prefix),
+ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ "%s%u", MODULE_NAME, instance);
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Reported-by: John Garry <john.g.garry@oracle.com>
+Reviewed-by: John Garry <john.g.garry@oracle.com>
+Signed-off-by: Matthew Sakai <msakai@redhat.com>
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/md/dm-vdo/vdo.c | 11 +----------
+ 1 file changed, 1 insertion(+), 10 deletions(-)
+
+diff --git a/drivers/md/dm-vdo/vdo.c b/drivers/md/dm-vdo/vdo.c
+index a7e32baab4afd..80b6086740225 100644
+--- a/drivers/md/dm-vdo/vdo.c
++++ b/drivers/md/dm-vdo/vdo.c
+@@ -31,9 +31,7 @@
+
+ #include <linux/completion.h>
+ #include <linux/device-mapper.h>
+-#include <linux/kernel.h>
+ #include <linux/lz4.h>
+-#include <linux/module.h>
+ #include <linux/mutex.h>
+ #include <linux/spinlock.h>
+ #include <linux/types.h>
+@@ -142,12 +140,6 @@ static void finish_vdo_request_queue(void *ptr)
+ vdo_unregister_allocating_thread();
+ }
+
+-#ifdef MODULE
+-#define MODULE_NAME THIS_MODULE->name
+-#else
+-#define MODULE_NAME "dm-vdo"
+-#endif /* MODULE */
+-
+ static const struct vdo_work_queue_type default_queue_type = {
+ .start = start_vdo_request_queue,
+ .finish = finish_vdo_request_queue,
+@@ -559,8 +551,7 @@ int vdo_make(unsigned int instance, struct device_config *config, char **reason,
+ *vdo_ptr = vdo;
+
+ snprintf(vdo->thread_name_prefix, sizeof(vdo->thread_name_prefix),
+- "%s%u", MODULE_NAME, instance);
+- BUG_ON(vdo->thread_name_prefix[0] == '\0');
++ "vdo%u", instance);
+ result = vdo_allocate(vdo->thread_config.thread_count,
+ struct vdo_thread, __func__, &vdo->threads);
+ if (result != VDO_SUCCESS) {
+--
+2.39.5
+
--- /dev/null
+From 921200c5e2f6a07ad93419d800d6a1a2fbf7abc7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jan 2025 21:18:05 -0500
+Subject: dm vdo vio-pool: allow variable-sized metadata vios
+
+From: Ken Raeburn <raeburn@redhat.com>
+
+[ Upstream commit f979da512553a41a657f2c1198277e84d66f8ce3 ]
+
+With larger-sized metadata vio pools, vdo will sometimes need to
+issue I/O with a smaller size than the allocated size. Since
+vio_reset_bio is where the bvec array and I/O size are initialized,
+this reset interface must now specify what I/O size to use.
+
+Signed-off-by: Ken Raeburn <raeburn@redhat.com>
+Signed-off-by: Matthew Sakai <msakai@redhat.com>
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/md/dm-vdo/io-submitter.c | 6 ++++--
+ drivers/md/dm-vdo/io-submitter.h | 18 +++++++++++++---
+ drivers/md/dm-vdo/types.h | 3 +++
+ drivers/md/dm-vdo/vio.c | 36 +++++++++++++++++++-------------
+ drivers/md/dm-vdo/vio.h | 2 ++
+ 5 files changed, 46 insertions(+), 19 deletions(-)
+
+diff --git a/drivers/md/dm-vdo/io-submitter.c b/drivers/md/dm-vdo/io-submitter.c
+index 421e5436c32c9..11d47770b54d2 100644
+--- a/drivers/md/dm-vdo/io-submitter.c
++++ b/drivers/md/dm-vdo/io-submitter.c
+@@ -327,6 +327,7 @@ void vdo_submit_data_vio(struct data_vio *data_vio)
+ * @error_handler: the handler for submission or I/O errors (may be NULL)
+ * @operation: the type of I/O to perform
+ * @data: the buffer to read or write (may be NULL)
++ * @size: the I/O amount in bytes
+ *
+ * The vio is enqueued on a vdo bio queue so that bio submission (which may block) does not block
+ * other vdo threads.
+@@ -338,7 +339,7 @@ void vdo_submit_data_vio(struct data_vio *data_vio)
+ */
+ void __submit_metadata_vio(struct vio *vio, physical_block_number_t physical,
+ bio_end_io_t callback, vdo_action_fn error_handler,
+- blk_opf_t operation, char *data)
++ blk_opf_t operation, char *data, int size)
+ {
+ int result;
+ struct vdo_completion *completion = &vio->completion;
+@@ -349,7 +350,8 @@ void __submit_metadata_vio(struct vio *vio, physical_block_number_t physical,
+
+ vdo_reset_completion(completion);
+ completion->error_handler = error_handler;
+- result = vio_reset_bio(vio, data, callback, operation | REQ_META, physical);
++ result = vio_reset_bio_with_size(vio, data, size, callback, operation | REQ_META,
++ physical);
+ if (result != VDO_SUCCESS) {
+ continue_vio(vio, result);
+ return;
+diff --git a/drivers/md/dm-vdo/io-submitter.h b/drivers/md/dm-vdo/io-submitter.h
+index 80748699496f2..3088f11055fdd 100644
+--- a/drivers/md/dm-vdo/io-submitter.h
++++ b/drivers/md/dm-vdo/io-submitter.h
+@@ -8,6 +8,7 @@
+
+ #include <linux/bio.h>
+
++#include "constants.h"
+ #include "types.h"
+
+ struct io_submitter;
+@@ -26,14 +27,25 @@ void vdo_submit_data_vio(struct data_vio *data_vio);
+
+ void __submit_metadata_vio(struct vio *vio, physical_block_number_t physical,
+ bio_end_io_t callback, vdo_action_fn error_handler,
+- blk_opf_t operation, char *data);
++ blk_opf_t operation, char *data, int size);
+
+ static inline void vdo_submit_metadata_vio(struct vio *vio, physical_block_number_t physical,
+ bio_end_io_t callback, vdo_action_fn error_handler,
+ blk_opf_t operation)
+ {
+ __submit_metadata_vio(vio, physical, callback, error_handler,
+- operation, vio->data);
++ operation, vio->data, vio->block_count * VDO_BLOCK_SIZE);
++}
++
++static inline void vdo_submit_metadata_vio_with_size(struct vio *vio,
++ physical_block_number_t physical,
++ bio_end_io_t callback,
++ vdo_action_fn error_handler,
++ blk_opf_t operation,
++ int size)
++{
++ __submit_metadata_vio(vio, physical, callback, error_handler,
++ operation, vio->data, size);
+ }
+
+ static inline void vdo_submit_flush_vio(struct vio *vio, bio_end_io_t callback,
+@@ -41,7 +53,7 @@ static inline void vdo_submit_flush_vio(struct vio *vio, bio_end_io_t callback,
+ {
+ /* FIXME: Can we just use REQ_OP_FLUSH? */
+ __submit_metadata_vio(vio, 0, callback, error_handler,
+- REQ_OP_WRITE | REQ_PREFLUSH, NULL);
++ REQ_OP_WRITE | REQ_PREFLUSH, NULL, 0);
+ }
+
+ #endif /* VDO_IO_SUBMITTER_H */
+diff --git a/drivers/md/dm-vdo/types.h b/drivers/md/dm-vdo/types.h
+index dbe892b10f265..cdf36e7d77021 100644
+--- a/drivers/md/dm-vdo/types.h
++++ b/drivers/md/dm-vdo/types.h
+@@ -376,6 +376,9 @@ struct vio {
+ /* The size of this vio in blocks */
+ unsigned int block_count;
+
++ /* The amount of data to be read or written, in bytes */
++ unsigned int io_size;
++
+ /* The data being read or written. */
+ char *data;
+
+diff --git a/drivers/md/dm-vdo/vio.c b/drivers/md/dm-vdo/vio.c
+index e710f3c5a972d..725d87ecf2150 100644
+--- a/drivers/md/dm-vdo/vio.c
++++ b/drivers/md/dm-vdo/vio.c
+@@ -188,14 +188,23 @@ void vdo_set_bio_properties(struct bio *bio, struct vio *vio, bio_end_io_t callb
+
+ /*
+ * Prepares the bio to perform IO with the specified buffer. May only be used on a VDO-allocated
+- * bio, as it assumes the bio wraps a 4k buffer that is 4k aligned, but there does not have to be a
+- * vio associated with the bio.
++ * bio, as it assumes the bio wraps a 4k-multiple buffer that is 4k aligned, but there does not
++ * have to be a vio associated with the bio.
+ */
+ int vio_reset_bio(struct vio *vio, char *data, bio_end_io_t callback,
+ blk_opf_t bi_opf, physical_block_number_t pbn)
+ {
+- int bvec_count, offset, len, i;
++ return vio_reset_bio_with_size(vio, data, vio->block_count * VDO_BLOCK_SIZE,
++ callback, bi_opf, pbn);
++}
++
++int vio_reset_bio_with_size(struct vio *vio, char *data, int size, bio_end_io_t callback,
++ blk_opf_t bi_opf, physical_block_number_t pbn)
++{
++ int bvec_count, offset, i;
+ struct bio *bio = vio->bio;
++ int vio_size = vio->block_count * VDO_BLOCK_SIZE;
++ int remaining;
+
+ bio_reset(bio, bio->bi_bdev, bi_opf);
+ vdo_set_bio_properties(bio, vio, callback, bi_opf, pbn);
+@@ -205,22 +214,21 @@ int vio_reset_bio(struct vio *vio, char *data, bio_end_io_t callback,
+ bio->bi_ioprio = 0;
+ bio->bi_io_vec = bio->bi_inline_vecs;
+ bio->bi_max_vecs = vio->block_count + 1;
+- len = VDO_BLOCK_SIZE * vio->block_count;
++ if (VDO_ASSERT(size <= vio_size, "specified size %d is not greater than allocated %d",
++ size, vio_size) != VDO_SUCCESS)
++ size = vio_size;
++ vio->io_size = size;
+ offset = offset_in_page(data);
+- bvec_count = DIV_ROUND_UP(offset + len, PAGE_SIZE);
++ bvec_count = DIV_ROUND_UP(offset + size, PAGE_SIZE);
++ remaining = size;
+
+- /*
+- * If we knew that data was always on one page, or contiguous pages, we wouldn't need the
+- * loop. But if we're using vmalloc, it's not impossible that the data is in different
+- * pages that can't be merged in bio_add_page...
+- */
+- for (i = 0; (i < bvec_count) && (len > 0); i++) {
++ for (i = 0; (i < bvec_count) && (remaining > 0); i++) {
+ struct page *page;
+ int bytes_added;
+ int bytes = PAGE_SIZE - offset;
+
+- if (bytes > len)
+- bytes = len;
++ if (bytes > remaining)
++ bytes = remaining;
+
+ page = is_vmalloc_addr(data) ? vmalloc_to_page(data) : virt_to_page(data);
+ bytes_added = bio_add_page(bio, page, bytes, offset);
+@@ -232,7 +240,7 @@ int vio_reset_bio(struct vio *vio, char *data, bio_end_io_t callback,
+ }
+
+ data += bytes;
+- len -= bytes;
++ remaining -= bytes;
+ offset = 0;
+ }
+
+diff --git a/drivers/md/dm-vdo/vio.h b/drivers/md/dm-vdo/vio.h
+index 3490e9f59b04a..74e8fd7c8c029 100644
+--- a/drivers/md/dm-vdo/vio.h
++++ b/drivers/md/dm-vdo/vio.h
+@@ -123,6 +123,8 @@ void vdo_set_bio_properties(struct bio *bio, struct vio *vio, bio_end_io_t callb
+
+ int vio_reset_bio(struct vio *vio, char *data, bio_end_io_t callback,
+ blk_opf_t bi_opf, physical_block_number_t pbn);
++int vio_reset_bio_with_size(struct vio *vio, char *data, int size, bio_end_io_t callback,
++ blk_opf_t bi_opf, physical_block_number_t pbn);
+
+ void update_vio_error_stats(struct vio *vio, const char *format, ...)
+ __printf(2, 3);
+--
+2.39.5
+
--- /dev/null
+From 476cb6b8905e19cee5f5002df5a6716eb3d860c7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 15 Apr 2025 09:56:59 +0200
+Subject: dma-mapping: avoid potential unused data compilation warning
+
+From: Marek Szyprowski <m.szyprowski@samsung.com>
+
+[ Upstream commit c9b19ea63036fc537a69265acea1b18dabd1cbd3 ]
+
+When CONFIG_NEED_DMA_MAP_STATE is not defined, dma-mapping clients might
+report unused data compilation warnings for dma_unmap_*() calls
+arguments. Redefine macros for those calls to let compiler to notice that
+it is okay when the provided arguments are not used.
+
+Reported-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Suggested-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
+Tested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Link: https://lore.kernel.org/r/20250415075659.428549-1-m.szyprowski@samsung.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/dma-mapping.h | 12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
+index b79925b1c4333..85ab710ec0e72 100644
+--- a/include/linux/dma-mapping.h
++++ b/include/linux/dma-mapping.h
+@@ -629,10 +629,14 @@ static inline int dma_mmap_wc(struct device *dev,
+ #else
+ #define DEFINE_DMA_UNMAP_ADDR(ADDR_NAME)
+ #define DEFINE_DMA_UNMAP_LEN(LEN_NAME)
+-#define dma_unmap_addr(PTR, ADDR_NAME) (0)
+-#define dma_unmap_addr_set(PTR, ADDR_NAME, VAL) do { } while (0)
+-#define dma_unmap_len(PTR, LEN_NAME) (0)
+-#define dma_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0)
++#define dma_unmap_addr(PTR, ADDR_NAME) \
++ ({ typeof(PTR) __p __maybe_unused = PTR; 0; })
++#define dma_unmap_addr_set(PTR, ADDR_NAME, VAL) \
++ do { typeof(PTR) __p __maybe_unused = PTR; } while (0)
++#define dma_unmap_len(PTR, LEN_NAME) \
++ ({ typeof(PTR) __p __maybe_unused = PTR; 0; })
++#define dma_unmap_len_set(PTR, LEN_NAME, VAL) \
++ do { typeof(PTR) __p __maybe_unused = PTR; } while (0)
+ #endif
+
+ #endif /* _LINUX_DMA_MAPPING_H */
+--
+2.39.5
+
--- /dev/null
+From 5915980b96f18903b1e14b52b4488182783e8790 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 22 Apr 2025 21:40:34 +1000
+Subject: dma-mapping: Fix warning reported for missing prototype
+
+From: Balbir Singh <balbirs@nvidia.com>
+
+[ Upstream commit cae5572ec9261f752af834cdaaf5a0ba0afcf256 ]
+
+lkp reported a warning about missing prototype for a recent patch.
+
+The kernel-doc style comments are out of sync, move them to the right
+function.
+
+Cc: Marek Szyprowski <m.szyprowski@samsung.com>
+Cc: Christoph Hellwig <hch@lst.de>
+
+Reported-by: kernel test robot <lkp@intel.com>
+Closes: https://lore.kernel.org/oe-kbuild-all/202504190615.g9fANxHw-lkp@intel.com/
+
+Signed-off-by: Balbir Singh <balbirs@nvidia.com>
+[mszyprow: reformatted subject]
+Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
+Link: https://lore.kernel.org/r/20250422114034.3535515-1-balbirs@nvidia.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/dma/mapping.c | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+diff --git a/kernel/dma/mapping.c b/kernel/dma/mapping.c
+index 67da08fa67237..051a32988040f 100644
+--- a/kernel/dma/mapping.c
++++ b/kernel/dma/mapping.c
+@@ -910,14 +910,6 @@ int dma_set_coherent_mask(struct device *dev, u64 mask)
+ }
+ EXPORT_SYMBOL(dma_set_coherent_mask);
+
+-/**
+- * dma_addressing_limited - return if the device is addressing limited
+- * @dev: device to check
+- *
+- * Return %true if the devices DMA mask is too small to address all memory in
+- * the system, else %false. Lack of addressing bits is the prime reason for
+- * bounce buffering, but might not be the only one.
+- */
+ static bool __dma_addressing_limited(struct device *dev)
+ {
+ const struct dma_map_ops *ops = get_dma_ops(dev);
+@@ -931,6 +923,14 @@ static bool __dma_addressing_limited(struct device *dev)
+ return !dma_direct_all_ram_mapped(dev);
+ }
+
++/**
++ * dma_addressing_limited - return if the device is addressing limited
++ * @dev: device to check
++ *
++ * Return %true if the devices DMA mask is too small to address all memory in
++ * the system, else %false. Lack of addressing bits is the prime reason for
++ * bounce buffering, but might not be the only one.
++ */
+ bool dma_addressing_limited(struct device *dev)
+ {
+ if (!__dma_addressing_limited(dev))
+--
+2.39.5
+
--- /dev/null
+From b77e818f7f80bf2b0176d96179bbff3495cc5125 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 14 Apr 2025 21:37:52 +1000
+Subject: dma/mapping.c: dev_dbg support for dma_addressing_limited
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Balbir Singh <balbirs@nvidia.com>
+
+[ Upstream commit 2042c352e21d19eaf5f9e22fb6afce72293ef28c ]
+
+In the debug and resolution of an issue involving forced use of bounce
+buffers, 7170130e4c72 ("x86/mm/init: Handle the special case of device
+private pages in add_pages(), to not increase max_pfn and trigger
+dma_addressing_limited() bounce buffers"). It would have been easier
+to debug the issue if dma_addressing_limited() had debug information
+about the device not being able to address all of memory and thus forcing
+all accesses through a bounce buffer. Please see[2]
+
+Implement dev_dbg to debug the potential use of bounce buffers
+when we hit the condition. When swiotlb is used,
+dma_addressing_limited() is used to determine the size of maximum dma
+buffer size in dma_direct_max_mapping_size(). The debug prints could be
+triggered in that check as well (when enabled).
+
+Link: https://lore.kernel.org/lkml/20250401000752.249348-1-balbirs@nvidia.com/ [1]
+Link: https://lore.kernel.org/lkml/20250310112206.4168-1-spasswolf@web.de/ [2]
+
+Cc: Marek Szyprowski <m.szyprowski@samsung.com>
+Cc: Robin Murphy <robin.murphy@arm.com>
+Cc: "Christian König" <christian.koenig@amd.com>
+Cc: Ingo Molnar <mingo@kernel.org>
+Cc: Kees Cook <kees@kernel.org>
+Cc: Bjorn Helgaas <bhelgaas@google.com>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Andy Lutomirski <luto@kernel.org>
+Cc: Alex Deucher <alexander.deucher@amd.com>
+Cc: Bert Karwatzki <spasswolf@web.de>
+Cc: Christoph Hellwig <hch@infradead.org>
+
+Signed-off-by: Balbir Singh <balbirs@nvidia.com>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
+Link: https://lore.kernel.org/r/20250414113752.3298276-1-balbirs@nvidia.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/dma/mapping.c | 11 ++++++++++-
+ 1 file changed, 10 insertions(+), 1 deletion(-)
+
+diff --git a/kernel/dma/mapping.c b/kernel/dma/mapping.c
+index cda127027e48a..67da08fa67237 100644
+--- a/kernel/dma/mapping.c
++++ b/kernel/dma/mapping.c
+@@ -918,7 +918,7 @@ EXPORT_SYMBOL(dma_set_coherent_mask);
+ * the system, else %false. Lack of addressing bits is the prime reason for
+ * bounce buffering, but might not be the only one.
+ */
+-bool dma_addressing_limited(struct device *dev)
++static bool __dma_addressing_limited(struct device *dev)
+ {
+ const struct dma_map_ops *ops = get_dma_ops(dev);
+
+@@ -930,6 +930,15 @@ bool dma_addressing_limited(struct device *dev)
+ return false;
+ return !dma_direct_all_ram_mapped(dev);
+ }
++
++bool dma_addressing_limited(struct device *dev)
++{
++ if (!__dma_addressing_limited(dev))
++ return false;
++
++ dev_dbg(dev, "device is DMA addressing limited\n");
++ return true;
++}
+ EXPORT_SYMBOL_GPL(dma_addressing_limited);
+
+ size_t dma_max_mapping_size(struct device *dev)
+--
+2.39.5
+
--- /dev/null
+From 54a9db82e32011419d2e3a6c30b30b40a8579327 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 24 Feb 2025 16:04:17 +0200
+Subject: dmaengine: ti: k3-udma-glue: Drop skip_fdq argument from
+ k3_udma_glue_reset_rx_chn
+
+From: Roger Quadros <rogerq@kernel.org>
+
+[ Upstream commit 0da30874729baeb01889b0eca16cfda122687503 ]
+
+The user of k3_udma_glue_reset_rx_chn() e.g. ti_am65_cpsw_nuss can
+run on multiple platforms having different DMA architectures.
+On some platforms there can be one FDQ for all flows in the RX channel
+while for others there is a separate FDQ for each flow in the RX channel.
+
+So far we have been relying on the skip_fdq argument of
+k3_udma_glue_reset_rx_chn().
+
+Instead of relying on the user to provide this information, infer it
+based on DMA architecture during k3_udma_glue_request_rx_chn() and save it
+in an internal flag 'single_fdq'. Use that flag at
+k3_udma_glue_reset_rx_chn() to deicide if the FDQ needs
+to be cleared for every flow or just for flow 0.
+
+Fixes the below issue on ti_am65_cpsw_nuss driver on AM62-SK.
+
+> ip link set eth1 down
+> ip link set eth0 down
+> ethtool -L eth0 rx 8
+> ip link set eth0 up
+> modprobe -r ti_am65_cpsw_nuss
+
+[ 103.045726] ------------[ cut here ]------------
+[ 103.050505] k3_knav_desc_pool size 512000 != avail 64000
+[ 103.050703] WARNING: CPU: 1 PID: 450 at drivers/net/ethernet/ti/k3-cppi-desc-pool.c:33 k3_cppi_desc_pool_destroy+0xa0/0xa8 [k3_cppi_desc_pool]
+[ 103.068810] Modules linked in: ti_am65_cpsw_nuss(-) k3_cppi_desc_pool snd_soc_hdmi_codec crct10dif_ce snd_soc_simple_card snd_soc_simple_card_utils display_connector rtc_ti_k3 k3_j72xx_bandgap tidss drm_client_lib snd_soc_davinci_mcas
+p drm_dma_helper tps6598x phylink snd_soc_ti_udma rti_wdt drm_display_helper snd_soc_tlv320aic3x_i2c typec at24 phy_gmii_sel snd_soc_ti_edma snd_soc_tlv320aic3x sii902x snd_soc_ti_sdma sa2ul omap_mailbox drm_kms_helper authenc cfg80211 r
+fkill fuse drm drm_panel_orientation_quirks backlight ip_tables x_tables ipv6 [last unloaded: k3_cppi_desc_pool]
+[ 103.119950] CPU: 1 UID: 0 PID: 450 Comm: modprobe Not tainted 6.13.0-rc7-00001-g9c5e3435fa66 #1011
+[ 103.119968] Hardware name: Texas Instruments AM625 SK (DT)
+[ 103.119974] pstate: 80000005 (Nzcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
+[ 103.119983] pc : k3_cppi_desc_pool_destroy+0xa0/0xa8 [k3_cppi_desc_pool]
+[ 103.148007] lr : k3_cppi_desc_pool_destroy+0xa0/0xa8 [k3_cppi_desc_pool]
+[ 103.154709] sp : ffff8000826ebbc0
+[ 103.158015] x29: ffff8000826ebbc0 x28: ffff0000090b6300 x27: 0000000000000000
+[ 103.165145] x26: 0000000000000000 x25: 0000000000000000 x24: ffff0000019df6b0
+[ 103.172271] x23: ffff0000019df6b8 x22: ffff0000019df410 x21: ffff8000826ebc88
+[ 103.179397] x20: 000000000007d000 x19: ffff00000a3b3000 x18: 0000000000000000
+[ 103.186522] x17: 0000000000000000 x16: 0000000000000000 x15: 000001e8c35e1cde
+[ 103.193647] x14: 0000000000000396 x13: 000000000000035c x12: 0000000000000000
+[ 103.200772] x11: 000000000000003a x10: 00000000000009c0 x9 : ffff8000826eba20
+[ 103.207897] x8 : ffff0000090b6d20 x7 : ffff00007728c180 x6 : ffff00007728c100
+[ 103.215022] x5 : 0000000000000001 x4 : ffff000000508a50 x3 : ffff7ffff6146000
+[ 103.222147] x2 : 0000000000000000 x1 : e300b4173ee6b200 x0 : 0000000000000000
+[ 103.229274] Call trace:
+[ 103.231714] k3_cppi_desc_pool_destroy+0xa0/0xa8 [k3_cppi_desc_pool] (P)
+[ 103.238408] am65_cpsw_nuss_free_rx_chns+0x28/0x4c [ti_am65_cpsw_nuss]
+[ 103.244942] devm_action_release+0x14/0x20
+[ 103.249040] release_nodes+0x3c/0x68
+[ 103.252610] devres_release_all+0x8c/0xdc
+[ 103.256614] device_unbind_cleanup+0x18/0x60
+[ 103.260876] device_release_driver_internal+0xf8/0x178
+[ 103.266004] driver_detach+0x50/0x9c
+[ 103.269571] bus_remove_driver+0x6c/0xbc
+[ 103.273485] driver_unregister+0x30/0x60
+[ 103.277401] platform_driver_unregister+0x14/0x20
+[ 103.282096] am65_cpsw_nuss_driver_exit+0x18/0xff4 [ti_am65_cpsw_nuss]
+[ 103.288620] __arm64_sys_delete_module+0x17c/0x25c
+[ 103.293404] invoke_syscall+0x44/0x100
+[ 103.297149] el0_svc_common.constprop.0+0xc0/0xe0
+[ 103.301845] do_el0_svc+0x1c/0x28
+[ 103.305155] el0_svc+0x28/0x98
+[ 103.308207] el0t_64_sync_handler+0xc8/0xcc
+[ 103.312384] el0t_64_sync+0x198/0x19c
+[ 103.316040] ---[ end trace 0000000000000000 ]---
+
+Signed-off-by: Roger Quadros <rogerq@kernel.org>
+Acked-by: Jakub Kicinski <kuba@kernel.org>
+Acked-by: Peter Ujfalusi <peter.ujfalusi@gmail.com>
+Link: https://lore.kernel.org/r/20250224-k3-udma-glue-single-fdq-v2-1-cbe7621f2507@kernel.org
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/dma/ti/k3-udma-glue.c | 15 +++++++++++----
+ drivers/net/ethernet/ti/am65-cpsw-nuss.c | 4 ++--
+ drivers/net/ethernet/ti/icssg/icssg_common.c | 2 +-
+ include/linux/dma/k3-udma-glue.h | 3 +--
+ 4 files changed, 15 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/dma/ti/k3-udma-glue.c b/drivers/dma/ti/k3-udma-glue.c
+index 7c224c3ab7a07..f87d244cc2d67 100644
+--- a/drivers/dma/ti/k3-udma-glue.c
++++ b/drivers/dma/ti/k3-udma-glue.c
+@@ -84,6 +84,7 @@ struct k3_udma_glue_rx_channel {
+ struct k3_udma_glue_rx_flow *flows;
+ u32 flow_num;
+ u32 flows_ready;
++ bool single_fdq; /* one FDQ for all flows */
+ };
+
+ static void k3_udma_chan_dev_release(struct device *dev)
+@@ -970,10 +971,13 @@ k3_udma_glue_request_rx_chn_priv(struct device *dev, const char *name,
+
+ ep_cfg = rx_chn->common.ep_config;
+
+- if (xudma_is_pktdma(rx_chn->common.udmax))
++ if (xudma_is_pktdma(rx_chn->common.udmax)) {
+ rx_chn->udma_rchan_id = ep_cfg->mapped_channel_id;
+- else
++ rx_chn->single_fdq = false;
++ } else {
+ rx_chn->udma_rchan_id = -1;
++ rx_chn->single_fdq = true;
++ }
+
+ /* request and cfg UDMAP RX channel */
+ rx_chn->udma_rchanx = xudma_rchan_get(rx_chn->common.udmax,
+@@ -1103,6 +1107,9 @@ k3_udma_glue_request_remote_rx_chn_common(struct k3_udma_glue_rx_channel *rx_chn
+ rx_chn->common.chan_dev.dma_coherent = true;
+ dma_coerce_mask_and_coherent(&rx_chn->common.chan_dev,
+ DMA_BIT_MASK(48));
++ rx_chn->single_fdq = false;
++ } else {
++ rx_chn->single_fdq = true;
+ }
+
+ ret = k3_udma_glue_allocate_rx_flows(rx_chn, cfg);
+@@ -1453,7 +1460,7 @@ EXPORT_SYMBOL_GPL(k3_udma_glue_tdown_rx_chn);
+
+ void k3_udma_glue_reset_rx_chn(struct k3_udma_glue_rx_channel *rx_chn,
+ u32 flow_num, void *data,
+- void (*cleanup)(void *data, dma_addr_t desc_dma), bool skip_fdq)
++ void (*cleanup)(void *data, dma_addr_t desc_dma))
+ {
+ struct k3_udma_glue_rx_flow *flow = &rx_chn->flows[flow_num];
+ struct device *dev = rx_chn->common.dev;
+@@ -1465,7 +1472,7 @@ void k3_udma_glue_reset_rx_chn(struct k3_udma_glue_rx_channel *rx_chn,
+ dev_dbg(dev, "RX reset flow %u occ_rx %u\n", flow_num, occ_rx);
+
+ /* Skip RX FDQ in case one FDQ is used for the set of flows */
+- if (skip_fdq)
++ if (rx_chn->single_fdq && flow_num)
+ goto do_reset;
+
+ /*
+diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
+index afe8127fd32be..cac67babe4559 100644
+--- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c
++++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
+@@ -515,7 +515,7 @@ static void am65_cpsw_destroy_rxq(struct am65_cpsw_common *common, int id)
+ napi_disable(&flow->napi_rx);
+ hrtimer_cancel(&flow->rx_hrtimer);
+ k3_udma_glue_reset_rx_chn(rx_chn->rx_chn, id, rx_chn,
+- am65_cpsw_nuss_rx_cleanup, !!id);
++ am65_cpsw_nuss_rx_cleanup);
+
+ for (port = 0; port < common->port_num; port++) {
+ if (!common->ports[port].ndev)
+@@ -3433,7 +3433,7 @@ static int am65_cpsw_nuss_register_ndevs(struct am65_cpsw_common *common)
+ for (i = 0; i < common->rx_ch_num_flows; i++)
+ k3_udma_glue_reset_rx_chn(rx_chan->rx_chn, i,
+ rx_chan,
+- am65_cpsw_nuss_rx_cleanup, !!i);
++ am65_cpsw_nuss_rx_cleanup);
+
+ k3_udma_glue_disable_rx_chn(rx_chan->rx_chn);
+
+diff --git a/drivers/net/ethernet/ti/icssg/icssg_common.c b/drivers/net/ethernet/ti/icssg/icssg_common.c
+index 74f0f200a89d4..62065416e8861 100644
+--- a/drivers/net/ethernet/ti/icssg/icssg_common.c
++++ b/drivers/net/ethernet/ti/icssg/icssg_common.c
+@@ -955,7 +955,7 @@ void prueth_reset_rx_chan(struct prueth_rx_chn *chn,
+
+ for (i = 0; i < num_flows; i++)
+ k3_udma_glue_reset_rx_chn(chn->rx_chn, i, chn,
+- prueth_rx_cleanup, !!i);
++ prueth_rx_cleanup);
+ if (disable)
+ k3_udma_glue_disable_rx_chn(chn->rx_chn);
+ }
+diff --git a/include/linux/dma/k3-udma-glue.h b/include/linux/dma/k3-udma-glue.h
+index 2dea217629d0a..5d43881e6fb77 100644
+--- a/include/linux/dma/k3-udma-glue.h
++++ b/include/linux/dma/k3-udma-glue.h
+@@ -138,8 +138,7 @@ int k3_udma_glue_rx_get_irq(struct k3_udma_glue_rx_channel *rx_chn,
+ u32 flow_num);
+ void k3_udma_glue_reset_rx_chn(struct k3_udma_glue_rx_channel *rx_chn,
+ u32 flow_num, void *data,
+- void (*cleanup)(void *data, dma_addr_t desc_dma),
+- bool skip_fdq);
++ void (*cleanup)(void *data, dma_addr_t desc_dma));
+ int k3_udma_glue_rx_flow_enable(struct k3_udma_glue_rx_channel *rx_chn,
+ u32 flow_idx);
+ int k3_udma_glue_rx_flow_disable(struct k3_udma_glue_rx_channel *rx_chn,
+--
+2.39.5
+
--- /dev/null
+From 7d00e7dc1055c18845a6a21a8003e5d22fd8d5a7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 28 Feb 2025 15:02:10 +0000
+Subject: dpll: Add an assertion to check freq_supported_num
+
+From: Jiasheng Jiang <jiashengjiangcool@gmail.com>
+
+[ Upstream commit 39e912a959c19338855b768eaaee2917d7841f71 ]
+
+Since the driver is broken in the case that src->freq_supported is not
+NULL but src->freq_supported_num is 0, add an assertion for it.
+
+Signed-off-by: Jiasheng Jiang <jiashengjiangcool@gmail.com>
+Reviewed-by: Jiri Pirko <jiri@nvidia.com>
+Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev>
+Reviewed-by: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
+Link: https://patch.msgid.link/20250228150210.34404-1-jiashengjiangcool@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/dpll/dpll_core.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c
+index 1877201d1aa9f..20bdc52f63a50 100644
+--- a/drivers/dpll/dpll_core.c
++++ b/drivers/dpll/dpll_core.c
+@@ -443,8 +443,11 @@ static void dpll_pin_prop_free(struct dpll_pin_properties *prop)
+ static int dpll_pin_prop_dup(const struct dpll_pin_properties *src,
+ struct dpll_pin_properties *dst)
+ {
++ if (WARN_ON(src->freq_supported && !src->freq_supported_num))
++ return -EINVAL;
++
+ memcpy(dst, src, sizeof(*dst));
+- if (src->freq_supported && src->freq_supported_num) {
++ if (src->freq_supported) {
+ size_t freq_size = src->freq_supported_num *
+ sizeof(*src->freq_supported);
+ dst->freq_supported = kmemdup(src->freq_supported,
+--
+2.39.5
+
--- /dev/null
+From 6fc181843107b6a8617e94a7242b4d5c3829a5c0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 19 Mar 2025 16:57:51 +0800
+Subject: dql: Fix dql->limit value when reset.
+
+From: Jing Su <jingsusu@didiglobal.com>
+
+[ Upstream commit 3a17f23f7c36bac3a3584aaf97d3e3e0b2790396 ]
+
+Executing dql_reset after setting a non-zero value for limit_min can
+lead to an unreasonable situation where dql->limit is less than
+dql->limit_min.
+
+For instance, after setting
+/sys/class/net/eth*/queues/tx-0/byte_queue_limits/limit_min,
+an ifconfig down/up operation might cause the ethernet driver to call
+netdev_tx_reset_queue, which in turn invokes dql_reset.
+
+In this case, dql->limit is reset to 0 while dql->limit_min remains
+non-zero value, which is unexpected. The limit should always be
+greater than or equal to limit_min.
+
+Signed-off-by: Jing Su <jingsusu@didiglobal.com>
+Link: https://patch.msgid.link/Z9qHD1s/NEuQBdgH@pilot-ThinkCentre-M930t-N000
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ lib/dynamic_queue_limits.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/lib/dynamic_queue_limits.c b/lib/dynamic_queue_limits.c
+index c1b7638a594ac..f97a752e900a0 100644
+--- a/lib/dynamic_queue_limits.c
++++ b/lib/dynamic_queue_limits.c
+@@ -190,7 +190,7 @@ EXPORT_SYMBOL(dql_completed);
+ void dql_reset(struct dql *dql)
+ {
+ /* Reset all dynamic values */
+- dql->limit = 0;
++ dql->limit = dql->min_limit;
+ dql->num_queued = 0;
+ dql->num_completed = 0;
+ dql->last_obj_cnt = 0;
+--
+2.39.5
+
--- /dev/null
+From 469a5bbb0cefbe5ae7373c935815c35540dd31a2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 25 Feb 2025 07:35:46 +0100
+Subject: driver core: faux: only create the device if probe() succeeds
+
+From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+[ Upstream commit 21b0dc55bed6d9b5dd5d1ad22b75d9d1c7426bbc ]
+
+It's really hard to know if a faux device properly passes the callback
+to probe() without having to poke around in the faux_device structure
+and then clean up. Instead of having to have every user of the api do
+this logic, just do it in the faux device core itself.
+
+This makes the use of a custom probe() callback for a faux device much
+simpler overall.
+
+Suggested-by: Kurt Borja <kuurtb@gmail.com>
+Cc: Rafael J. Wysocki <rafael@kernel.org>
+Reviewed-by: Kurt Borja <kuurtb@gmail.com>
+Reviewed-by: Danilo Krummrich <dakr@kernel.org>
+Link: https://lore.kernel.org/r/2025022545-unroasted-common-fa0e@gregkh
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/base/faux.c | 15 ++++++++++++++-
+ 1 file changed, 14 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/base/faux.c b/drivers/base/faux.c
+index 531e9d789ee04..407c1d1aad50b 100644
+--- a/drivers/base/faux.c
++++ b/drivers/base/faux.c
+@@ -102,7 +102,9 @@ static void faux_device_release(struct device *dev)
+ *
+ * Note, when this function is called, the functions specified in struct
+ * faux_ops can be called before the function returns, so be prepared for
+- * everything to be properly initialized before that point in time.
++ * everything to be properly initialized before that point in time. If the
++ * probe callback (if one is present) does NOT succeed, the creation of the
++ * device will fail and NULL will be returned.
+ *
+ * Return:
+ * * NULL if an error happened with creating the device
+@@ -147,6 +149,17 @@ struct faux_device *faux_device_create_with_groups(const char *name,
+ return NULL;
+ }
+
++ /*
++ * Verify that we did bind the driver to the device (i.e. probe worked),
++ * if not, let's fail the creation as trying to guess if probe was
++ * successful is almost impossible to determine by the caller.
++ */
++ if (!dev->driver) {
++ dev_err(dev, "probe did not succeed, tearing down the device\n");
++ faux_device_destroy(faux_dev);
++ faux_dev = NULL;
++ }
++
+ return faux_dev;
+ }
+ EXPORT_SYMBOL_GPL(faux_device_create_with_groups);
+--
+2.39.5
+
--- /dev/null
+From 405e6cdabda45e49545617dfbf8856085c47a71c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 16 Dec 2024 16:43:14 -0800
+Subject: drm: Add valid clones check
+
+From: Jessica Zhang <quic_jesszhan@quicinc.com>
+
+[ Upstream commit 41b4b11da02157c7474caf41d56baae0e941d01a ]
+
+Check that all encoders attached to a given CRTC are valid
+possible_clones of each other.
+
+Signed-off-by: Jessica Zhang <quic_jesszhan@quicinc.com>
+Reviewed-by: Maxime Ripard <mripard@kernel.org>
+Link: https://patchwork.freedesktop.org/patch/msgid/20241216-concurrent-wb-v4-3-fe220297a7f0@quicinc.com
+Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/drm_atomic_helper.c | 28 ++++++++++++++++++++++++++++
+ 1 file changed, 28 insertions(+)
+
+diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
+index 32902f77f00dd..40e4e1b6c9110 100644
+--- a/drivers/gpu/drm/drm_atomic_helper.c
++++ b/drivers/gpu/drm/drm_atomic_helper.c
+@@ -574,6 +574,30 @@ mode_valid(struct drm_atomic_state *state)
+ return 0;
+ }
+
++static int drm_atomic_check_valid_clones(struct drm_atomic_state *state,
++ struct drm_crtc *crtc)
++{
++ struct drm_encoder *drm_enc;
++ struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
++ crtc);
++
++ drm_for_each_encoder_mask(drm_enc, crtc->dev, crtc_state->encoder_mask) {
++ if (!drm_enc->possible_clones) {
++ DRM_DEBUG("enc%d possible_clones is 0\n", drm_enc->base.id);
++ continue;
++ }
++
++ if ((crtc_state->encoder_mask & drm_enc->possible_clones) !=
++ crtc_state->encoder_mask) {
++ DRM_DEBUG("crtc%d failed valid clone check for mask 0x%x\n",
++ crtc->base.id, crtc_state->encoder_mask);
++ return -EINVAL;
++ }
++ }
++
++ return 0;
++}
++
+ /**
+ * drm_atomic_helper_check_modeset - validate state object for modeset changes
+ * @dev: DRM device
+@@ -745,6 +769,10 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
+ ret = drm_atomic_add_affected_planes(state, crtc);
+ if (ret != 0)
+ return ret;
++
++ ret = drm_atomic_check_valid_clones(state, crtc);
++ if (ret != 0)
++ return ret;
+ }
+
+ /*
+--
+2.39.5
+
--- /dev/null
+From 144b8b91a2ac75a10c0dbd7e245fb32458406d7c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Jan 2025 14:13:51 -0500
+Subject: drm/amd/display: Account For OTO Prefetch Bandwidth When Calculating
+ Urgent Bandwidth
+
+From: Austin Zheng <Austin.Zheng@amd.com>
+
+[ Upstream commit 36681f15bb12b5c01df924379cdab9234259825c ]
+
+[Why]
+1) The current calculations for OTO prefetch bandwidth do not consider the number of DPP pipes in use.
+As a result, OTO prefetch bandwidth may be larger than the vactive bandwidth if multiple DPP pipes are used.
+OTO prefetch bandwidth should never exceed the vactive bandwidth.
+
+2) Mode programming may be mismatched with mode support
+In cases where mode support has chosen to use the equalized (equ) prefetch schedule,
+mode programming may end up using oto prefetch schedule instead.
+The bandwidth required to do the oto schedule may end up being higher than the equ schedule.
+This can cause the required urgent bandwidth to exceed the available urgent bandwidth.
+
+[How]
+Output the oto prefetch bandwidth and incorperate it into the urgent bandwidth calculations
+even if the prefetch schedule being used is not the oto schedule.
+
+Reviewed-by: Dillon Varone <dillon.varone@amd.com>
+Signed-off-by: Austin Zheng <Austin.Zheng@amd.com>
+Signed-off-by: Zaeem Mohamed <zaeem.mohamed@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../src/dml2_core/dml2_core_dcn4_calcs.c | 25 ++++++++++++++++++-
+ .../src/dml2_core/dml2_core_shared_types.h | 5 ++++
+ 2 files changed, 29 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c b/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c
+index 8ad7704b76691..913f33c31cf38 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c
++++ b/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c
+@@ -4915,6 +4915,7 @@ static double get_urgent_bandwidth_required(
+ double ReadBandwidthChroma[],
+ double PrefetchBandwidthLuma[],
+ double PrefetchBandwidthChroma[],
++ double PrefetchBandwidthOto[],
+ double excess_vactive_fill_bw_l[],
+ double excess_vactive_fill_bw_c[],
+ double cursor_bw[],
+@@ -4978,8 +4979,9 @@ static double get_urgent_bandwidth_required(
+ l->vm_row_bw = NumberOfDPP[k] * prefetch_vmrow_bw[k];
+ l->flip_and_active_bw = l->per_plane_flip_bw[k] + ReadBandwidthLuma[k] * l->adj_factor_p0 + ReadBandwidthChroma[k] * l->adj_factor_p1 + cursor_bw[k] * l->adj_factor_cur;
+ l->flip_and_prefetch_bw = l->per_plane_flip_bw[k] + NumberOfDPP[k] * (PrefetchBandwidthLuma[k] * l->adj_factor_p0_pre + PrefetchBandwidthChroma[k] * l->adj_factor_p1_pre) + prefetch_cursor_bw[k] * l->adj_factor_cur_pre;
++ l->flip_and_prefetch_bw_oto = l->per_plane_flip_bw[k] + NumberOfDPP[k] * (PrefetchBandwidthOto[k] * l->adj_factor_p0_pre + PrefetchBandwidthChroma[k] * l->adj_factor_p1_pre) + prefetch_cursor_bw[k] * l->adj_factor_cur_pre;
+ l->active_and_excess_bw = (ReadBandwidthLuma[k] + excess_vactive_fill_bw_l[k]) * l->tmp_nom_adj_factor_p0 + (ReadBandwidthChroma[k] + excess_vactive_fill_bw_c[k]) * l->tmp_nom_adj_factor_p1 + dpte_row_bw[k] + meta_row_bw[k];
+- surface_required_bw[k] = math_max4(l->vm_row_bw, l->flip_and_active_bw, l->flip_and_prefetch_bw, l->active_and_excess_bw);
++ surface_required_bw[k] = math_max5(l->vm_row_bw, l->flip_and_active_bw, l->flip_and_prefetch_bw, l->active_and_excess_bw, l->flip_and_prefetch_bw_oto);
+
+ /* export peak required bandwidth for the surface */
+ surface_peak_required_bw[k] = math_max2(surface_required_bw[k], surface_peak_required_bw[k]);
+@@ -5177,6 +5179,7 @@ static bool CalculatePrefetchSchedule(struct dml2_core_internal_scratch *scratch
+ s->Tsw_est3 = 0.0;
+ s->cursor_prefetch_bytes = 0;
+ *p->prefetch_cursor_bw = 0;
++ *p->RequiredPrefetchBWOTO = 0.0;
+
+ dcc_mrq_enable = (p->dcc_enable && p->mrq_present);
+
+@@ -5390,6 +5393,9 @@ static bool CalculatePrefetchSchedule(struct dml2_core_internal_scratch *scratch
+ s->prefetch_bw_oto += (p->swath_width_chroma_ub * p->myPipe->BytePerPixelC) / s->LineTime;
+ }
+
++ /* oto prefetch bw should be always be less than total vactive bw */
++ DML2_ASSERT(s->prefetch_bw_oto < s->per_pipe_vactive_sw_bw * p->myPipe->DPPPerSurface);
++
+ s->prefetch_bw_oto = math_max2(s->per_pipe_vactive_sw_bw, s->prefetch_bw_oto) * p->mall_prefetch_sdp_overhead_factor;
+
+ s->prefetch_bw_oto = math_min2(s->prefetch_bw_oto, *p->prefetch_sw_bytes/(s->min_Lsw_oto*s->LineTime));
+@@ -5400,6 +5406,12 @@ static bool CalculatePrefetchSchedule(struct dml2_core_internal_scratch *scratch
+ p->vm_bytes * p->HostVMInefficiencyFactor / (31 * s->LineTime) - *p->Tno_bw,
+ (p->PixelPTEBytesPerRow * p->HostVMInefficiencyFactor + p->meta_row_bytes + tdlut_row_bytes) / (15 * s->LineTime));
+
++ /* oto bw needs to be outputted even if the oto schedule isn't being used to avoid ms/mp mismatch.
++ * mp will fail if ms decides to use equ schedule and mp decides to use oto schedule
++ * and the required bandwidth increases when going from ms to mp
++ */
++ *p->RequiredPrefetchBWOTO = s->prefetch_bw_oto;
++
+ #ifdef __DML_VBA_DEBUG__
+ dml2_printf("DML::%s: vactive_sw_bw_l = %f\n", __func__, p->vactive_sw_bw_l);
+ dml2_printf("DML::%s: vactive_sw_bw_c = %f\n", __func__, p->vactive_sw_bw_c);
+@@ -6160,6 +6172,7 @@ static void calculate_peak_bandwidth_required(
+ p->surface_read_bandwidth_c,
+ l->zero_array, //PrefetchBandwidthLuma,
+ l->zero_array, //PrefetchBandwidthChroma,
++ l->zero_array, //PrefetchBWOTO
+ l->zero_array,
+ l->zero_array,
+ l->zero_array,
+@@ -6196,6 +6209,7 @@ static void calculate_peak_bandwidth_required(
+ p->surface_read_bandwidth_c,
+ l->zero_array, //PrefetchBandwidthLuma,
+ l->zero_array, //PrefetchBandwidthChroma,
++ l->zero_array, //PrefetchBWOTO
+ p->excess_vactive_fill_bw_l,
+ p->excess_vactive_fill_bw_c,
+ p->cursor_bw,
+@@ -6232,6 +6246,7 @@ static void calculate_peak_bandwidth_required(
+ p->surface_read_bandwidth_c,
+ p->prefetch_bandwidth_l,
+ p->prefetch_bandwidth_c,
++ p->prefetch_bandwidth_oto, // to prevent ms/mp mismatch when oto bw > total vactive bw
+ p->excess_vactive_fill_bw_l,
+ p->excess_vactive_fill_bw_c,
+ p->cursor_bw,
+@@ -6268,6 +6283,7 @@ static void calculate_peak_bandwidth_required(
+ p->surface_read_bandwidth_c,
+ p->prefetch_bandwidth_l,
+ p->prefetch_bandwidth_c,
++ p->prefetch_bandwidth_oto, // to prevent ms/mp mismatch when oto bw > total vactive bw
+ p->excess_vactive_fill_bw_l,
+ p->excess_vactive_fill_bw_c,
+ p->cursor_bw,
+@@ -6304,6 +6320,7 @@ static void calculate_peak_bandwidth_required(
+ p->surface_read_bandwidth_c,
+ p->prefetch_bandwidth_l,
+ p->prefetch_bandwidth_c,
++ p->prefetch_bandwidth_oto, // to prevent ms/mp mismatch when oto bw > total vactive bw
+ p->excess_vactive_fill_bw_l,
+ p->excess_vactive_fill_bw_c,
+ p->cursor_bw,
+@@ -9066,6 +9083,7 @@ static bool dml_core_mode_support(struct dml2_core_calcs_mode_support_ex *in_out
+ CalculatePrefetchSchedule_params->VRatioPrefetchC = &mode_lib->ms.VRatioPreC[k];
+ CalculatePrefetchSchedule_params->RequiredPrefetchPixelDataBWLuma = &mode_lib->ms.RequiredPrefetchPixelDataBWLuma[k]; // prefetch_sw_bw_l
+ CalculatePrefetchSchedule_params->RequiredPrefetchPixelDataBWChroma = &mode_lib->ms.RequiredPrefetchPixelDataBWChroma[k]; // prefetch_sw_bw_c
++ CalculatePrefetchSchedule_params->RequiredPrefetchBWOTO = &mode_lib->ms.RequiredPrefetchBWOTO[k];
+ CalculatePrefetchSchedule_params->NotEnoughTimeForDynamicMetadata = &mode_lib->ms.NoTimeForDynamicMetadata[k];
+ CalculatePrefetchSchedule_params->Tno_bw = &mode_lib->ms.Tno_bw[k];
+ CalculatePrefetchSchedule_params->Tno_bw_flip = &mode_lib->ms.Tno_bw_flip[k];
+@@ -9210,6 +9228,7 @@ static bool dml_core_mode_support(struct dml2_core_calcs_mode_support_ex *in_out
+ calculate_peak_bandwidth_params->surface_read_bandwidth_c = mode_lib->ms.vactive_sw_bw_c;
+ calculate_peak_bandwidth_params->prefetch_bandwidth_l = mode_lib->ms.RequiredPrefetchPixelDataBWLuma;
+ calculate_peak_bandwidth_params->prefetch_bandwidth_c = mode_lib->ms.RequiredPrefetchPixelDataBWChroma;
++ calculate_peak_bandwidth_params->prefetch_bandwidth_oto = mode_lib->ms.RequiredPrefetchBWOTO;
+ calculate_peak_bandwidth_params->excess_vactive_fill_bw_l = mode_lib->ms.excess_vactive_fill_bw_l;
+ calculate_peak_bandwidth_params->excess_vactive_fill_bw_c = mode_lib->ms.excess_vactive_fill_bw_c;
+ calculate_peak_bandwidth_params->cursor_bw = mode_lib->ms.cursor_bw;
+@@ -9376,6 +9395,7 @@ static bool dml_core_mode_support(struct dml2_core_calcs_mode_support_ex *in_out
+ calculate_peak_bandwidth_params->surface_read_bandwidth_c = mode_lib->ms.vactive_sw_bw_c;
+ calculate_peak_bandwidth_params->prefetch_bandwidth_l = mode_lib->ms.RequiredPrefetchPixelDataBWLuma;
+ calculate_peak_bandwidth_params->prefetch_bandwidth_c = mode_lib->ms.RequiredPrefetchPixelDataBWChroma;
++ calculate_peak_bandwidth_params->prefetch_bandwidth_oto = mode_lib->ms.RequiredPrefetchBWOTO;
+ calculate_peak_bandwidth_params->excess_vactive_fill_bw_l = mode_lib->ms.excess_vactive_fill_bw_l;
+ calculate_peak_bandwidth_params->excess_vactive_fill_bw_c = mode_lib->ms.excess_vactive_fill_bw_c;
+ calculate_peak_bandwidth_params->cursor_bw = mode_lib->ms.cursor_bw;
+@@ -11292,6 +11312,7 @@ static bool dml_core_mode_programming(struct dml2_core_calcs_mode_programming_ex
+ CalculatePrefetchSchedule_params->VRatioPrefetchC = &mode_lib->mp.VRatioPrefetchC[k];
+ CalculatePrefetchSchedule_params->RequiredPrefetchPixelDataBWLuma = &mode_lib->mp.RequiredPrefetchPixelDataBWLuma[k];
+ CalculatePrefetchSchedule_params->RequiredPrefetchPixelDataBWChroma = &mode_lib->mp.RequiredPrefetchPixelDataBWChroma[k];
++ CalculatePrefetchSchedule_params->RequiredPrefetchBWOTO = &s->dummy_single_array[0][k];
+ CalculatePrefetchSchedule_params->NotEnoughTimeForDynamicMetadata = &mode_lib->mp.NotEnoughTimeForDynamicMetadata[k];
+ CalculatePrefetchSchedule_params->Tno_bw = &mode_lib->mp.Tno_bw[k];
+ CalculatePrefetchSchedule_params->Tno_bw_flip = &mode_lib->mp.Tno_bw_flip[k];
+@@ -11434,6 +11455,7 @@ static bool dml_core_mode_programming(struct dml2_core_calcs_mode_programming_ex
+ calculate_peak_bandwidth_params->surface_read_bandwidth_c = mode_lib->mp.vactive_sw_bw_c;
+ calculate_peak_bandwidth_params->prefetch_bandwidth_l = mode_lib->mp.RequiredPrefetchPixelDataBWLuma;
+ calculate_peak_bandwidth_params->prefetch_bandwidth_c = mode_lib->mp.RequiredPrefetchPixelDataBWChroma;
++ calculate_peak_bandwidth_params->prefetch_bandwidth_oto = s->dummy_single_array[0];
+ calculate_peak_bandwidth_params->excess_vactive_fill_bw_l = mode_lib->mp.excess_vactive_fill_bw_l;
+ calculate_peak_bandwidth_params->excess_vactive_fill_bw_c = mode_lib->mp.excess_vactive_fill_bw_c;
+ calculate_peak_bandwidth_params->cursor_bw = mode_lib->mp.cursor_bw;
+@@ -11566,6 +11588,7 @@ static bool dml_core_mode_programming(struct dml2_core_calcs_mode_programming_ex
+ calculate_peak_bandwidth_params->surface_read_bandwidth_c = mode_lib->mp.vactive_sw_bw_c;
+ calculate_peak_bandwidth_params->prefetch_bandwidth_l = mode_lib->mp.RequiredPrefetchPixelDataBWLuma;
+ calculate_peak_bandwidth_params->prefetch_bandwidth_c = mode_lib->mp.RequiredPrefetchPixelDataBWChroma;
++ calculate_peak_bandwidth_params->prefetch_bandwidth_oto = s->dummy_single_array[k];
+ calculate_peak_bandwidth_params->excess_vactive_fill_bw_l = mode_lib->mp.excess_vactive_fill_bw_l;
+ calculate_peak_bandwidth_params->excess_vactive_fill_bw_c = mode_lib->mp.excess_vactive_fill_bw_c;
+ calculate_peak_bandwidth_params->cursor_bw = mode_lib->mp.cursor_bw;
+diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_shared_types.h b/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_shared_types.h
+index 23c0fca5515fe..b7cb017b59baa 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_shared_types.h
++++ b/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_shared_types.h
+@@ -484,6 +484,8 @@ struct dml2_core_internal_mode_support {
+ double WriteBandwidth[DML2_MAX_PLANES][DML2_MAX_WRITEBACK];
+ double RequiredPrefetchPixelDataBWLuma[DML2_MAX_PLANES];
+ double RequiredPrefetchPixelDataBWChroma[DML2_MAX_PLANES];
++ /* oto bw should also be considered when calculating urgent bw to avoid situations oto/equ mismatches between ms and mp */
++ double RequiredPrefetchBWOTO[DML2_MAX_PLANES];
+ double cursor_bw[DML2_MAX_PLANES];
+ double prefetch_cursor_bw[DML2_MAX_PLANES];
+ double prefetch_vmrow_bw[DML2_MAX_PLANES];
+@@ -1381,6 +1383,7 @@ struct dml2_core_shared_get_urgent_bandwidth_required_locals {
+ double vm_row_bw;
+ double flip_and_active_bw;
+ double flip_and_prefetch_bw;
++ double flip_and_prefetch_bw_oto;
+ double active_and_excess_bw;
+ };
+
+@@ -1792,6 +1795,7 @@ struct dml2_core_calcs_CalculatePrefetchSchedule_params {
+ double *VRatioPrefetchC;
+ double *RequiredPrefetchPixelDataBWLuma;
+ double *RequiredPrefetchPixelDataBWChroma;
++ double *RequiredPrefetchBWOTO;
+ bool *NotEnoughTimeForDynamicMetadata;
+ double *Tno_bw;
+ double *Tno_bw_flip;
+@@ -2025,6 +2029,7 @@ struct dml2_core_calcs_calculate_peak_bandwidth_required_params {
+ double *surface_read_bandwidth_c;
+ double *prefetch_bandwidth_l;
+ double *prefetch_bandwidth_c;
++ double *prefetch_bandwidth_oto;
+ double *excess_vactive_fill_bw_l;
+ double *excess_vactive_fill_bw_c;
+ double *cursor_bw;
+--
+2.39.5
+
--- /dev/null
+From c9e5720c802a163c0a96de59a08e5b0f04d02ae3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 20 Jan 2025 12:35:23 -0500
+Subject: drm/amd/display: Add opp recout adjustment
+
+From: Navid Assadian <Navid.Assadian@amd.com>
+
+[ Upstream commit fba4d19f3731483ee8565f9e9bb7ed9fc89479e8 ]
+
+[Why]
+For subsampled YUV output formats, more pixels can get fetched and be
+used for scaling.
+
+[How]
+Add the adjustment to the calculated recout, so the viewport covers the
+corresponding pixels on the source plane.
+
+Signed-off-by: Navid Assadian <Navid.Assadian@amd.com>
+Reviewed-by: Samson Tam <Samson.Tam@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/spl/dc_spl.c | 31 +++++++++++++++----
+ .../gpu/drm/amd/display/dc/spl/dc_spl_types.h | 10 ++++++
+ 2 files changed, 35 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/spl/dc_spl.c b/drivers/gpu/drm/amd/display/dc/spl/dc_spl.c
+index 22602f088553d..153b7a8904e1e 100644
+--- a/drivers/gpu/drm/amd/display/dc/spl/dc_spl.c
++++ b/drivers/gpu/drm/amd/display/dc/spl/dc_spl.c
+@@ -76,6 +76,21 @@ static struct spl_rect shift_rec(const struct spl_rect *rec_in, int x, int y)
+ return rec_out;
+ }
+
++static void spl_opp_adjust_rect(struct spl_rect *rec, const struct spl_opp_adjust *adjust)
++{
++ if ((rec->x + adjust->x) >= 0)
++ rec->x += adjust->x;
++
++ if ((rec->y + adjust->y) >= 0)
++ rec->y += adjust->y;
++
++ if ((rec->width + adjust->width) >= 1)
++ rec->width += adjust->width;
++
++ if ((rec->height + adjust->height) >= 1)
++ rec->height += adjust->height;
++}
++
+ static struct spl_rect calculate_plane_rec_in_timing_active(
+ struct spl_in *spl_in,
+ const struct spl_rect *rec_in)
+@@ -723,13 +738,15 @@ static void spl_handle_3d_recout(struct spl_in *spl_in, struct spl_rect *recout)
+ }
+ }
+
+-static void spl_clamp_viewport(struct spl_rect *viewport)
++static void spl_clamp_viewport(struct spl_rect *viewport, int min_viewport_size)
+ {
++ if (min_viewport_size == 0)
++ min_viewport_size = MIN_VIEWPORT_SIZE;
+ /* Clamp minimum viewport size */
+- if (viewport->height < MIN_VIEWPORT_SIZE)
+- viewport->height = MIN_VIEWPORT_SIZE;
+- if (viewport->width < MIN_VIEWPORT_SIZE)
+- viewport->width = MIN_VIEWPORT_SIZE;
++ if (viewport->height < min_viewport_size)
++ viewport->height = min_viewport_size;
++ if (viewport->width < min_viewport_size)
++ viewport->width = min_viewport_size;
+ }
+
+ static enum scl_mode spl_get_dscl_mode(const struct spl_in *spl_in,
+@@ -1800,6 +1817,8 @@ static bool spl_calculate_number_of_taps(struct spl_in *spl_in, struct spl_scrat
+ spl_calculate_recout(spl_in, spl_scratch, spl_out);
+ /* depends on pixel format */
+ spl_calculate_scaling_ratios(spl_in, spl_scratch, spl_out);
++ /* Adjust recout for opp if needed */
++ spl_opp_adjust_rect(&spl_scratch->scl_data.recout, &spl_in->basic_in.opp_recout_adjust);
+ /* depends on scaling ratios and recout, does not calculate offset yet */
+ spl_calculate_viewport_size(spl_in, spl_scratch);
+
+@@ -1836,7 +1855,7 @@ bool spl_calculate_scaler_params(struct spl_in *spl_in, struct spl_out *spl_out)
+ // Handle 3d recout
+ spl_handle_3d_recout(spl_in, &spl_scratch.scl_data.recout);
+ // Clamp
+- spl_clamp_viewport(&spl_scratch.scl_data.viewport);
++ spl_clamp_viewport(&spl_scratch.scl_data.viewport, spl_in->min_viewport_size);
+
+ // Save all calculated parameters in dscl_prog_data structure to program hw registers
+ spl_set_dscl_prog_data(spl_in, &spl_scratch, spl_out, enable_easf_v, enable_easf_h, enable_isharp);
+diff --git a/drivers/gpu/drm/amd/display/dc/spl/dc_spl_types.h b/drivers/gpu/drm/amd/display/dc/spl/dc_spl_types.h
+index 5d139cf51e89b..1c3949b24611f 100644
+--- a/drivers/gpu/drm/amd/display/dc/spl/dc_spl_types.h
++++ b/drivers/gpu/drm/amd/display/dc/spl/dc_spl_types.h
+@@ -427,6 +427,14 @@ struct spl_out {
+
+ // SPL inputs
+
++// opp extra adjustment for rect
++struct spl_opp_adjust {
++ int x;
++ int y;
++ int width;
++ int height;
++};
++
+ // Basic input information
+ struct basic_in {
+ enum spl_pixel_format format; // Pixel Format
+@@ -444,6 +452,7 @@ struct basic_in {
+ } num_slices_recout_width;
+ } num_h_slices_recout_width_align;
+ int mpc_h_slice_index; // previous mpc_combine_v - split_idx
++ struct spl_opp_adjust opp_recout_adjust;
+ // Inputs for adaptive scaler - TODO
+ enum spl_transfer_func_type tf_type; /* Transfer function type */
+ enum spl_transfer_func_predefined tf_predefined_type; /* Transfer function predefined type */
+@@ -535,6 +544,7 @@ struct spl_in {
+ bool is_hdr_on;
+ int h_active;
+ int v_active;
++ int min_viewport_size;
+ int sdr_white_level_nits;
+ enum sharpen_policy sharpen_policy;
+ };
+--
+2.39.5
+
--- /dev/null
+From ea71cdda73d2a5d6bfdd47db95d2ab3f033352ce Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 7 Feb 2025 13:46:53 -0500
+Subject: drm/amd/display: Add support for disconnected eDP streams
+
+From: Harry VanZyllDeJong <hvanzyll@amd.com>
+
+[ Upstream commit 6571bef25fe48c642f7a69ccf7c3198b317c136a ]
+
+[Why]
+eDP may not be connected to the GPU on driver start causing
+fail enumeration.
+
+[How]
+Move the virtual signal type check before the eDP connector
+signal check.
+
+Reviewed-by: Wenjing Liu <wenjing.liu@amd.com>
+Signed-off-by: Harry VanZyllDeJong <hvanzyll@amd.com>
+Signed-off-by: Roman Li <roman.li@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../drm/amd/display/dc/link/protocols/link_dp_capability.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c
+index 6d7131369f00b..28843e9882d39 100644
+--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c
++++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c
+@@ -945,6 +945,9 @@ bool link_decide_link_settings(struct dc_stream_state *stream,
+ * TODO: add MST specific link training routine
+ */
+ decide_mst_link_settings(link, link_setting);
++ } else if (stream->signal == SIGNAL_TYPE_VIRTUAL) {
++ link_setting->lane_count = LANE_COUNT_FOUR;
++ link_setting->link_rate = LINK_RATE_HIGH3;
+ } else if (link->connector_signal == SIGNAL_TYPE_EDP) {
+ /* enable edp link optimization for DSC eDP case */
+ if (stream->timing.flags.DSC) {
+@@ -967,9 +970,6 @@ bool link_decide_link_settings(struct dc_stream_state *stream,
+ } else {
+ edp_decide_link_settings(link, link_setting, req_bw);
+ }
+- } else if (stream->signal == SIGNAL_TYPE_VIRTUAL) {
+- link_setting->lane_count = LANE_COUNT_FOUR;
+- link_setting->link_rate = LINK_RATE_HIGH3;
+ } else {
+ decide_dp_link_settings(link, link_setting, req_bw);
+ }
+--
+2.39.5
+
--- /dev/null
+From 9d40dfbefe3e2127f6cc75d95ebf5f919dc72bf7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 14 Jan 2025 12:14:26 -0500
+Subject: drm/amd/display: Ammend DCPG IP control sequences to align with HW
+ guidance
+
+From: Dillon Varone <dillon.varone@amd.com>
+
+[ Upstream commit cbd97d621ece1d92c3542e52f8af7c04cd2c6afb ]
+
+[WHY&HOW]
+IP_REQUEST_CNTL should only be toggled off when it was originally, never
+unconditionally.
+
+Reviewed-by: Alvin Lee <alvin.lee2@amd.com>
+Signed-off-by: Dillon Varone <dillon.varone@amd.com>
+Signed-off-by: Zaeem Mohamed <zaeem.mohamed@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../amd/display/dc/hwss/dcn20/dcn20_hwseq.c | 14 +++++---
+ .../amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 34 +++++++++++++++++++
+ .../amd/display/dc/hwss/dcn401/dcn401_hwseq.h | 3 ++
+ .../amd/display/dc/hwss/dcn401/dcn401_init.c | 2 +-
+ 4 files changed, 48 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
+index f7e31aec32058..1a07973ead4f5 100644
+--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
+@@ -1264,14 +1264,18 @@ static void dcn20_power_on_plane_resources(
+ struct dce_hwseq *hws,
+ struct pipe_ctx *pipe_ctx)
+ {
++ uint32_t org_ip_request_cntl = 0;
++
+ DC_LOGGER_INIT(hws->ctx->logger);
+
+ if (hws->funcs.dpp_root_clock_control)
+ hws->funcs.dpp_root_clock_control(hws, pipe_ctx->plane_res.dpp->inst, true);
+
+ if (REG(DC_IP_REQUEST_CNTL)) {
+- REG_SET(DC_IP_REQUEST_CNTL, 0,
+- IP_REQUEST_EN, 1);
++ REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl);
++ if (org_ip_request_cntl == 0)
++ REG_SET(DC_IP_REQUEST_CNTL, 0,
++ IP_REQUEST_EN, 1);
+
+ if (hws->funcs.dpp_pg_control)
+ hws->funcs.dpp_pg_control(hws, pipe_ctx->plane_res.dpp->inst, true);
+@@ -1279,8 +1283,10 @@ static void dcn20_power_on_plane_resources(
+ if (hws->funcs.hubp_pg_control)
+ hws->funcs.hubp_pg_control(hws, pipe_ctx->plane_res.hubp->inst, true);
+
+- REG_SET(DC_IP_REQUEST_CNTL, 0,
+- IP_REQUEST_EN, 0);
++ if (org_ip_request_cntl == 0)
++ REG_SET(DC_IP_REQUEST_CNTL, 0,
++ IP_REQUEST_EN, 0);
++
+ DC_LOG_DEBUG(
+ "Un-gated front end for pipe %d\n", pipe_ctx->plane_res.hubp->inst);
+ }
+diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
+index 284f011f5643d..a6f2aff84267d 100644
+--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
+@@ -2655,3 +2655,37 @@ void dcn401_detect_pipe_changes(struct dc_state *old_state,
+ new_pipe->update_flags.bits.test_pattern_changed = 1;
+ }
+ }
++
++void dcn401_plane_atomic_power_down(struct dc *dc,
++ struct dpp *dpp,
++ struct hubp *hubp)
++{
++ struct dce_hwseq *hws = dc->hwseq;
++ uint32_t org_ip_request_cntl = 0;
++
++ DC_LOGGER_INIT(dc->ctx->logger);
++
++ REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl);
++ if (org_ip_request_cntl == 0)
++ REG_SET(DC_IP_REQUEST_CNTL, 0,
++ IP_REQUEST_EN, 1);
++
++ if (hws->funcs.dpp_pg_control)
++ hws->funcs.dpp_pg_control(hws, dpp->inst, false);
++
++ if (hws->funcs.hubp_pg_control)
++ hws->funcs.hubp_pg_control(hws, hubp->inst, false);
++
++ hubp->funcs->hubp_reset(hubp);
++ dpp->funcs->dpp_reset(dpp);
++
++ if (org_ip_request_cntl == 0)
++ REG_SET(DC_IP_REQUEST_CNTL, 0,
++ IP_REQUEST_EN, 0);
++
++ DC_LOG_DEBUG(
++ "Power gated front end %d\n", hubp->inst);
++
++ if (hws->funcs.dpp_root_clock_control)
++ hws->funcs.dpp_root_clock_control(hws, dpp->inst, false);
++}
+diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h
+index 17cea748789e1..dbd69d215b8bc 100644
+--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h
++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h
+@@ -102,4 +102,7 @@ void dcn401_detect_pipe_changes(
+ struct dc_state *new_state,
+ struct pipe_ctx *old_pipe,
+ struct pipe_ctx *new_pipe);
++void dcn401_plane_atomic_power_down(struct dc *dc,
++ struct dpp *dpp,
++ struct hubp *hubp);
+ #endif /* __DC_HWSS_DCN401_H__ */
+diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c
+index 44cb376f97c17..a4e3501fadbbe 100644
+--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c
++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c
+@@ -123,7 +123,7 @@ static const struct hwseq_private_funcs dcn401_private_funcs = {
+ .disable_vga = dcn20_disable_vga,
+ .bios_golden_init = dcn10_bios_golden_init,
+ .plane_atomic_disable = dcn20_plane_atomic_disable,
+- .plane_atomic_power_down = dcn10_plane_atomic_power_down,
++ .plane_atomic_power_down = dcn401_plane_atomic_power_down,
+ .enable_power_gating_plane = dcn32_enable_power_gating_plane,
+ .hubp_pg_control = dcn32_hubp_pg_control,
+ .program_all_writeback_pipes_in_tree = dcn30_program_all_writeback_pipes_in_tree,
+--
+2.39.5
+
--- /dev/null
+From 678160d9fb7eafe7bd1327c3e8430dff276a5ab1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Feb 2025 20:09:14 +0800
+Subject: drm/amd/display: calculate the remain segments for all pipes
+
+From: Zhikai Zhai <zhikai.zhai@amd.com>
+
+[ Upstream commit d3069feecdb5542604d29b59acfd1fd213bad95b ]
+
+[WHY]
+In some cases the remain de-tile buffer segments will be greater
+than zero if we don't add the non-top pipe to calculate, at
+this time the override de-tile buffer size will be valid and used.
+But it makes the de-tile buffer segments used finally for all of pipes
+exceed the maximum.
+
+[HOW]
+Add the non-top pipe to calculate the remain de-tile buffer segments.
+Don't set override size to use the average according to pipe count
+if the value exceed the maximum.
+
+Reviewed-by: Charlene Liu <charlene.liu@amd.com>
+Signed-off-by: Zhikai Zhai <zhikai.zhai@amd.com>
+Signed-off-by: Tom Chung <chiahsuan.chung@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../dc/resource/dcn315/dcn315_resource.c | 42 +++++++++----------
+ 1 file changed, 20 insertions(+), 22 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c
+index 14acef036b5a0..6c2bb3f63be15 100644
+--- a/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c
+@@ -1698,7 +1698,7 @@ static int dcn315_populate_dml_pipes_from_context(
+ pipes[pipe_cnt].dout.dsc_input_bpc = 0;
+ DC_FP_START();
+ dcn31_zero_pipe_dcc_fraction(pipes, pipe_cnt);
+- if (pixel_rate_crb && !pipe->top_pipe && !pipe->prev_odm_pipe) {
++ if (pixel_rate_crb) {
+ int bpp = source_format_to_bpp(pipes[pipe_cnt].pipe.src.source_format);
+ /* Ceil to crb segment size */
+ int approx_det_segs_required_for_pstate = dcn_get_approx_det_segs_required_for_pstate(
+@@ -1755,28 +1755,26 @@ static int dcn315_populate_dml_pipes_from_context(
+ continue;
+ }
+
+- if (!pipe->top_pipe && !pipe->prev_odm_pipe) {
+- bool split_required = pipe->stream->timing.pix_clk_100hz >= dcn_get_max_non_odm_pix_rate_100hz(&dc->dml.soc)
+- || (pipe->plane_state && pipe->plane_state->src_rect.width > 5120);
+-
+- if (remaining_det_segs > MIN_RESERVED_DET_SEGS && crb_pipes != 0)
+- pipes[pipe_cnt].pipe.src.det_size_override += (remaining_det_segs - MIN_RESERVED_DET_SEGS) / crb_pipes +
+- (crb_idx < (remaining_det_segs - MIN_RESERVED_DET_SEGS) % crb_pipes ? 1 : 0);
+- if (pipes[pipe_cnt].pipe.src.det_size_override > 2 * DCN3_15_MAX_DET_SEGS) {
+- /* Clamp to 2 pipe split max det segments */
+- remaining_det_segs += pipes[pipe_cnt].pipe.src.det_size_override - 2 * (DCN3_15_MAX_DET_SEGS);
+- pipes[pipe_cnt].pipe.src.det_size_override = 2 * DCN3_15_MAX_DET_SEGS;
+- }
+- if (pipes[pipe_cnt].pipe.src.det_size_override > DCN3_15_MAX_DET_SEGS || split_required) {
+- /* If we are splitting we must have an even number of segments */
+- remaining_det_segs += pipes[pipe_cnt].pipe.src.det_size_override % 2;
+- pipes[pipe_cnt].pipe.src.det_size_override -= pipes[pipe_cnt].pipe.src.det_size_override % 2;
+- }
+- /* Convert segments into size for DML use */
+- pipes[pipe_cnt].pipe.src.det_size_override *= DCN3_15_CRB_SEGMENT_SIZE_KB;
+-
+- crb_idx++;
++ bool split_required = pipe->stream->timing.pix_clk_100hz >= dcn_get_max_non_odm_pix_rate_100hz(&dc->dml.soc)
++ || (pipe->plane_state && pipe->plane_state->src_rect.width > 5120);
++
++ if (remaining_det_segs > MIN_RESERVED_DET_SEGS && crb_pipes != 0)
++ pipes[pipe_cnt].pipe.src.det_size_override += (remaining_det_segs - MIN_RESERVED_DET_SEGS) / crb_pipes +
++ (crb_idx < (remaining_det_segs - MIN_RESERVED_DET_SEGS) % crb_pipes ? 1 : 0);
++ if (pipes[pipe_cnt].pipe.src.det_size_override > 2 * DCN3_15_MAX_DET_SEGS) {
++ /* Clamp to 2 pipe split max det segments */
++ remaining_det_segs += pipes[pipe_cnt].pipe.src.det_size_override - 2 * (DCN3_15_MAX_DET_SEGS);
++ pipes[pipe_cnt].pipe.src.det_size_override = 2 * DCN3_15_MAX_DET_SEGS;
++ }
++ if (pipes[pipe_cnt].pipe.src.det_size_override > DCN3_15_MAX_DET_SEGS || split_required) {
++ /* If we are splitting we must have an even number of segments */
++ remaining_det_segs += pipes[pipe_cnt].pipe.src.det_size_override % 2;
++ pipes[pipe_cnt].pipe.src.det_size_override -= pipes[pipe_cnt].pipe.src.det_size_override % 2;
+ }
++ /* Convert segments into size for DML use */
++ pipes[pipe_cnt].pipe.src.det_size_override *= DCN3_15_CRB_SEGMENT_SIZE_KB;
++
++ crb_idx++;
+ pipe_cnt++;
+ }
+ }
+--
+2.39.5
+
--- /dev/null
+From bf4a0c678ba742424cd8675f0700546381eab492 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 17 Apr 2025 10:24:29 -0400
+Subject: drm/amd/display: Call FP Protect Before Mode Programming/Mode Support
+
+From: Austin Zheng <Austin.Zheng@amd.com>
+
+[ Upstream commit eba692ca3abca258b3214a6e4126afefad1822f0 ]
+
+[Why]
+Memory allocation occurs within dml21_validate() for adding phantom planes.
+May cause kernel to be tainted due to usage of FP Start.
+
+[How]
+Move FP start from dml21_validate to before mode programming/mode support.
+Calculations requiring floating point are all done within mode programming
+or mode support.
+
+Reviewed-by: Alvin Lee <alvin.lee2@amd.com>
+Signed-off-by: Austin Zheng <Austin.Zheng@amd.com>
+Signed-off-by: Ray Wu <ray.wu@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+(cherry picked from commit fe3250f10819b411808ab9ae1d824c5fc9b59170)
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/dml2/dml21/dml21_wrapper.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml21/dml21_wrapper.c b/drivers/gpu/drm/amd/display/dc/dml2/dml21/dml21_wrapper.c
+index 5d16f36ec95c8..ed6584535e898 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml2/dml21/dml21_wrapper.c
++++ b/drivers/gpu/drm/amd/display/dc/dml2/dml21/dml21_wrapper.c
+@@ -234,7 +234,9 @@ static bool dml21_mode_check_and_programming(const struct dc *in_dc, struct dc_s
+ if (!result)
+ return false;
+
++ DC_FP_START();
+ result = dml2_build_mode_programming(mode_programming);
++ DC_FP_END();
+ if (!result)
+ return false;
+
+@@ -277,7 +279,9 @@ static bool dml21_check_mode_support(const struct dc *in_dc, struct dc_state *co
+ mode_support->dml2_instance = dml_init->dml2_instance;
+ dml21_map_dc_state_into_dml_display_cfg(in_dc, context, dml_ctx);
+ dml_ctx->v21.mode_programming.dml2_instance->scratch.build_mode_programming_locals.mode_programming_params.programming = dml_ctx->v21.mode_programming.programming;
++ DC_FP_START();
+ is_supported = dml2_check_mode_supported(mode_support);
++ DC_FP_END();
+ if (!is_supported)
+ return false;
+
+@@ -288,16 +292,12 @@ bool dml21_validate(const struct dc *in_dc, struct dc_state *context, struct dml
+ {
+ bool out = false;
+
+- DC_FP_START();
+-
+ /* Use dml_validate_only for fast_validate path */
+ if (fast_validate)
+ out = dml21_check_mode_support(in_dc, context, dml_ctx);
+ else
+ out = dml21_mode_check_and_programming(in_dc, context, dml_ctx);
+
+- DC_FP_END();
+-
+ return out;
+ }
+
+--
+2.39.5
+
--- /dev/null
+From ba0f8a83948c429f8b30510b6b071567dad0a38c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 28 Feb 2025 10:35:23 +0800
+Subject: drm/amd/display: Correct timing_adjust_pending flag setting.
+
+From: Zhongwei Zhang <Zhongwei.Zhang@amd.com>
+
+[ Upstream commit 34935701b7ed1a1ef449310ba041f10964b23cf4 ]
+
+[Why&How]
+stream->adjust will be overwritten by update->crtc_timing_adjust.
+We should set update->crtc_timing_adjust->timing_adjust_pending
+and then overwrite stream->adjust.
+Reset update->crtc_timing_adjust->timing_adjust_pending after
+the assignment.
+
+Reviewed-by: Charlene Liu <charlene.liu@amd.com>
+Signed-off-by: Zhongwei Zhang <Zhongwei.Zhang@amd.com>
+Signed-off-by: Tom Chung <chiahsuan.chung@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Stable-dep-of: 874697e12793 ("drm/amd/display: Defer BW-optimization-blocked DRR adjustments")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/core/dc.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
+index a444fe1e0838a..e70b097cf478d 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
+@@ -3131,8 +3131,9 @@ static void copy_stream_update_to_stream(struct dc *dc,
+ if (update->crtc_timing_adjust) {
+ if (stream->adjust.v_total_min != update->crtc_timing_adjust->v_total_min ||
+ stream->adjust.v_total_max != update->crtc_timing_adjust->v_total_max)
+- stream->adjust.timing_adjust_pending = true;
++ update->crtc_timing_adjust->timing_adjust_pending = true;
+ stream->adjust = *update->crtc_timing_adjust;
++ update->crtc_timing_adjust->timing_adjust_pending = false;
+ }
+
+ if (update->dpms_off)
+--
+2.39.5
+
--- /dev/null
+From d1ac63be1590dc6c45ec39a6254285b32a04bd21 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 16 Apr 2025 02:54:26 -0400
+Subject: drm/amd/display: Defer BW-optimization-blocked DRR adjustments
+
+From: John Olender <john.olender@gmail.com>
+
+[ Upstream commit 874697e127931bf50a37ce9d96ee80f3a08a0c38 ]
+
+[Why & How]
+Instead of dropping DRR updates, defer them. This fixes issues where
+monitor continues to see incorrect refresh rate after VRR was turned off
+by userspace.
+
+Fixes: 32953485c558 ("drm/amd/display: Do not update DRR while BW optimizations pending")
+Link: https://gitlab.freedesktop.org/drm/amd/-/issues/3546
+Reviewed-by: Sun peng Li <sunpeng.li@amd.com>
+Signed-off-by: John Olender <john.olender@gmail.com>
+Signed-off-by: Aurabindo Pillai <aurabindo.pillai@amd.com>
+Signed-off-by: Ray Wu <ray.wu@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+(cherry picked from commit 53761b7ecd83e6fbb9f2206f8c980a6aa308c844)
+Cc: stable@vger.kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 ++
+ drivers/gpu/drm/amd/display/dc/core/dc.c | 10 +++++++---
+ 2 files changed, 9 insertions(+), 3 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 4a8d76a4f3ce6..ee79a54de6d19 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+@@ -367,6 +367,8 @@ get_crtc_by_otg_inst(struct amdgpu_device *adev,
+ static inline bool is_dc_timing_adjust_needed(struct dm_crtc_state *old_state,
+ struct dm_crtc_state *new_state)
+ {
++ if (new_state->stream->adjust.timing_adjust_pending)
++ return true;
+ if (new_state->freesync_config.state == VRR_STATE_ACTIVE_FIXED)
+ return true;
+ else if (amdgpu_dm_crtc_vrr_active(old_state) != amdgpu_dm_crtc_vrr_active(new_state))
+diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
+index e70b097cf478d..722175e347fdc 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
+@@ -438,9 +438,12 @@ bool dc_stream_adjust_vmin_vmax(struct dc *dc,
+ * Don't adjust DRR while there's bandwidth optimizations pending to
+ * avoid conflicting with firmware updates.
+ */
+- if (dc->ctx->dce_version > DCE_VERSION_MAX)
+- if (dc->optimized_required || dc->wm_optimized_required)
++ if (dc->ctx->dce_version > DCE_VERSION_MAX) {
++ if (dc->optimized_required || dc->wm_optimized_required) {
++ stream->adjust.timing_adjust_pending = true;
+ return false;
++ }
++ }
+
+ dc_exit_ips_for_hw_access(dc);
+
+@@ -3130,7 +3133,8 @@ static void copy_stream_update_to_stream(struct dc *dc,
+
+ if (update->crtc_timing_adjust) {
+ if (stream->adjust.v_total_min != update->crtc_timing_adjust->v_total_min ||
+- stream->adjust.v_total_max != update->crtc_timing_adjust->v_total_max)
++ stream->adjust.v_total_max != update->crtc_timing_adjust->v_total_max ||
++ stream->adjust.timing_adjust_pending)
+ update->crtc_timing_adjust->timing_adjust_pending = true;
+ stream->adjust = *update->crtc_timing_adjust;
+ update->crtc_timing_adjust->timing_adjust_pending = false;
+--
+2.39.5
+
--- /dev/null
+From b0779980722dac03c41a452591f2dc66ae9ca50b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 17 Dec 2024 09:25:18 -0500
+Subject: drm/amd/display/dm: drop hw_support check in amdgpu_dm_i2c_xfer()
+
+From: Alex Deucher <alexander.deucher@amd.com>
+
+[ Upstream commit 33da70bd1e115d7d73f45fb1c09f5ecc448f3f13 ]
+
+DC supports SW i2c as well. Drop the check.
+
+Reviewed-by: Harry Wentland <harry.wentland@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+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 2cfc18401f3f2..7b1fd3b28e9b5 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+@@ -8382,7 +8382,7 @@ static int amdgpu_dm_i2c_xfer(struct i2c_adapter *i2c_adap,
+ int i;
+ int result = -EIO;
+
+- if (!ddc_service->ddc_pin || !ddc_service->ddc_pin->hw_info.hw_supported)
++ if (!ddc_service->ddc_pin)
+ return result;
+
+ cmd.payloads = kcalloc(num, sizeof(struct i2c_payload), GFP_KERNEL);
+--
+2.39.5
+
--- /dev/null
+From 18e2449381305bced8aa7e747c78d454ba7d2862 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 13 Feb 2025 16:18:34 +0800
+Subject: drm/amd/display: Do not enable replay when vtotal update is pending.
+
+From: Danny Wang <danny.wang@amd.com>
+
+[ Upstream commit bd00b29b5f236dce677089319176dee5872b5a7a ]
+
+[Why&How]
+Vtotal is not applied to HW when handling vsync interrupt.
+Make sure vtotal is aligned before enable replay.
+
+Reviewed-by: Anthony Koo <anthony.koo@amd.com>
+Reviewed-by: Robin Chen <robin.chen@amd.com>
+Signed-off-by: Danny Wang <danny.wang@amd.com>
+Signed-off-by: Zhongwei Zhang <Zhongwei.Zhang@amd.com>
+Signed-off-by: Tom Chung <chiahsuan.chung@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Stable-dep-of: 874697e12793 ("drm/amd/display: Defer BW-optimization-blocked DRR adjustments")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/core/dc.c | 9 +++++++--
+ .../gpu/drm/amd/display/dc/core/dc_hw_sequencer.c | 15 +++++++++++++++
+ drivers/gpu/drm/amd/display/dc/dc_hw_types.h | 1 +
+ .../drm/amd/display/dc/hwss/dce110/dce110_hwseq.c | 7 ++-----
+ .../drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c | 7 ++-----
+ .../drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c | 8 ++------
+ .../drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c | 4 +---
+ .../drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c | 3 +--
+ .../drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 10 +++-------
+ .../gpu/drm/amd/display/dc/hwss/hw_sequencer.h | 6 ++++++
+ 10 files changed, 40 insertions(+), 30 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
+index 4683c7ef4507f..a444fe1e0838a 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
+@@ -452,6 +452,7 @@ bool dc_stream_adjust_vmin_vmax(struct dc *dc,
+
+ if (dc->caps.max_v_total != 0 &&
+ (adjust->v_total_max > dc->caps.max_v_total || adjust->v_total_min > dc->caps.max_v_total)) {
++ stream->adjust.timing_adjust_pending = false;
+ if (adjust->allow_otg_v_count_halt)
+ return set_long_vtotal(dc, stream, adjust);
+ else
+@@ -465,7 +466,7 @@ bool dc_stream_adjust_vmin_vmax(struct dc *dc,
+ dc->hwss.set_drr(&pipe,
+ 1,
+ *adjust);
+-
++ stream->adjust.timing_adjust_pending = false;
+ return true;
+ }
+ }
+@@ -3127,8 +3128,12 @@ static void copy_stream_update_to_stream(struct dc *dc,
+ if (update->vrr_active_fixed)
+ stream->vrr_active_fixed = *update->vrr_active_fixed;
+
+- if (update->crtc_timing_adjust)
++ if (update->crtc_timing_adjust) {
++ if (stream->adjust.v_total_min != update->crtc_timing_adjust->v_total_min ||
++ stream->adjust.v_total_max != update->crtc_timing_adjust->v_total_max)
++ stream->adjust.timing_adjust_pending = true;
+ stream->adjust = *update->crtc_timing_adjust;
++ }
+
+ if (update->dpms_off)
+ stream->dpms_off = *update->dpms_off;
+diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
+index 6eb9bae3af912..a49604b7701f7 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
+@@ -609,6 +609,21 @@ void set_p_state_switch_method(
+ }
+ }
+
++void set_drr_and_clear_adjust_pending(
++ struct pipe_ctx *pipe_ctx,
++ struct dc_stream_state *stream,
++ struct drr_params *params)
++{
++ /* params can be null.*/
++ if (pipe_ctx && pipe_ctx->stream_res.tg &&
++ pipe_ctx->stream_res.tg->funcs->set_drr)
++ pipe_ctx->stream_res.tg->funcs->set_drr(
++ pipe_ctx->stream_res.tg, params);
++
++ if (stream)
++ stream->adjust.timing_adjust_pending = false;
++}
++
+ void get_fams2_visual_confirm_color(
+ struct dc *dc,
+ struct dc_state *context,
+diff --git a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h
+index 5ac55601a6da1..37e381fc7f02a 100644
+--- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h
++++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h
+@@ -1015,6 +1015,7 @@ struct dc_crtc_timing_adjust {
+ uint32_t v_total_mid;
+ uint32_t v_total_mid_frame_num;
+ uint32_t allow_otg_v_count_halt;
++ uint8_t timing_adjust_pending;
+ };
+
+
+diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
+index 81f4c386c2875..fc4fb4055ab00 100644
+--- a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
++++ b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
+@@ -1654,9 +1654,7 @@ enum dc_status dce110_apply_single_controller_ctx_to_hw(
+
+ params.vertical_total_min = stream->adjust.v_total_min;
+ params.vertical_total_max = stream->adjust.v_total_max;
+- if (pipe_ctx->stream_res.tg->funcs->set_drr)
+- pipe_ctx->stream_res.tg->funcs->set_drr(
+- pipe_ctx->stream_res.tg, ¶ms);
++ set_drr_and_clear_adjust_pending(pipe_ctx, stream, ¶ms);
+
+ // DRR should set trigger event to monitor surface update event
+ if (stream->adjust.v_total_min != 0 && stream->adjust.v_total_max != 0)
+@@ -2104,8 +2102,7 @@ static void set_drr(struct pipe_ctx **pipe_ctx,
+ struct timing_generator *tg = pipe_ctx[i]->stream_res.tg;
+
+ if ((tg != NULL) && tg->funcs) {
+- if (tg->funcs->set_drr)
+- tg->funcs->set_drr(tg, ¶ms);
++ set_drr_and_clear_adjust_pending(pipe_ctx[i], pipe_ctx[i]->stream, ¶ms);
+ if (adjust.v_total_max != 0 && adjust.v_total_min != 0)
+ if (tg->funcs->set_static_screen_control)
+ tg->funcs->set_static_screen_control(
+diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
+index 13f9e9b439f6a..4c89bf6725b3b 100644
+--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
+@@ -1112,9 +1112,7 @@ static void dcn10_reset_back_end_for_pipe(
+ pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg);
+
+ pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false);
+- if (pipe_ctx->stream_res.tg->funcs->set_drr)
+- pipe_ctx->stream_res.tg->funcs->set_drr(
+- pipe_ctx->stream_res.tg, NULL);
++ set_drr_and_clear_adjust_pending(pipe_ctx, pipe_ctx->stream, NULL);
+ if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal))
+ pipe_ctx->stream->link->phy_state.symclk_ref_cnts.otg = 0;
+ }
+@@ -3217,8 +3215,7 @@ void dcn10_set_drr(struct pipe_ctx **pipe_ctx,
+ struct timing_generator *tg = pipe_ctx[i]->stream_res.tg;
+
+ if ((tg != NULL) && tg->funcs) {
+- if (tg->funcs->set_drr)
+- tg->funcs->set_drr(tg, ¶ms);
++ set_drr_and_clear_adjust_pending(pipe_ctx[i], pipe_ctx[i]->stream, ¶ms);
+ if (adjust.v_total_max != 0 && adjust.v_total_min != 0)
+ if (tg->funcs->set_static_screen_control)
+ tg->funcs->set_static_screen_control(
+diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
+index b78096a7690ee..f7e31aec32058 100644
+--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
+@@ -952,9 +952,7 @@ enum dc_status dcn20_enable_stream_timing(
+ params.vertical_total_max = stream->adjust.v_total_max;
+ params.vertical_total_mid = stream->adjust.v_total_mid;
+ params.vertical_total_mid_frame_num = stream->adjust.v_total_mid_frame_num;
+- if (pipe_ctx->stream_res.tg->funcs->set_drr)
+- pipe_ctx->stream_res.tg->funcs->set_drr(
+- pipe_ctx->stream_res.tg, ¶ms);
++ set_drr_and_clear_adjust_pending(pipe_ctx, stream, ¶ms);
+
+ // DRR should set trigger event to monitor surface update event
+ if (stream->adjust.v_total_min != 0 && stream->adjust.v_total_max != 0)
+@@ -2849,9 +2847,7 @@ void dcn20_reset_back_end_for_pipe(
+ pipe_ctx->stream_res.tg->funcs->set_odm_bypass(
+ pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
+
+- if (pipe_ctx->stream_res.tg->funcs->set_drr)
+- pipe_ctx->stream_res.tg->funcs->set_drr(
+- pipe_ctx->stream_res.tg, NULL);
++ set_drr_and_clear_adjust_pending(pipe_ctx, pipe_ctx->stream, NULL);
+ /* TODO - convert symclk_ref_cnts for otg to a bit map to solve
+ * the case where the same symclk is shared across multiple otg
+ * instances
+diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c
+index 03ba01f4ace18..38f8898266971 100644
+--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c
++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c
+@@ -538,9 +538,7 @@ static void dcn31_reset_back_end_for_pipe(
+ if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal))
+ pipe_ctx->stream->link->phy_state.symclk_ref_cnts.otg = 0;
+
+- if (pipe_ctx->stream_res.tg->funcs->set_drr)
+- pipe_ctx->stream_res.tg->funcs->set_drr(
+- pipe_ctx->stream_res.tg, NULL);
++ set_drr_and_clear_adjust_pending(pipe_ctx, pipe_ctx->stream, NULL);
+
+ /* DPMS may already disable or */
+ /* dpms_off status is incorrect due to fastboot
+diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c
+index b907ad1acedd9..922b8d71cf1aa 100644
+--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c
++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c
+@@ -1473,8 +1473,7 @@ void dcn35_set_drr(struct pipe_ctx **pipe_ctx,
+ num_frames = 2 * (frame_rate % 60);
+ }
+ }
+- if (tg->funcs->set_drr)
+- tg->funcs->set_drr(tg, ¶ms);
++ set_drr_and_clear_adjust_pending(pipe_ctx[i], pipe_ctx[i]->stream, ¶ms);
+ if (adjust.v_total_max != 0 && adjust.v_total_min != 0)
+ if (tg->funcs->set_static_screen_control)
+ tg->funcs->set_static_screen_control(
+diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
+index 0d39d193dacfa..284f011f5643d 100644
+--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
+@@ -830,10 +830,7 @@ enum dc_status dcn401_enable_stream_timing(
+ }
+
+ hws->funcs.wait_for_blank_complete(pipe_ctx->stream_res.opp);
+-
+- if (pipe_ctx->stream_res.tg->funcs->set_drr)
+- pipe_ctx->stream_res.tg->funcs->set_drr(
+- pipe_ctx->stream_res.tg, ¶ms);
++ set_drr_and_clear_adjust_pending(pipe_ctx, stream, ¶ms);
+
+ /* Event triggers and num frames initialized for DRR, but can be
+ * later updated for PSR use. Note DRR trigger events are generated
+@@ -1866,9 +1863,8 @@ void dcn401_reset_back_end_for_pipe(
+ pipe_ctx->stream_res.tg->funcs->set_odm_bypass(
+ pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
+
+- if (pipe_ctx->stream_res.tg->funcs->set_drr)
+- pipe_ctx->stream_res.tg->funcs->set_drr(
+- pipe_ctx->stream_res.tg, NULL);
++ set_drr_and_clear_adjust_pending(pipe_ctx, pipe_ctx->stream, NULL);
++
+ /* TODO - convert symclk_ref_cnts for otg to a bit map to solve
+ * the case where the same symclk is shared across multiple otg
+ * instances
+diff --git a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
+index a7d66cfd93c91..16ef5250a02e1 100644
+--- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
++++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
+@@ -46,6 +46,7 @@ struct dce_hwseq;
+ struct link_resource;
+ struct dc_dmub_cmd;
+ struct pg_block_update;
++struct drr_params;
+
+ struct subvp_pipe_control_lock_fast_params {
+ struct dc *dc;
+@@ -521,6 +522,11 @@ void set_p_state_switch_method(
+ struct dc_state *context,
+ struct pipe_ctx *pipe_ctx);
+
++void set_drr_and_clear_adjust_pending(
++ struct pipe_ctx *pipe_ctx,
++ struct dc_stream_state *stream,
++ struct drr_params *params);
++
+ void hwss_execute_sequence(struct dc *dc,
+ struct block_sequence block_sequence[],
+ int num_steps);
+--
+2.39.5
+
--- /dev/null
+From 0fe2bcb1865c43204c544de9abbd48748202f703 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jan 2025 11:57:49 -0500
+Subject: drm/amd/display: Don't treat wb connector as physical in
+ create_validate_stream_for_sink
+
+From: Harry Wentland <harry.wentland@amd.com>
+
+[ Upstream commit cbf4890c6f28fb1ad733e14613fbd33c2004bced ]
+
+Don't try to operate on a drm_wb_connector as an amdgpu_dm_connector.
+While dereferencing aconnector->base will "work" it's wrong and
+might lead to unknown bad things. Just... don't.
+
+Reviewed-by: Alex Hung <alex.hung@amd.com>
+Signed-off-by: Harry Wentland <harry.wentland@amd.com>
+Signed-off-by: Roman Li <roman.li@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 26 ++++++++++++-------
+ .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 2 +-
+ .../display/amdgpu_dm/amdgpu_dm_mst_types.c | 6 ++---
+ 3 files changed, 20 insertions(+), 14 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 6c2d79d84feec..2cfc18401f3f2 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+@@ -7493,12 +7493,12 @@ static enum dc_status dm_validate_stream_and_context(struct dc *dc,
+ }
+
+ struct dc_stream_state *
+-create_validate_stream_for_sink(struct amdgpu_dm_connector *aconnector,
++create_validate_stream_for_sink(struct drm_connector *connector,
+ const struct drm_display_mode *drm_mode,
+ const struct dm_connector_state *dm_state,
+ const struct dc_stream_state *old_stream)
+ {
+- struct drm_connector *connector = &aconnector->base;
++ struct amdgpu_dm_connector *aconnector = NULL;
+ struct amdgpu_device *adev = drm_to_adev(connector->dev);
+ struct dc_stream_state *stream;
+ const struct drm_connector_state *drm_state = dm_state ? &dm_state->base : NULL;
+@@ -7509,8 +7509,12 @@ create_validate_stream_for_sink(struct amdgpu_dm_connector *aconnector,
+ if (!dm_state)
+ return NULL;
+
+- if (aconnector->dc_link->connector_signal == SIGNAL_TYPE_HDMI_TYPE_A ||
+- aconnector->dc_link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER)
++ if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK)
++ aconnector = to_amdgpu_dm_connector(connector);
++
++ if (aconnector &&
++ (aconnector->dc_link->connector_signal == SIGNAL_TYPE_HDMI_TYPE_A ||
++ aconnector->dc_link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER))
+ bpc_limit = 8;
+
+ do {
+@@ -7522,10 +7526,11 @@ create_validate_stream_for_sink(struct amdgpu_dm_connector *aconnector,
+ break;
+ }
+
+- if (aconnector->base.connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
++ dc_result = dc_validate_stream(adev->dm.dc, stream);
++
++ if (!aconnector) /* writeback connector */
+ return stream;
+
+- dc_result = dc_validate_stream(adev->dm.dc, stream);
+ if (dc_result == DC_OK && stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
+ dc_result = dm_dp_mst_is_port_support_mode(aconnector, stream);
+
+@@ -7555,7 +7560,7 @@ create_validate_stream_for_sink(struct amdgpu_dm_connector *aconnector,
+ __func__, __LINE__);
+
+ aconnector->force_yuv420_output = true;
+- stream = create_validate_stream_for_sink(aconnector, drm_mode,
++ stream = create_validate_stream_for_sink(connector, drm_mode,
+ dm_state, old_stream);
+ aconnector->force_yuv420_output = false;
+ }
+@@ -7570,6 +7575,9 @@ enum drm_mode_status amdgpu_dm_connector_mode_valid(struct drm_connector *connec
+ struct dc_sink *dc_sink;
+ /* TODO: Unhardcode stream count */
+ struct dc_stream_state *stream;
++ /* we always have an amdgpu_dm_connector here since we got
++ * here via the amdgpu_dm_connector_helper_funcs
++ */
+ struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
+
+ if ((mode->flags & DRM_MODE_FLAG_INTERLACE) ||
+@@ -7594,7 +7602,7 @@ enum drm_mode_status amdgpu_dm_connector_mode_valid(struct drm_connector *connec
+
+ drm_mode_set_crtcinfo(mode, 0);
+
+- stream = create_validate_stream_for_sink(aconnector, mode,
++ stream = create_validate_stream_for_sink(connector, mode,
+ to_dm_connector_state(connector->state),
+ NULL);
+ if (stream) {
+@@ -10646,7 +10654,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
+ if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
+ goto skip_modeset;
+
+- new_stream = create_validate_stream_for_sink(aconnector,
++ new_stream = create_validate_stream_for_sink(connector,
+ &new_crtc_state->mode,
+ dm_new_conn_state,
+ dm_old_crtc_state->stream);
+diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+index d2703ca7dff31..195fec9048df7 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+@@ -989,7 +989,7 @@ int amdgpu_dm_process_dmub_set_config_sync(struct dc_context *ctx, unsigned int
+ struct set_config_cmd_payload *payload, enum set_config_status *operation_result);
+
+ struct dc_stream_state *
+- create_validate_stream_for_sink(struct amdgpu_dm_connector *aconnector,
++ create_validate_stream_for_sink(struct drm_connector *connector,
+ const struct drm_display_mode *drm_mode,
+ const struct dm_connector_state *dm_state,
+ const struct dc_stream_state *old_stream);
+diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+index 8497de360640a..c3759a1c32cec 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+@@ -1651,7 +1651,6 @@ int pre_validate_dsc(struct drm_atomic_state *state,
+
+ if (ind >= 0) {
+ struct drm_connector *connector;
+- struct amdgpu_dm_connector *aconnector;
+ struct drm_connector_state *drm_new_conn_state;
+ struct dm_connector_state *dm_new_conn_state;
+ struct dm_crtc_state *dm_old_crtc_state;
+@@ -1659,15 +1658,14 @@ int pre_validate_dsc(struct drm_atomic_state *state,
+ connector =
+ amdgpu_dm_find_first_crtc_matching_connector(state,
+ state->crtcs[ind].ptr);
+- aconnector = to_amdgpu_dm_connector(connector);
+ drm_new_conn_state =
+ drm_atomic_get_new_connector_state(state,
+- &aconnector->base);
++ connector);
+ dm_new_conn_state = to_dm_connector_state(drm_new_conn_state);
+ dm_old_crtc_state = to_dm_crtc_state(state->crtcs[ind].old_state);
+
+ local_dc_state->streams[i] =
+- create_validate_stream_for_sink(aconnector,
++ create_validate_stream_for_sink(connector,
+ &state->crtcs[ind].new_state->mode,
+ dm_new_conn_state,
+ dm_old_crtc_state->stream);
+--
+2.39.5
+
--- /dev/null
+From 815ab561e01ab2d2f041463ecd8368ff0bed1981 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jan 2025 13:14:54 -0500
+Subject: drm/amd/display: Don't try AUX transactions on disconnected link
+
+From: Ilya Bakoulin <Ilya.Bakoulin@amd.com>
+
+[ Upstream commit e8bffa52e0253cfd689813a620e64521256bc712 ]
+
+[Why]
+Setting link DPMS off in response to HPD disconnect creates AUX
+transactions on a link that is supposed to be disconnected. This can
+cause issues in some cases when the sink re-asserts HPD and expects
+source to re-enable the link.
+
+[How]
+Avoid AUX transactions on disconnected link.
+
+Reviewed-by: Wenjing Liu <wenjing.liu@amd.com>
+Signed-off-by: Ilya Bakoulin <Ilya.Bakoulin@amd.com>
+Signed-off-by: Aurabindo Pillai <aurabindo.pillai@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../gpu/drm/amd/display/dc/link/protocols/link_dp_phy.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.c
+index 2c73ac87cd665..c27ffec5d84fb 100644
+--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.c
++++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.c
+@@ -75,7 +75,8 @@ void dp_disable_link_phy(struct dc_link *link,
+ struct dc *dc = link->ctx->dc;
+
+ if (!link->wa_flags.dp_keep_receiver_powered &&
+- !link->skip_implict_edp_power_control)
++ !link->skip_implict_edp_power_control &&
++ link->type != dc_connection_none)
+ dpcd_write_rx_power_ctrl(link, false);
+
+ dc->hwss.disable_link_output(link, link_res, signal);
+@@ -163,8 +164,9 @@ enum dc_status dp_set_fec_ready(struct dc_link *link, const struct link_resource
+ } else {
+ if (link->fec_state == dc_link_fec_ready) {
+ fec_config = 0;
+- core_link_write_dpcd(link, DP_FEC_CONFIGURATION,
+- &fec_config, sizeof(fec_config));
++ if (link->type != dc_connection_none)
++ core_link_write_dpcd(link, DP_FEC_CONFIGURATION,
++ &fec_config, sizeof(fec_config));
+
+ link_enc->funcs->fec_set_ready(link_enc, false);
+ link->fec_state = dc_link_fec_not_ready;
+--
+2.39.5
+
--- /dev/null
+From ca009a4dc1772871e4070f32b3ace70f8ea189ea Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 2 Apr 2025 15:04:08 -0400
+Subject: drm/amd/display: Enable urgent latency adjustment on DCN35
+
+From: Nicholas Susanto <nsusanto@amd.com>
+
+[ Upstream commit 756c85e4d0ddc497b4ad5b1f41ad54e838e06188 ]
+
+[Why]
+
+Urgent latency adjustment was disabled on DCN35 due to issues with P0
+enablement on some platforms. Without urgent latency, underflows occur
+when doing certain high timing configurations. After testing, we found
+that reenabling urgent latency didn't reintroduce p0 support on multiple
+platforms.
+
+[How]
+
+renable urgent latency on DCN35 and setting it to 3000 Mhz.
+
+This reverts commit 3412860cc4c0c484f53f91b371483e6e4440c3e5.
+
+Reviewed-by: Charlene Liu <charlene.liu@amd.com>
+Signed-off-by: Nicholas Susanto <nsusanto@amd.com>
+Signed-off-by: Zaeem Mohamed <zaeem.mohamed@amd.com>
+Tested-by: Mark Broadworth <mark.broadworth@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+(cherry picked from commit cd74ce1f0cddffb3f36d0995d0f61e89f0010738)
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c
+index 47d785204f29c..beed7adbbd43e 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c
++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c
+@@ -195,9 +195,9 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_5_soc = {
+ .dcn_downspread_percent = 0.5,
+ .gpuvm_min_page_size_bytes = 4096,
+ .hostvm_min_page_size_bytes = 4096,
+- .do_urgent_latency_adjustment = 0,
++ .do_urgent_latency_adjustment = 1,
+ .urgent_latency_adjustment_fabric_clock_component_us = 0,
+- .urgent_latency_adjustment_fabric_clock_reference_mhz = 0,
++ .urgent_latency_adjustment_fabric_clock_reference_mhz = 3000,
+ };
+
+ void dcn35_build_wm_range_table_fpu(struct clk_mgr *clk_mgr)
+--
+2.39.5
+
--- /dev/null
+From bd2b1ba18e79049e3370e8f33d645d092172f9ab Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 19 Feb 2025 09:56:53 -0500
+Subject: drm/amd/display: Ensure DMCUB idle before reset on DCN31/DCN35
+
+From: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
+
+[ Upstream commit c707ea82c79dbd1d295ec94cc6529a5248c77757 ]
+
+[Why]
+If we soft reset before halt finishes and there are outstanding
+memory transactions then the memory interface may produce unexpected
+results, such as out of order transactions when the firmware next runs.
+
+These can manifest as random or unexpected load/store violations.
+
+[How]
+Increase the timeout before soft reset to ensure the DMCUB has quiesced.
+This is effectively 1s maximum based on experimentation.
+
+Use the enable bit check on DCN31 like we're doing on DCN35 and reorder
+the reset writes to follow the HW programming guide.
+
+Ensure we're reading SCRATCH7 instead of SCRATCH8 for the HALT code.
+No current versions of DMCUB firmware use the SCRATCH8 boot bit to
+dynamically switch where the HALT code goes to maintain backwards
+compatibility with PSP.
+
+Reviewed-by: Dillon Varone <dillon.varone@amd.com>
+Signed-off-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
+Signed-off-by: Wayne Lin <wayne.lin@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../gpu/drm/amd/display/dmub/src/dmub_dcn31.c | 17 +++++++++++------
+ .../gpu/drm/amd/display/dmub/src/dmub_dcn35.c | 4 ++--
+ 2 files changed, 13 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c
+index d9f31b191c693..1a68b5782cac6 100644
+--- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c
++++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c
+@@ -83,8 +83,8 @@ static inline void dmub_dcn31_translate_addr(const union dmub_addr *addr_in,
+ void dmub_dcn31_reset(struct dmub_srv *dmub)
+ {
+ union dmub_gpint_data_register cmd;
+- const uint32_t timeout = 100;
+- uint32_t in_reset, scratch, i, pwait_mode;
++ const uint32_t timeout = 100000;
++ uint32_t in_reset, is_enabled, scratch, i, pwait_mode;
+
+ REG_GET(DMCUB_CNTL2, DMCUB_SOFT_RESET, &in_reset);
+
+@@ -108,7 +108,7 @@ void dmub_dcn31_reset(struct dmub_srv *dmub)
+ }
+
+ for (i = 0; i < timeout; ++i) {
+- scratch = dmub->hw_funcs.get_gpint_response(dmub);
++ scratch = REG_READ(DMCUB_SCRATCH7);
+ if (scratch == DMUB_GPINT__STOP_FW_RESPONSE)
+ break;
+
+@@ -125,9 +125,14 @@ void dmub_dcn31_reset(struct dmub_srv *dmub)
+ /* Force reset in case we timed out, DMCUB is likely hung. */
+ }
+
+- REG_UPDATE(DMCUB_CNTL2, DMCUB_SOFT_RESET, 1);
+- REG_UPDATE(DMCUB_CNTL, DMCUB_ENABLE, 0);
+- REG_UPDATE(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET, 1);
++ REG_GET(DMCUB_CNTL, DMCUB_ENABLE, &is_enabled);
++
++ if (is_enabled) {
++ REG_UPDATE(DMCUB_CNTL2, DMCUB_SOFT_RESET, 1);
++ REG_UPDATE(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET, 1);
++ REG_UPDATE(DMCUB_CNTL, DMCUB_ENABLE, 0);
++ }
++
+ REG_WRITE(DMCUB_INBOX1_RPTR, 0);
+ REG_WRITE(DMCUB_INBOX1_WPTR, 0);
+ REG_WRITE(DMCUB_OUTBOX1_RPTR, 0);
+diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn35.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn35.c
+index e5e77bd3c31ea..01d013a12b947 100644
+--- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn35.c
++++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn35.c
+@@ -88,7 +88,7 @@ static inline void dmub_dcn35_translate_addr(const union dmub_addr *addr_in,
+ void dmub_dcn35_reset(struct dmub_srv *dmub)
+ {
+ union dmub_gpint_data_register cmd;
+- const uint32_t timeout = 100;
++ const uint32_t timeout = 100000;
+ uint32_t in_reset, is_enabled, scratch, i, pwait_mode;
+
+ REG_GET(DMCUB_CNTL2, DMCUB_SOFT_RESET, &in_reset);
+@@ -113,7 +113,7 @@ void dmub_dcn35_reset(struct dmub_srv *dmub)
+ }
+
+ for (i = 0; i < timeout; ++i) {
+- scratch = dmub->hw_funcs.get_gpint_response(dmub);
++ scratch = REG_READ(DMCUB_SCRATCH7);
+ if (scratch == DMUB_GPINT__STOP_FW_RESPONSE)
+ break;
+
+--
+2.39.5
+
--- /dev/null
+From 7aad5e91d1c74e86b276a66ec45ea297aea27e6c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Feb 2025 15:43:32 -0500
+Subject: drm/amd/display: Exit idle optimizations before accessing PHY
+
+From: Ovidiu Bunea <Ovidiu.Bunea@amd.com>
+
+[ Upstream commit c488967488d7eff7b9c527d5469c424c15377502 ]
+
+[why & how]
+By default, DCN HW is in idle optimized state which does not allow access
+to PHY registers. If BIOS powers up the DCN, it is fine because they will
+power up everything. Only exit idle optimized state when not taking control
+from VBIOS.
+
+Fixes: be704e5ef4bd ("Revert "drm/amd/display: Exit idle optimizations before attempt to access PHY"")
+Reviewed-by: Charlene Liu <charlene.liu@amd.com>
+Signed-off-by: Ovidiu Bunea <Ovidiu.Bunea@amd.com>
+Signed-off-by: Roman Li <roman.li@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
+index 2f5f3e749a1ab..94ceccfc04982 100644
+--- a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
++++ b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
+@@ -1889,6 +1889,7 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context)
+ bool can_apply_edp_fast_boot = false;
+ bool can_apply_seamless_boot = false;
+ bool keep_edp_vdd_on = false;
++ struct dc_bios *dcb = dc->ctx->dc_bios;
+ DC_LOGGER_INIT();
+
+
+@@ -1965,6 +1966,8 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context)
+ hws->funcs.edp_backlight_control(edp_link_with_sink, false);
+ }
+ /*resume from S3, no vbios posting, no need to power down again*/
++ if (dcb && dcb->funcs && !dcb->funcs->is_accelerated_mode(dcb))
++ clk_mgr_exit_optimized_pwr_state(dc, dc->clk_mgr);
+
+ power_down_all_hw_blocks(dc);
+
+@@ -1977,6 +1980,8 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context)
+ disable_vga_and_power_gate_all_controllers(dc);
+ if (edp_link_with_sink && !keep_edp_vdd_on)
+ dc->hwss.edp_power_control(edp_link_with_sink, false);
++ if (dcb && dcb->funcs && !dcb->funcs->is_accelerated_mode(dcb))
++ clk_mgr_optimize_pwr_state(dc, dc->clk_mgr);
+ }
+ bios_set_scratch_acc_mode_change(dc->ctx->dc_bios, 1);
+ }
+--
+2.39.5
+
--- /dev/null
+From 9b9709ac0ccc04f1f151059996db88fd7f15cd5a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jan 2025 14:46:27 -0500
+Subject: drm/amd/display: Fix BT2020 YCbCr limited/full range input
+
+From: Ilya Bakoulin <Ilya.Bakoulin@amd.com>
+
+[ Upstream commit 07bc2dcbcf403d47d6f305ef7f0d3d489491c5fb ]
+
+[Why]
+BT2020 YCbCr input is not handled properly when full range
+quantization is used and limited range is not supported at all.
+
+[How]
+- Add enums for BT2020 YCbCr limited/full range
+- Add limited range CSC matrix
+
+Reviewed-by: Krunoslav Kovac <krunoslav.kovac@amd.com>
+Signed-off-by: Ilya Bakoulin <Ilya.Bakoulin@amd.com>
+Signed-off-by: Roman Li <roman.li@amd.com>
+Tested-by: Robert Mader <robert.mader@collabora.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 6 +++---
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 2 +-
+ drivers/gpu/drm/amd/display/dc/basics/dc_common.c | 3 ++-
+ drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c | 5 +++--
+ drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 4 ++--
+ drivers/gpu/drm/amd/display/dc/dc_hw_types.h | 4 +++-
+ drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c | 3 ++-
+ .../gpu/drm/amd/display/dc/dio/dcn10/dcn10_stream_encoder.c | 3 ++-
+ .../amd/display/dc/dio/dcn401/dcn401_dio_stream_encoder.c | 3 ++-
+ .../amd/display/dc/hpo/dcn31/dcn31_hpo_dp_stream_encoder.c | 3 ++-
+ drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h | 6 +++++-
+ .../gpu/drm/amd/display/modules/info_packet/info_packet.c | 4 ++--
+ 12 files changed, 29 insertions(+), 17 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 ee79a54de6d19..6c2d79d84feec 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+@@ -5650,9 +5650,9 @@ fill_plane_color_attributes(const struct drm_plane_state *plane_state,
+
+ case DRM_COLOR_YCBCR_BT2020:
+ if (full_range)
+- *color_space = COLOR_SPACE_2020_YCBCR;
++ *color_space = COLOR_SPACE_2020_YCBCR_FULL;
+ else
+- return -EINVAL;
++ *color_space = COLOR_SPACE_2020_YCBCR_LIMITED;
+ break;
+
+ default:
+@@ -6148,7 +6148,7 @@ get_output_color_space(const struct dc_crtc_timing *dc_crtc_timing,
+ if (dc_crtc_timing->pixel_encoding == PIXEL_ENCODING_RGB)
+ color_space = COLOR_SPACE_2020_RGB_FULLRANGE;
+ else
+- color_space = COLOR_SPACE_2020_YCBCR;
++ color_space = COLOR_SPACE_2020_YCBCR_LIMITED;
+ break;
+ case DRM_MODE_COLORIMETRY_DEFAULT: // ITU601
+ default:
+diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
+index 049046c604626..c7d13e743e6c8 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
+@@ -1169,7 +1169,7 @@ static int amdgpu_current_colorspace_show(struct seq_file *m, void *data)
+ case COLOR_SPACE_2020_RGB_FULLRANGE:
+ seq_puts(m, "BT2020_RGB");
+ break;
+- case COLOR_SPACE_2020_YCBCR:
++ case COLOR_SPACE_2020_YCBCR_LIMITED:
+ seq_puts(m, "BT2020_YCC");
+ break;
+ default:
+diff --git a/drivers/gpu/drm/amd/display/dc/basics/dc_common.c b/drivers/gpu/drm/amd/display/dc/basics/dc_common.c
+index b2fc4f8e64825..a51c2701da247 100644
+--- a/drivers/gpu/drm/amd/display/dc/basics/dc_common.c
++++ b/drivers/gpu/drm/amd/display/dc/basics/dc_common.c
+@@ -40,7 +40,8 @@ bool is_rgb_cspace(enum dc_color_space output_color_space)
+ case COLOR_SPACE_YCBCR709:
+ case COLOR_SPACE_YCBCR601_LIMITED:
+ case COLOR_SPACE_YCBCR709_LIMITED:
+- case COLOR_SPACE_2020_YCBCR:
++ case COLOR_SPACE_2020_YCBCR_LIMITED:
++ case COLOR_SPACE_2020_YCBCR_FULL:
+ return false;
+ default:
+ /* Add a case to switch */
+diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
+index 1406ee4bff801..4f54e75a8f95b 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
+@@ -176,7 +176,7 @@ static bool is_ycbcr2020_type(
+ {
+ bool ret = false;
+
+- if (color_space == COLOR_SPACE_2020_YCBCR)
++ if (color_space == COLOR_SPACE_2020_YCBCR_LIMITED || color_space == COLOR_SPACE_2020_YCBCR_FULL)
+ ret = true;
+ return ret;
+ }
+@@ -247,7 +247,8 @@ void color_space_to_black_color(
+ case COLOR_SPACE_YCBCR709_BLACK:
+ case COLOR_SPACE_YCBCR601_LIMITED:
+ case COLOR_SPACE_YCBCR709_LIMITED:
+- case COLOR_SPACE_2020_YCBCR:
++ case COLOR_SPACE_2020_YCBCR_LIMITED:
++ case COLOR_SPACE_2020_YCBCR_FULL:
+ *black_color = black_color_format[BLACK_COLOR_FORMAT_YUV_CV];
+ break;
+
+diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+index 298668e9729c7..3367030da3414 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+@@ -4247,7 +4247,7 @@ static void set_avi_info_frame(
+ break;
+ case COLOR_SPACE_2020_RGB_FULLRANGE:
+ case COLOR_SPACE_2020_RGB_LIMITEDRANGE:
+- case COLOR_SPACE_2020_YCBCR:
++ case COLOR_SPACE_2020_YCBCR_LIMITED:
+ hdmi_info.bits.EC0_EC2 = COLORIMETRYEX_BT2020RGBYCBCR;
+ hdmi_info.bits.C0_C1 = COLORIMETRY_EXTENDED;
+ break;
+@@ -4261,7 +4261,7 @@ static void set_avi_info_frame(
+ break;
+ }
+
+- if (pixel_encoding && color_space == COLOR_SPACE_2020_YCBCR &&
++ if (pixel_encoding && color_space == COLOR_SPACE_2020_YCBCR_LIMITED &&
+ stream->out_transfer_func.tf == TRANSFER_FUNCTION_GAMMA22) {
+ hdmi_info.bits.EC0_EC2 = 0;
+ hdmi_info.bits.C0_C1 = COLORIMETRY_ITU709;
+diff --git a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h
+index 37e381fc7f02a..d562ddeca5126 100644
+--- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h
++++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h
+@@ -653,7 +653,8 @@ enum dc_color_space {
+ COLOR_SPACE_YCBCR709_LIMITED,
+ COLOR_SPACE_2020_RGB_FULLRANGE,
+ COLOR_SPACE_2020_RGB_LIMITEDRANGE,
+- COLOR_SPACE_2020_YCBCR,
++ COLOR_SPACE_2020_YCBCR_LIMITED,
++ COLOR_SPACE_2020_YCBCR_FULL,
+ COLOR_SPACE_ADOBERGB,
+ COLOR_SPACE_DCIP3,
+ COLOR_SPACE_DISPLAYNATIVE,
+@@ -661,6 +662,7 @@ enum dc_color_space {
+ COLOR_SPACE_APPCTRL,
+ COLOR_SPACE_CUSTOMPOINTS,
+ COLOR_SPACE_YCBCR709_BLACK,
++ COLOR_SPACE_2020_YCBCR = COLOR_SPACE_2020_YCBCR_LIMITED,
+ };
+
+ enum dc_dither_option {
+diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c
+index d199e4ed2e59e..1130d7619b263 100644
+--- a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c
++++ b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c
+@@ -418,7 +418,7 @@ static void dce110_stream_encoder_dp_set_stream_attribute(
+ dynamic_range_rgb = 1; /*limited range*/
+ break;
+ case COLOR_SPACE_2020_RGB_FULLRANGE:
+- case COLOR_SPACE_2020_YCBCR:
++ case COLOR_SPACE_2020_YCBCR_LIMITED:
+ case COLOR_SPACE_XR_RGB:
+ case COLOR_SPACE_MSREF_SCRGB:
+ case COLOR_SPACE_ADOBERGB:
+@@ -430,6 +430,7 @@ static void dce110_stream_encoder_dp_set_stream_attribute(
+ case COLOR_SPACE_APPCTRL:
+ case COLOR_SPACE_CUSTOMPOINTS:
+ case COLOR_SPACE_UNKNOWN:
++ default:
+ /* do nothing */
+ break;
+ }
+diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_stream_encoder.c
+index d01a8b8f95954..22e66b375a7fe 100644
+--- a/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_stream_encoder.c
++++ b/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_stream_encoder.c
+@@ -391,7 +391,7 @@ void enc1_stream_encoder_dp_set_stream_attribute(
+ break;
+ case COLOR_SPACE_2020_RGB_LIMITEDRANGE:
+ case COLOR_SPACE_2020_RGB_FULLRANGE:
+- case COLOR_SPACE_2020_YCBCR:
++ case COLOR_SPACE_2020_YCBCR_LIMITED:
+ case COLOR_SPACE_XR_RGB:
+ case COLOR_SPACE_MSREF_SCRGB:
+ case COLOR_SPACE_ADOBERGB:
+@@ -404,6 +404,7 @@ void enc1_stream_encoder_dp_set_stream_attribute(
+ case COLOR_SPACE_CUSTOMPOINTS:
+ case COLOR_SPACE_UNKNOWN:
+ case COLOR_SPACE_YCBCR709_BLACK:
++ default:
+ /* do nothing */
+ break;
+ }
+diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_stream_encoder.c
+index 098c2a01a8509..9e5072627ec7b 100644
+--- a/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_stream_encoder.c
++++ b/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_stream_encoder.c
+@@ -632,7 +632,7 @@ void enc401_stream_encoder_dp_set_stream_attribute(
+ break;
+ case COLOR_SPACE_2020_RGB_LIMITEDRANGE:
+ case COLOR_SPACE_2020_RGB_FULLRANGE:
+- case COLOR_SPACE_2020_YCBCR:
++ case COLOR_SPACE_2020_YCBCR_LIMITED:
+ case COLOR_SPACE_XR_RGB:
+ case COLOR_SPACE_MSREF_SCRGB:
+ case COLOR_SPACE_ADOBERGB:
+@@ -645,6 +645,7 @@ void enc401_stream_encoder_dp_set_stream_attribute(
+ case COLOR_SPACE_CUSTOMPOINTS:
+ case COLOR_SPACE_UNKNOWN:
+ case COLOR_SPACE_YCBCR709_BLACK:
++ default:
+ /* do nothing */
+ break;
+ }
+diff --git a/drivers/gpu/drm/amd/display/dc/hpo/dcn31/dcn31_hpo_dp_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/hpo/dcn31/dcn31_hpo_dp_stream_encoder.c
+index 678db949cfe3c..759b453385c46 100644
+--- a/drivers/gpu/drm/amd/display/dc/hpo/dcn31/dcn31_hpo_dp_stream_encoder.c
++++ b/drivers/gpu/drm/amd/display/dc/hpo/dcn31/dcn31_hpo_dp_stream_encoder.c
+@@ -323,7 +323,7 @@ static void dcn31_hpo_dp_stream_enc_set_stream_attribute(
+ break;
+ case COLOR_SPACE_2020_RGB_LIMITEDRANGE:
+ case COLOR_SPACE_2020_RGB_FULLRANGE:
+- case COLOR_SPACE_2020_YCBCR:
++ case COLOR_SPACE_2020_YCBCR_LIMITED:
+ case COLOR_SPACE_XR_RGB:
+ case COLOR_SPACE_MSREF_SCRGB:
+ case COLOR_SPACE_ADOBERGB:
+@@ -336,6 +336,7 @@ static void dcn31_hpo_dp_stream_enc_set_stream_attribute(
+ case COLOR_SPACE_CUSTOMPOINTS:
+ case COLOR_SPACE_UNKNOWN:
+ case COLOR_SPACE_YCBCR709_BLACK:
++ default:
+ /* do nothing */
+ break;
+ }
+diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h
+index 0150f2581ee4c..0c5675d1c5936 100644
+--- a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h
++++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h
+@@ -119,10 +119,14 @@ static const struct dpp_input_csc_matrix __maybe_unused dpp_input_csc_matrix[] =
+ { 0x39a6, 0x2568, 0, 0xe0d6,
+ 0xeedd, 0x2568, 0xf925, 0x9a8,
+ 0, 0x2568, 0x43ee, 0xdbb2 } },
+- { COLOR_SPACE_2020_YCBCR,
++ { COLOR_SPACE_2020_YCBCR_FULL,
+ { 0x2F30, 0x2000, 0, 0xE869,
+ 0xEDB7, 0x2000, 0xFABC, 0xBC6,
+ 0, 0x2000, 0x3C34, 0xE1E6 } },
++ { COLOR_SPACE_2020_YCBCR_LIMITED,
++ { 0x35B9, 0x2543, 0, 0xE2B2,
++ 0xEB2F, 0x2543, 0xFA01, 0x0B1F,
++ 0, 0x2543, 0x4489, 0xDB42 } },
+ { COLOR_SPACE_2020_RGB_LIMITEDRANGE,
+ { 0x35E0, 0x255F, 0, 0xE2B3,
+ 0xEB20, 0x255F, 0xF9FD, 0xB1E,
+diff --git a/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c b/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c
+index a344e2e49b0ea..b3d55cac35694 100644
+--- a/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c
++++ b/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c
+@@ -383,10 +383,10 @@ void mod_build_vsc_infopacket(const struct dc_stream_state *stream,
+ colorimetryFormat = ColorimetryYCC_DP_ITU709;
+ else if (cs == COLOR_SPACE_ADOBERGB)
+ colorimetryFormat = ColorimetryYCC_DP_AdobeYCC;
+- else if (cs == COLOR_SPACE_2020_YCBCR)
++ else if (cs == COLOR_SPACE_2020_YCBCR_LIMITED)
+ colorimetryFormat = ColorimetryYCC_DP_ITU2020YCbCr;
+
+- if (cs == COLOR_SPACE_2020_YCBCR && tf == TRANSFER_FUNC_GAMMA_22)
++ if (cs == COLOR_SPACE_2020_YCBCR_LIMITED && tf == TRANSFER_FUNC_GAMMA_22)
+ colorimetryFormat = ColorimetryYCC_DP_ITU709;
+ break;
+
+--
+2.39.5
+
--- /dev/null
+From 8d98296f312c30dc9e0bec43e6ebe8e7f85970b2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 21 Jan 2025 11:01:47 -0500
+Subject: drm/amd/display: fix check for identity ratio
+
+From: Samson Tam <Samson.Tam@amd.com>
+
+[ Upstream commit 0d3004647631aedb713251525a99784661574767 ]
+
+[Why]
+IDENTITY_RATIO check uses 2 bits for integer, which only allows
+ checking downscale ratios up to 3. But we support up to 6x
+ downscale
+
+[How]
+Update IDENTITY_RATIO to check 3 bits for integer
+Add ASSERT to catch if we downscale more than 6x
+
+Signed-off-by: Samson Tam <Samson.Tam@amd.com>
+Reviewed-by: Jun Lei <jun.lei@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/spl/dc_spl.c | 21 ++++++++++++++++++++-
+ 1 file changed, 20 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/spl/dc_spl.c b/drivers/gpu/drm/amd/display/dc/spl/dc_spl.c
+index 38a9a0d680581..18b423bd302a7 100644
+--- a/drivers/gpu/drm/amd/display/dc/spl/dc_spl.c
++++ b/drivers/gpu/drm/amd/display/dc/spl/dc_spl.c
+@@ -8,7 +8,7 @@
+ #include "dc_spl_isharp_filters.h"
+ #include "spl_debug.h"
+
+-#define IDENTITY_RATIO(ratio) (spl_fixpt_u2d19(ratio) == (1 << 19))
++#define IDENTITY_RATIO(ratio) (spl_fixpt_u3d19(ratio) == (1 << 19))
+ #define MIN_VIEWPORT_SIZE 12
+
+ static bool spl_is_yuv420(enum spl_pixel_format format)
+@@ -887,6 +887,8 @@ static bool spl_get_isharp_en(struct spl_in *spl_in,
+ static void spl_get_taps_non_adaptive_scaler(
+ struct spl_scratch *spl_scratch, const struct spl_taps *in_taps)
+ {
++ bool check_max_downscale = false;
++
+ if (in_taps->h_taps == 0) {
+ if (spl_fixpt_ceil(spl_scratch->scl_data.ratios.horz) > 1)
+ spl_scratch->scl_data.taps.h_taps = spl_min(2 * spl_fixpt_ceil(
+@@ -926,6 +928,23 @@ static void spl_get_taps_non_adaptive_scaler(
+ else
+ spl_scratch->scl_data.taps.h_taps_c = in_taps->h_taps_c;
+
++
++ /*
++ * Max downscale supported is 6.0x. Add ASSERT to catch if go beyond that
++ */
++ check_max_downscale = spl_fixpt_le(spl_scratch->scl_data.ratios.horz,
++ spl_fixpt_from_fraction(6, 1));
++ SPL_ASSERT(check_max_downscale);
++ check_max_downscale = spl_fixpt_le(spl_scratch->scl_data.ratios.vert,
++ spl_fixpt_from_fraction(6, 1));
++ SPL_ASSERT(check_max_downscale);
++ check_max_downscale = spl_fixpt_le(spl_scratch->scl_data.ratios.horz_c,
++ spl_fixpt_from_fraction(6, 1));
++ SPL_ASSERT(check_max_downscale);
++ check_max_downscale = spl_fixpt_le(spl_scratch->scl_data.ratios.vert_c,
++ spl_fixpt_from_fraction(6, 1));
++ SPL_ASSERT(check_max_downscale);
++
+ if (IDENTITY_RATIO(spl_scratch->scl_data.ratios.horz))
+ spl_scratch->scl_data.taps.h_taps = 1;
+ if (IDENTITY_RATIO(spl_scratch->scl_data.ratios.vert))
+--
+2.39.5
+
--- /dev/null
+From c9bc317cb096e5afdded29dfb999b1a511ec4a29 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 13 Feb 2025 12:37:10 -0500
+Subject: drm/amd/display: fix dcn4x init failed
+
+From: Charlene Liu <Charlene.Liu@amd.com>
+
+[ Upstream commit 23ef388a84c72b0614a6c10f866ffeac7e807719 ]
+
+[why]
+failed due to cmdtable not created.
+switch atombios cmdtable as default.
+
+Reviewed-by: Alvin Lee <alvin.lee2@amd.com>
+Signed-off-by: Charlene Liu <Charlene.Liu@amd.com>
+Signed-off-by: Zaeem Mohamed <zaeem.mohamed@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/bios/command_table2.c | 9 ---------
+ .../gpu/drm/amd/display/dc/bios/command_table_helper2.c | 3 +--
+ 2 files changed, 1 insertion(+), 11 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c
+index 7d18f372ce7ab..6bc59b7ef007b 100644
+--- a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c
++++ b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c
+@@ -101,7 +101,6 @@ static void init_dig_encoder_control(struct bios_parser *bp)
+ bp->cmd_tbl.dig_encoder_control = encoder_control_digx_v1_5;
+ break;
+ default:
+- dm_output_to_console("Don't have dig_encoder_control for v%d\n", version);
+ bp->cmd_tbl.dig_encoder_control = encoder_control_fallback;
+ break;
+ }
+@@ -238,7 +237,6 @@ static void init_transmitter_control(struct bios_parser *bp)
+ bp->cmd_tbl.transmitter_control = transmitter_control_v1_7;
+ break;
+ default:
+- dm_output_to_console("Don't have transmitter_control for v%d\n", crev);
+ bp->cmd_tbl.transmitter_control = transmitter_control_fallback;
+ break;
+ }
+@@ -408,8 +406,6 @@ static void init_set_pixel_clock(struct bios_parser *bp)
+ bp->cmd_tbl.set_pixel_clock = set_pixel_clock_v7;
+ break;
+ default:
+- dm_output_to_console("Don't have set_pixel_clock for v%d\n",
+- BIOS_CMD_TABLE_PARA_REVISION(setpixelclock));
+ bp->cmd_tbl.set_pixel_clock = set_pixel_clock_fallback;
+ break;
+ }
+@@ -554,7 +550,6 @@ static void init_set_crtc_timing(struct bios_parser *bp)
+ set_crtc_using_dtd_timing_v3;
+ break;
+ default:
+- dm_output_to_console("Don't have set_crtc_timing for v%d\n", dtd_version);
+ bp->cmd_tbl.set_crtc_timing = NULL;
+ break;
+ }
+@@ -671,8 +666,6 @@ static void init_enable_crtc(struct bios_parser *bp)
+ bp->cmd_tbl.enable_crtc = enable_crtc_v1;
+ break;
+ default:
+- dm_output_to_console("Don't have enable_crtc for v%d\n",
+- BIOS_CMD_TABLE_PARA_REVISION(enablecrtc));
+ bp->cmd_tbl.enable_crtc = NULL;
+ break;
+ }
+@@ -864,8 +857,6 @@ static void init_set_dce_clock(struct bios_parser *bp)
+ bp->cmd_tbl.set_dce_clock = set_dce_clock_v2_1;
+ break;
+ default:
+- dm_output_to_console("Don't have set_dce_clock for v%d\n",
+- BIOS_CMD_TABLE_PARA_REVISION(setdceclock));
+ bp->cmd_tbl.set_dce_clock = NULL;
+ break;
+ }
+diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c
+index 73458e2951034..df8139bda142b 100644
+--- a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c
++++ b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c
+@@ -87,8 +87,7 @@ bool dal_bios_parser_init_cmd_tbl_helper2(
+ return true;
+
+ default:
+- /* Unsupported DCE */
+- BREAK_TO_DEBUGGER();
++ *h = dal_cmd_tbl_helper_dce112_get_table2();
+ return false;
+ }
+ }
+--
+2.39.5
+
--- /dev/null
+From 63c76a7de44b53e943219bf8211eba3860f961d7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 13 Feb 2025 13:10:41 -0500
+Subject: drm/amd/display: Fix DMUB reset sequence for DCN401
+
+From: Dillon Varone <Dillon.Varone@amd.com>
+
+[ Upstream commit 0dfcc2bf269010a6e093793034c048049a40ee93 ]
+
+[WHY]
+It should no longer use DMCUB_SOFT_RESET as it can result
+in the memory request path becoming desynchronized.
+
+[HOW]
+To ensure robustness in the reset sequence:
+1) Extend timeout on the "halt" command sent via gpint, and check for
+controller to enter "wait" as a stronger guarantee that there are no
+requests to memory still in flight.
+2) Remove usage of DMCUB_SOFT_RESET
+3) Rely on PSP to reset the controller safely
+
+Reviewed-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
+Signed-off-by: Dillon Varone <Dillon.Varone@amd.com>
+Signed-off-by: Wayne Lin <wayne.lin@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../drm/amd/display/dmub/src/dmub_dcn401.c | 47 ++++++++++++-------
+ .../drm/amd/display/dmub/src/dmub_dcn401.h | 3 +-
+ 2 files changed, 32 insertions(+), 18 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.c
+index 39a8cb6d7523c..e1c4fe1c6e3ee 100644
+--- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.c
++++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.c
+@@ -63,8 +63,10 @@ static inline void dmub_dcn401_translate_addr(const union dmub_addr *addr_in,
+ void dmub_dcn401_reset(struct dmub_srv *dmub)
+ {
+ union dmub_gpint_data_register cmd;
+- const uint32_t timeout = 30;
+- uint32_t in_reset, scratch, i;
++ const uint32_t timeout_us = 1 * 1000 * 1000; //1s
++ const uint32_t poll_delay_us = 1; //1us
++ uint32_t i = 0;
++ uint32_t in_reset, scratch, pwait_mode;
+
+ REG_GET(DMCUB_CNTL2, DMCUB_SOFT_RESET, &in_reset);
+
+@@ -75,32 +77,35 @@ void dmub_dcn401_reset(struct dmub_srv *dmub)
+
+ dmub->hw_funcs.set_gpint(dmub, cmd);
+
+- /**
+- * Timeout covers both the ACK and the wait
+- * for remaining work to finish.
+- *
+- * This is mostly bound by the PHY disable sequence.
+- * Each register check will be greater than 1us, so
+- * don't bother using udelay.
+- */
+-
+- for (i = 0; i < timeout; ++i) {
++ for (i = 0; i < timeout_us; i++) {
+ if (dmub->hw_funcs.is_gpint_acked(dmub, cmd))
+ break;
++
++ udelay(poll_delay_us);
+ }
+
+- for (i = 0; i < timeout; ++i) {
++ for (; i < timeout_us; i++) {
+ scratch = dmub->hw_funcs.get_gpint_response(dmub);
+ if (scratch == DMUB_GPINT__STOP_FW_RESPONSE)
+ break;
++
++ udelay(poll_delay_us);
+ }
+
+- /* Force reset in case we timed out, DMCUB is likely hung. */
++ for (; i < timeout_us; i++) {
++ REG_GET(DMCUB_CNTL, DMCUB_PWAIT_MODE_STATUS, &pwait_mode);
++ if (pwait_mode & (1 << 0))
++ break;
++
++ udelay(poll_delay_us);
++ }
++ }
++
++ if (i >= timeout_us) {
++ /* timeout should never occur */
++ BREAK_TO_DEBUGGER();
+ }
+
+- REG_UPDATE(DMCUB_CNTL2, DMCUB_SOFT_RESET, 1);
+- REG_UPDATE(DMCUB_CNTL, DMCUB_ENABLE, 0);
+- REG_UPDATE(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET, 1);
+ REG_WRITE(DMCUB_INBOX1_RPTR, 0);
+ REG_WRITE(DMCUB_INBOX1_WPTR, 0);
+ REG_WRITE(DMCUB_OUTBOX1_RPTR, 0);
+@@ -131,7 +136,10 @@ void dmub_dcn401_backdoor_load(struct dmub_srv *dmub,
+
+ dmub_dcn401_get_fb_base_offset(dmub, &fb_base, &fb_offset);
+
++ /* reset and disable DMCUB and MMHUBBUB DMUIF */
+ REG_UPDATE(DMCUB_SEC_CNTL, DMCUB_SEC_RESET, 1);
++ REG_UPDATE(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET, 1);
++ REG_UPDATE(DMCUB_CNTL, DMCUB_ENABLE, 0);
+
+ dmub_dcn401_translate_addr(&cw0->offset, fb_base, fb_offset, &offset);
+
+@@ -151,6 +159,7 @@ void dmub_dcn401_backdoor_load(struct dmub_srv *dmub,
+ DMCUB_REGION3_CW1_TOP_ADDRESS, cw1->region.top,
+ DMCUB_REGION3_CW1_ENABLE, 1);
+
++ /* release DMCUB reset only to prevent premature execution */
+ REG_UPDATE_2(DMCUB_SEC_CNTL, DMCUB_SEC_RESET, 0, DMCUB_MEM_UNIT_ID,
+ 0x20);
+ }
+@@ -161,7 +170,10 @@ void dmub_dcn401_backdoor_load_zfb_mode(struct dmub_srv *dmub,
+ {
+ union dmub_addr offset;
+
++ /* reset and disable DMCUB and MMHUBBUB DMUIF */
+ REG_UPDATE(DMCUB_SEC_CNTL, DMCUB_SEC_RESET, 1);
++ REG_UPDATE(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET, 1);
++ REG_UPDATE(DMCUB_CNTL, DMCUB_ENABLE, 0);
+
+ offset = cw0->offset;
+
+@@ -181,6 +193,7 @@ void dmub_dcn401_backdoor_load_zfb_mode(struct dmub_srv *dmub,
+ DMCUB_REGION3_CW1_TOP_ADDRESS, cw1->region.top,
+ DMCUB_REGION3_CW1_ENABLE, 1);
+
++ /* release DMCUB reset only to prevent premature execution */
+ REG_UPDATE_2(DMCUB_SEC_CNTL, DMCUB_SEC_RESET, 0, DMCUB_MEM_UNIT_ID,
+ 0x20);
+ }
+diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.h b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.h
+index 4c8843b796950..31f95b27e227d 100644
+--- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.h
++++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.h
+@@ -169,7 +169,8 @@ struct dmub_srv;
+ DMUB_SF(HOST_INTERRUPT_CSR, HOST_REG_INBOX0_RSP_INT_EN) \
+ DMUB_SF(HOST_INTERRUPT_CSR, HOST_REG_OUTBOX0_RDY_INT_ACK) \
+ DMUB_SF(HOST_INTERRUPT_CSR, HOST_REG_OUTBOX0_RDY_INT_STAT) \
+- DMUB_SF(HOST_INTERRUPT_CSR, HOST_REG_OUTBOX0_RDY_INT_EN)
++ DMUB_SF(HOST_INTERRUPT_CSR, HOST_REG_OUTBOX0_RDY_INT_EN) \
++ DMUB_SF(DMCUB_CNTL, DMCUB_PWAIT_MODE_STATUS)
+
+ struct dmub_srv_dcn401_reg_offset {
+ #define DMUB_SR(reg) uint32_t reg;
+--
+2.39.5
+
--- /dev/null
+From 605e8311ec7e540d5c8c9fad981ef653a380520d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Feb 2025 15:45:43 +0800
+Subject: drm/amd/display: Fix incorrect DPCD configs while Replay/PSR switch
+
+From: Leon Huang <Leon.Huang1@amd.com>
+
+[ Upstream commit 0d9cabc8f591ea1cd97c071b853b75b155c13259 ]
+
+[Why]
+When switching between PSR/Replay,
+the DPCD config of previous mode is not cleared,
+resulting in unexpected behavior in TCON.
+
+[How]
+Initialize the DPCD in setup function
+
+Reviewed-by: Robin Chen <robin.chen@amd.com>
+Signed-off-by: Leon Huang <Leon.Huang1@amd.com>
+Signed-off-by: Tom Chung <chiahsuan.chung@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../link/protocols/link_edp_panel_control.c | 25 ++++++++++++++++---
+ 1 file changed, 22 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c
+index e0e3bb8653595..1e4adbc764ea6 100644
+--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c
++++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c
+@@ -675,6 +675,18 @@ bool edp_setup_psr(struct dc_link *link,
+ if (!link)
+ return false;
+
++ //Clear PSR cfg
++ memset(&psr_configuration, 0, sizeof(psr_configuration));
++ dm_helpers_dp_write_dpcd(
++ link->ctx,
++ link,
++ DP_PSR_EN_CFG,
++ &psr_configuration.raw,
++ sizeof(psr_configuration.raw));
++
++ if (link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED)
++ return false;
++
+ dc = link->ctx->dc;
+ dmcu = dc->res_pool->dmcu;
+ psr = dc->res_pool->psr;
+@@ -685,9 +697,6 @@ bool edp_setup_psr(struct dc_link *link,
+ if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst))
+ return false;
+
+-
+- memset(&psr_configuration, 0, sizeof(psr_configuration));
+-
+ psr_configuration.bits.ENABLE = 1;
+ psr_configuration.bits.CRC_VERIFICATION = 1;
+ psr_configuration.bits.FRAME_CAPTURE_INDICATION =
+@@ -950,6 +959,16 @@ bool edp_setup_replay(struct dc_link *link, const struct dc_stream_state *stream
+ if (!link)
+ return false;
+
++ //Clear Replay config
++ dm_helpers_dp_write_dpcd(link->ctx, link,
++ DP_SINK_PR_ENABLE_AND_CONFIGURATION,
++ (uint8_t *)&(replay_config.raw), sizeof(uint8_t));
++
++ if (!(link->replay_settings.config.replay_supported))
++ return false;
++
++ link->replay_settings.config.replay_error_status.raw = 0;
++
+ dc = link->ctx->dc;
+
+ replay = dc->res_pool->replay;
+--
+2.39.5
+
--- /dev/null
+From df4c4b0062392e2cdecda879cc3f8508db631738 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 7 Jan 2025 14:16:04 -0500
+Subject: drm/amd/display: Fix mismatch type comparison in custom_float
+
+From: Samson Tam <Samson.Tam@amd.com>
+
+[ Upstream commit 86f06bcbb54e93f3c7b5e22ae37e72882b74c4b0 ]
+
+[Why & How]
+Passing uint into uchar function param. Pass uint instead
+
+Signed-off-by: Samson Tam <Samson.Tam@amd.com>
+Reviewed-by: Alvin Lee <alvin.lee2@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/spl/spl_fixpt31_32.c | 2 +-
+ drivers/gpu/drm/amd/display/dc/spl/spl_fixpt31_32.h | 4 ++--
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/spl/spl_fixpt31_32.c b/drivers/gpu/drm/amd/display/dc/spl/spl_fixpt31_32.c
+index 131f1e3949d33..52d97918a3bd2 100644
+--- a/drivers/gpu/drm/amd/display/dc/spl/spl_fixpt31_32.c
++++ b/drivers/gpu/drm/amd/display/dc/spl/spl_fixpt31_32.c
+@@ -346,7 +346,7 @@ struct spl_fixed31_32 spl_fixpt_exp(struct spl_fixed31_32 arg)
+ if (m > 0)
+ return spl_fixpt_shl(
+ spl_fixed31_32_exp_from_taylor_series(r),
+- (unsigned char)m);
++ (unsigned int)m);
+ else
+ return spl_fixpt_div_int(
+ spl_fixed31_32_exp_from_taylor_series(r),
+diff --git a/drivers/gpu/drm/amd/display/dc/spl/spl_fixpt31_32.h b/drivers/gpu/drm/amd/display/dc/spl/spl_fixpt31_32.h
+index ed2647f9a0999..9f349ffe91485 100644
+--- a/drivers/gpu/drm/amd/display/dc/spl/spl_fixpt31_32.h
++++ b/drivers/gpu/drm/amd/display/dc/spl/spl_fixpt31_32.h
+@@ -189,7 +189,7 @@ static inline struct spl_fixed31_32 spl_fixpt_clamp(
+ * @brief
+ * result = arg << shift
+ */
+-static inline struct spl_fixed31_32 spl_fixpt_shl(struct spl_fixed31_32 arg, unsigned char shift)
++static inline struct spl_fixed31_32 spl_fixpt_shl(struct spl_fixed31_32 arg, unsigned int shift)
+ {
+ SPL_ASSERT(((arg.value >= 0) && (arg.value <= LLONG_MAX >> shift)) ||
+ ((arg.value < 0) && (arg.value >= ~(LLONG_MAX >> shift))));
+@@ -203,7 +203,7 @@ static inline struct spl_fixed31_32 spl_fixpt_shl(struct spl_fixed31_32 arg, uns
+ * @brief
+ * result = arg >> shift
+ */
+-static inline struct spl_fixed31_32 spl_fixpt_shr(struct spl_fixed31_32 arg, unsigned char shift)
++static inline struct spl_fixed31_32 spl_fixpt_shr(struct spl_fixed31_32 arg, unsigned int shift)
+ {
+ bool negative = arg.value < 0;
+
+--
+2.39.5
+
--- /dev/null
+From 9bdd51639095e2af0bcfa1811a66b8fd15506ccc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 19 Dec 2024 17:19:09 -0500
+Subject: drm/amd/display: Fix mismatch type comparison
+
+From: Assadian, Navid <navid.assadian@amd.com>
+
+[ Upstream commit 26873260d394b1e33cdd720154aedf0af95327f9 ]
+
+The mismatch type comparison/assignment may cause data loss. Since the
+values are always non-negative, it is safe to use unsigned variables to
+resolve the mismatch.
+
+Signed-off-by: Navid Assadian <navid.assadian@amd.com>
+Reviewed-by: Joshua Aberback <joshua.aberback@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/spl/dc_spl.c | 4 ++--
+ drivers/gpu/drm/amd/display/dc/spl/dc_spl_types.h | 2 +-
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/spl/dc_spl.c b/drivers/gpu/drm/amd/display/dc/spl/dc_spl.c
+index 18b423bd302a7..22602f088553d 100644
+--- a/drivers/gpu/drm/amd/display/dc/spl/dc_spl.c
++++ b/drivers/gpu/drm/amd/display/dc/spl/dc_spl.c
+@@ -963,8 +963,8 @@ static bool spl_get_optimal_number_of_taps(
+ bool *enable_isharp)
+ {
+ int num_part_y, num_part_c;
+- int max_taps_y, max_taps_c;
+- int min_taps_y, min_taps_c;
++ unsigned int max_taps_y, max_taps_c;
++ unsigned int min_taps_y, min_taps_c;
+ enum lb_memory_config lb_config;
+ bool skip_easf = false;
+ bool is_subsampled = spl_is_subsampled_format(spl_in->basic_in.format);
+diff --git a/drivers/gpu/drm/amd/display/dc/spl/dc_spl_types.h b/drivers/gpu/drm/amd/display/dc/spl/dc_spl_types.h
+index 467af9dd90ded..5d139cf51e89b 100644
+--- a/drivers/gpu/drm/amd/display/dc/spl/dc_spl_types.h
++++ b/drivers/gpu/drm/amd/display/dc/spl/dc_spl_types.h
+@@ -484,7 +484,7 @@ struct spl_sharpness_range {
+ };
+ struct adaptive_sharpness {
+ bool enable;
+- int sharpness_level;
++ unsigned int sharpness_level;
+ struct spl_sharpness_range sharpness_range;
+ };
+ enum linear_light_scaling { // convert it in translation logic
+--
+2.39.5
+
--- /dev/null
+From ac9bdb3f7c2d0b7fd5c69c10324cf45cc804dc9e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 12 Feb 2025 17:06:42 -0500
+Subject: drm/amd/display: Fix p-state type when p-state is unsupported
+
+From: Dillon Varone <Dillon.Varone@amd.com>
+
+[ Upstream commit a025f424af0407b7561bd5e6217295dde3abbc2e ]
+
+[WHY&HOW]
+P-state type would remain on previously used when unsupported which
+causes confusion in logging and visual confirm, so set back to zero
+when unsupported.
+
+Reviewed-by: Aric Cyr <aric.cyr@amd.com>
+Signed-off-by: Dillon Varone <Dillon.Varone@amd.com>
+Signed-off-by: Wayne Lin <wayne.lin@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
+index a49604b7701f7..1406ee4bff801 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
+@@ -563,6 +563,7 @@ void set_p_state_switch_method(
+ if (!dc->ctx || !dc->ctx->dmub_srv || !pipe_ctx || !vba)
+ return;
+
++ pipe_ctx->p_state_type = P_STATE_UNKNOWN;
+ if (vba->DRAMClockChangeSupport[vba->VoltageLevel][vba->maxMpcComb] !=
+ dm_dram_clock_change_unsupported) {
+ /* MCLK switching is supported */
+--
+2.39.5
+
--- /dev/null
+From 92d641083e1414a30ea30770960a950a35d13613 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 17 Jan 2025 17:49:41 -0500
+Subject: drm/amd/display: Fixes for mcache programming in DML21
+
+From: Dillon Varone <dillon.varone@amd.com>
+
+[ Upstream commit c909a49128a31bced8cfbd2dfb0a4fe56e01a6d0 ]
+
+[WHY & HOW]
+- Fix indexing phantom planes for mcache programming in the wrapper
+- Fix phantom mcache allocations to align with HW guidance
+- Fix mcache assignment for chroma plane for multi-planar formats
+
+Reviewed-by: Austin Zheng <Austin.Zheng@amd.com>
+Signed-off-by: Dillon Varone <dillon.varone@amd.com>
+Signed-off-by: Alex Hung <alex.hung@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../amd/display/dc/dml2/dml21/dml21_utils.c | 1 -
+ .../amd/display/dc/dml2/dml21/dml21_wrapper.c | 14 +++++++++
+ .../display/dc/dml2/dml21/inc/dml_top_types.h | 1 +
+ .../dml2/dml21/src/dml2_core/dml2_core_dcn4.c | 30 ++++++++++++++++++-
+ .../src/dml2_core/dml2_core_dcn4_calcs.c | 3 ++
+ .../dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.c | 21 +++++++++++++
+ .../dml2/dml21/src/dml2_top/dml2_top_soc15.c | 8 -----
+ 7 files changed, 68 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml21/dml21_utils.c b/drivers/gpu/drm/amd/display/dc/dml2/dml21/dml21_utils.c
+index 1e56d995cd0e7..930e86cdb88a2 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml2/dml21/dml21_utils.c
++++ b/drivers/gpu/drm/amd/display/dc/dml2/dml21/dml21_utils.c
+@@ -232,7 +232,6 @@ void dml21_program_dc_pipe(struct dml2_context *dml_ctx, struct dc_state *contex
+ context->bw_ctx.bw.dcn.clk.dppclk_khz = pipe_ctx->plane_res.bw.dppclk_khz;
+
+ dml21_populate_mall_allocation_size(context, dml_ctx, pln_prog, pipe_ctx);
+- memcpy(&context->bw_ctx.bw.dcn.mcache_allocations[pipe_ctx->pipe_idx], &pln_prog->mcache_allocation, sizeof(struct dml2_mcache_surface_allocation));
+
+ bool sub_vp_enabled = is_sub_vp_enabled(pipe_ctx->stream->ctx->dc, context);
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml21/dml21_wrapper.c b/drivers/gpu/drm/amd/display/dc/dml2/dml21/dml21_wrapper.c
+index d6fd13f43c08f..5d16f36ec95c8 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml2/dml21/dml21_wrapper.c
++++ b/drivers/gpu/drm/amd/display/dc/dml2/dml21/dml21_wrapper.c
+@@ -129,6 +129,7 @@ static void dml21_calculate_rq_and_dlg_params(const struct dc *dc, struct dc_sta
+ struct pipe_ctx *dc_main_pipes[__DML2_WRAPPER_MAX_STREAMS_PLANES__];
+ struct pipe_ctx *dc_phantom_pipes[__DML2_WRAPPER_MAX_STREAMS_PLANES__] = {0};
+ int num_pipes;
++ unsigned int dml_phantom_prog_idx;
+
+ context->bw_ctx.bw.dcn.clk.dppclk_khz = 0;
+
+@@ -142,6 +143,9 @@ static void dml21_calculate_rq_and_dlg_params(const struct dc *dc, struct dc_sta
+ context->bw_ctx.bw.dcn.mall_ss_psr_active_size_bytes = 0;
+ context->bw_ctx.bw.dcn.mall_subvp_size_bytes = 0;
+
++ /* phantom's start after main planes */
++ dml_phantom_prog_idx = in_ctx->v21.mode_programming.programming->display_config.num_planes;
++
+ for (dml_prog_idx = 0; dml_prog_idx < DML2_MAX_PLANES; dml_prog_idx++) {
+ pln_prog = &in_ctx->v21.mode_programming.programming->plane_programming[dml_prog_idx];
+
+@@ -167,6 +171,16 @@ static void dml21_calculate_rq_and_dlg_params(const struct dc *dc, struct dc_sta
+ dml21_program_dc_pipe(in_ctx, context, dc_phantom_pipes[dc_pipe_index], pln_prog, stream_prog);
+ }
+ }
++
++ /* copy per plane mcache allocation */
++ memcpy(&context->bw_ctx.bw.dcn.mcache_allocations[dml_prog_idx], &pln_prog->mcache_allocation, sizeof(struct dml2_mcache_surface_allocation));
++ if (pln_prog->phantom_plane.valid) {
++ memcpy(&context->bw_ctx.bw.dcn.mcache_allocations[dml_phantom_prog_idx],
++ &pln_prog->phantom_plane.mcache_allocation,
++ sizeof(struct dml2_mcache_surface_allocation));
++
++ dml_phantom_prog_idx++;
++ }
+ }
+
+ /* assign global clocks */
+diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml21/inc/dml_top_types.h b/drivers/gpu/drm/amd/display/dc/dml2/dml21/inc/dml_top_types.h
+index d2d053f2354d0..0ab19cf4d2421 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml2/dml21/inc/dml_top_types.h
++++ b/drivers/gpu/drm/amd/display/dc/dml2/dml21/inc/dml_top_types.h
+@@ -245,6 +245,7 @@ struct dml2_per_plane_programming {
+ struct {
+ bool valid;
+ struct dml2_plane_parameters descriptor;
++ struct dml2_mcache_surface_allocation mcache_allocation;
+ struct dml2_dchub_per_pipe_register_set *pipe_regs[DML2_MAX_PLANES];
+ } phantom_plane;
+ };
+diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4.c b/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4.c
+index 7216d25c783e6..44d2969a904ea 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4.c
++++ b/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4.c
+@@ -253,7 +253,8 @@ static void expand_implict_subvp(const struct display_configuation_with_meta *di
+ static void pack_mode_programming_params_with_implicit_subvp(struct dml2_core_instance *core, const struct display_configuation_with_meta *display_cfg,
+ const struct dml2_display_cfg *svp_expanded_display_cfg, struct dml2_display_cfg_programming *programming, struct dml2_core_scratch *scratch)
+ {
+- unsigned int stream_index, plane_index, pipe_offset, stream_already_populated_mask, main_plane_index;
++ unsigned int stream_index, plane_index, pipe_offset, stream_already_populated_mask, main_plane_index, mcache_index;
++ unsigned int total_main_mcaches_required = 0;
+ int total_pipe_regs_copied = 0;
+ int dml_internal_pipe_index = 0;
+ const struct dml2_plane_parameters *main_plane;
+@@ -324,6 +325,13 @@ static void pack_mode_programming_params_with_implicit_subvp(struct dml2_core_in
+
+ dml2_core_calcs_get_mall_allocation(&core->clean_me_up.mode_lib, &programming->plane_programming[plane_index].surface_size_mall_bytes, dml_internal_pipe_index);
+
++ memcpy(&programming->plane_programming[plane_index].mcache_allocation,
++ &display_cfg->stage2.mcache_allocations[plane_index],
++ sizeof(struct dml2_mcache_surface_allocation));
++ total_main_mcaches_required += programming->plane_programming[plane_index].mcache_allocation.num_mcaches_plane0 +
++ programming->plane_programming[plane_index].mcache_allocation.num_mcaches_plane1 -
++ (programming->plane_programming[plane_index].mcache_allocation.last_slice_sharing.plane0_plane1 ? 1 : 0);
++
+ for (pipe_offset = 0; pipe_offset < programming->plane_programming[plane_index].num_dpps_required; pipe_offset++) {
+ // Assign storage for this pipe's register values
+ programming->plane_programming[plane_index].pipe_regs[pipe_offset] = &programming->pipe_regs[total_pipe_regs_copied];
+@@ -362,6 +370,22 @@ static void pack_mode_programming_params_with_implicit_subvp(struct dml2_core_in
+ memcpy(&programming->plane_programming[main_plane_index].phantom_plane.descriptor, phantom_plane, sizeof(struct dml2_plane_parameters));
+
+ dml2_core_calcs_get_mall_allocation(&core->clean_me_up.mode_lib, &programming->plane_programming[main_plane_index].svp_size_mall_bytes, dml_internal_pipe_index);
++
++ /* generate mcache allocation, phantoms use identical mcache configuration, but in the MALL set and unique mcache ID's beginning after all main ID's */
++ memcpy(&programming->plane_programming[main_plane_index].phantom_plane.mcache_allocation,
++ &programming->plane_programming[main_plane_index].mcache_allocation,
++ sizeof(struct dml2_mcache_surface_allocation));
++ for (mcache_index = 0; mcache_index < programming->plane_programming[main_plane_index].phantom_plane.mcache_allocation.num_mcaches_plane0; mcache_index++) {
++ programming->plane_programming[main_plane_index].phantom_plane.mcache_allocation.global_mcache_ids_plane0[mcache_index] += total_main_mcaches_required;
++ programming->plane_programming[main_plane_index].phantom_plane.mcache_allocation.global_mcache_ids_mall_plane0[mcache_index] =
++ programming->plane_programming[main_plane_index].phantom_plane.mcache_allocation.global_mcache_ids_plane0[mcache_index];
++ }
++ for (mcache_index = 0; mcache_index < programming->plane_programming[main_plane_index].phantom_plane.mcache_allocation.num_mcaches_plane1; mcache_index++) {
++ programming->plane_programming[main_plane_index].phantom_plane.mcache_allocation.global_mcache_ids_plane1[mcache_index] += total_main_mcaches_required;
++ programming->plane_programming[main_plane_index].phantom_plane.mcache_allocation.global_mcache_ids_mall_plane1[mcache_index] =
++ programming->plane_programming[main_plane_index].phantom_plane.mcache_allocation.global_mcache_ids_plane1[mcache_index];
++ }
++
+ for (pipe_offset = 0; pipe_offset < programming->plane_programming[main_plane_index].num_dpps_required; pipe_offset++) {
+ // Assign storage for this pipe's register values
+ programming->plane_programming[main_plane_index].phantom_plane.pipe_regs[pipe_offset] = &programming->pipe_regs[total_pipe_regs_copied];
+@@ -571,6 +595,10 @@ bool core_dcn4_mode_programming(struct dml2_core_mode_programming_in_out *in_out
+
+ dml2_core_calcs_get_mall_allocation(&core->clean_me_up.mode_lib, &in_out->programming->plane_programming[plane_index].surface_size_mall_bytes, dml_internal_pipe_index);
+
++ memcpy(&in_out->programming->plane_programming[plane_index].mcache_allocation,
++ &in_out->display_cfg->stage2.mcache_allocations[plane_index],
++ sizeof(struct dml2_mcache_surface_allocation));
++
+ for (pipe_offset = 0; pipe_offset < in_out->programming->plane_programming[plane_index].num_dpps_required; pipe_offset++) {
+ in_out->programming->plane_programming[plane_index].plane_descriptor = &in_out->programming->display_config.plane_descriptors[plane_index];
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c b/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c
+index c1ff869512f27..8ad7704b76691 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c
++++ b/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c
+@@ -2638,6 +2638,9 @@ static void calculate_mcache_setting(
+ // Luma/Chroma combine in the last mcache
+ // In the case of Luma/Chroma combine-mCache (with lc_comb_mcache==1), all mCaches except the last segment are filled as much as possible, when stay aligned to mvmpg boundary
+ if (*p->lc_comb_mcache && l->is_dual_plane) {
++ /* if luma and chroma planes share an mcache, increase total chroma mcache count */
++ *p->num_mcaches_c = *p->num_mcaches_c + 1;
++
+ for (n = 0; n < *p->num_mcaches_l - 1; n++)
+ p->mcache_offsets_l[n] = (n + 1) * l->mvmpg_per_mcache_lb_l * l->mvmpg_access_width_l;
+ p->mcache_offsets_l[*p->num_mcaches_l - 1] = l->full_vp_access_width_l;
+diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.c b/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.c
+index a3324f7b9ba68..15c906c42ec45 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.c
++++ b/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.c
+@@ -1082,12 +1082,21 @@ static bool all_timings_support_svp(const struct dml2_pmo_instance *pmo,
+ const struct dml2_fams2_meta *stream_fams2_meta;
+ unsigned int microschedule_vlines;
+ unsigned int i;
++ unsigned int mcaches_per_plane;
++ unsigned int total_mcaches_required = 0;
+
+ unsigned int num_planes_per_stream[DML2_MAX_PLANES] = { 0 };
+
+ /* confirm timing it is not a centered timing */
+ for (i = 0; i < display_config->display_config.num_planes; i++) {
+ plane_descriptor = &display_config->display_config.plane_descriptors[i];
++ mcaches_per_plane = 0;
++
++ if (plane_descriptor->surface.dcc.enable) {
++ mcaches_per_plane += display_config->stage2.mcache_allocations[i].num_mcaches_plane0 +
++ display_config->stage2.mcache_allocations[i].num_mcaches_plane1 -
++ (display_config->stage2.mcache_allocations[i].last_slice_sharing.plane0_plane1 ? 1 : 0);
++ }
+
+ if (is_bit_set_in_bitfield(mask, (unsigned char)plane_descriptor->stream_index)) {
+ num_planes_per_stream[plane_descriptor->stream_index]++;
+@@ -1098,7 +1107,19 @@ static bool all_timings_support_svp(const struct dml2_pmo_instance *pmo,
+ plane_descriptor->composition.rotation_angle != dml2_rotation_0) {
+ return false;
+ }
++
++ /* phantom requires same number of mcaches as main */
++ if (plane_descriptor->surface.dcc.enable) {
++ mcaches_per_plane *= 2;
++ }
+ }
++
++ total_mcaches_required += mcaches_per_plane;
++ }
++
++ if (total_mcaches_required > pmo->soc_bb->num_dcc_mcaches) {
++ /* too many mcaches required */
++ return false;
+ }
+
+ for (i = 0; i < DML2_MAX_PLANES; i++) {
+diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_top/dml2_top_soc15.c b/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_top/dml2_top_soc15.c
+index a8f58f8448e42..dc2ce5e77f579 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_top/dml2_top_soc15.c
++++ b/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_top/dml2_top_soc15.c
+@@ -831,7 +831,6 @@ static bool dml2_top_soc15_build_mode_programming(struct dml2_build_mode_program
+ bool uclk_pstate_success = false;
+ bool vmin_success = false;
+ bool stutter_success = false;
+- unsigned int i;
+
+ memset(l, 0, sizeof(struct dml2_build_mode_programming_locals));
+ memset(in_out->programming, 0, sizeof(struct dml2_display_cfg_programming));
+@@ -976,13 +975,6 @@ static bool dml2_top_soc15_build_mode_programming(struct dml2_build_mode_program
+ l->base_display_config_with_meta.stage5.success = true;
+ }
+
+- /*
+- * Populate mcache programming
+- */
+- for (i = 0; i < in_out->display_config->num_planes; i++) {
+- in_out->programming->plane_programming[i].mcache_allocation = l->base_display_config_with_meta.stage2.mcache_allocations[i];
+- }
+-
+ /*
+ * Call DPMM to map all requirements to minimum clock state
+ */
+--
+2.39.5
+
--- /dev/null
+From 911b79e9c141c7bc01d47781ee7ca3cae802e477 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Mar 2025 23:15:56 +0800
+Subject: drm/amd/display: Guard against setting dispclk low for dcn31x
+
+From: Jing Zhou <Jing.Zhou@amd.com>
+
+[ Upstream commit 9c2f4ae64bb6f6d83a54d88b9ee0f369cdbb9fa8 ]
+
+[WHY]
+We should never apply a minimum dispclk value while in
+prepare_bandwidth or while displays are active. This is
+always an optimizaiton for when all displays are disabled.
+
+[HOW]
+Defer dispclk optimization until safe_to_lower = true
+and display_count reaches 0.
+
+Since 0 has a special value in this logic (ie. no dispclk
+required) we also need adjust the logic that clamps it for
+the actual request to PMFW.
+
+Reviewed-by: Charlene Liu <charlene.liu@amd.com>
+Reviewed-by: Chris Park <chris.park@amd.com>
+Reviewed-by: Eric Yang <eric.yang@amd.com>
+Signed-off-by: Jing Zhou <Jing.Zhou@amd.com>
+Signed-off-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
+Signed-off-by: Alex Hung <alex.hung@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../dc/clk_mgr/dcn315/dcn315_clk_mgr.c | 20 +++++++++++--------
+ .../dc/clk_mgr/dcn316/dcn316_clk_mgr.c | 13 +++++++++---
+ 2 files changed, 22 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c
+index a0fb4481d2f1b..827b24b3442ad 100644
+--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c
++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c
+@@ -130,7 +130,7 @@ static void dcn315_update_clocks(struct clk_mgr *clk_mgr_base,
+ struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
+ struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk;
+ struct dc *dc = clk_mgr_base->ctx->dc;
+- int display_count;
++ int display_count = 0;
+ bool update_dppclk = false;
+ bool update_dispclk = false;
+ bool dpp_clock_lowered = false;
+@@ -204,15 +204,19 @@ static void dcn315_update_clocks(struct clk_mgr *clk_mgr_base,
+ update_dppclk = true;
+ }
+
+- if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) {
+- /* No need to apply the w/a if we haven't taken over from bios yet */
+- if (clk_mgr_base->clks.dispclk_khz)
+- dcn315_disable_otg_wa(clk_mgr_base, context, true);
++ if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz) &&
++ (new_clocks->dispclk_khz > 0 || (safe_to_lower && display_count == 0))) {
++ int requested_dispclk_khz = new_clocks->dispclk_khz;
+
++ dcn315_disable_otg_wa(clk_mgr_base, context, true);
++
++ /* Clamp the requested clock to PMFW based on their limit. */
++ if (dc->debug.min_disp_clk_khz > 0 && requested_dispclk_khz < dc->debug.min_disp_clk_khz)
++ requested_dispclk_khz = dc->debug.min_disp_clk_khz;
++
++ dcn315_smu_set_dispclk(clk_mgr, requested_dispclk_khz);
+ clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz;
+- dcn315_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz);
+- if (clk_mgr_base->clks.dispclk_khz)
+- dcn315_disable_otg_wa(clk_mgr_base, context, false);
++ dcn315_disable_otg_wa(clk_mgr_base, context, false);
+
+ update_dispclk = true;
+ }
+diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c
+index c3e50c3aaa609..37c39756fece4 100644
+--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c
++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c
+@@ -140,7 +140,7 @@ static void dcn316_update_clocks(struct clk_mgr *clk_mgr_base,
+ struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
+ struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk;
+ struct dc *dc = clk_mgr_base->ctx->dc;
+- int display_count;
++ int display_count = 0;
+ bool update_dppclk = false;
+ bool update_dispclk = false;
+ bool dpp_clock_lowered = false;
+@@ -211,11 +211,18 @@ static void dcn316_update_clocks(struct clk_mgr *clk_mgr_base,
+ update_dppclk = true;
+ }
+
+- if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) {
++ if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz) &&
++ (new_clocks->dispclk_khz > 0 || (safe_to_lower && display_count == 0))) {
++ int requested_dispclk_khz = new_clocks->dispclk_khz;
++
+ dcn316_disable_otg_wa(clk_mgr_base, context, safe_to_lower, true);
+
++ /* Clamp the requested clock to PMFW based on their limit. */
++ if (dc->debug.min_disp_clk_khz > 0 && requested_dispclk_khz < dc->debug.min_disp_clk_khz)
++ requested_dispclk_khz = dc->debug.min_disp_clk_khz;
++
++ dcn316_smu_set_dispclk(clk_mgr, requested_dispclk_khz);
+ clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz;
+- dcn316_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz);
+ dcn316_disable_otg_wa(clk_mgr_base, context, safe_to_lower, false);
+
+ update_dispclk = true;
+--
+2.39.5
+
--- /dev/null
+From 1b001607bcbb63e9db4a86f6b3deb0fc1e005293 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Feb 2025 09:49:58 -0500
+Subject: drm/amd/display: Guard against setting dispclk low when active
+
+From: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
+
+[ Upstream commit 72d7a7fa1f2404fd31c84a8f808b1b37021a3a9e ]
+
+[Why]
+We should never apply a minimum dispclk value while in prepare_bandwidth
+or while displays are active. This is always an optimization for when
+all displays are disabled.
+
+[How]
+Defer dispclk optimization until safe_to_lower = true and display_count
+reaches 0.
+
+Since 0 has a special value in this logic (ie. no dispclk required)
+we also need adjust the logic that clamps it for the actual request
+to PMFW.
+
+Reviewed-by: Gabe Teeger <gabe.teeger@amd.com>
+Reviewed-by: Leo Chen <leo.chen@amd.com>
+Reviewed-by: Syed Hassan <syed.hassan@amd.com>
+Signed-off-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
+Signed-off-by: Roman Li <roman.li@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c | 13 +++++++++----
+ 1 file changed, 9 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c
+index 1648226586e22..1f47931c2dafc 100644
+--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c
++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c
+@@ -467,14 +467,19 @@ void dcn35_update_clocks(struct clk_mgr *clk_mgr_base,
+ update_dppclk = true;
+ }
+
+- if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) {
++ if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz) &&
++ (new_clocks->dispclk_khz > 0 || (safe_to_lower && display_count == 0))) {
++ int requested_dispclk_khz = new_clocks->dispclk_khz;
++
+ dcn35_disable_otg_wa(clk_mgr_base, context, safe_to_lower, true);
+
+- if (dc->debug.min_disp_clk_khz > 0 && new_clocks->dispclk_khz < dc->debug.min_disp_clk_khz)
+- new_clocks->dispclk_khz = dc->debug.min_disp_clk_khz;
++ /* Clamp the requested clock to PMFW based on their limit. */
++ if (dc->debug.min_disp_clk_khz > 0 && requested_dispclk_khz < dc->debug.min_disp_clk_khz)
++ requested_dispclk_khz = dc->debug.min_disp_clk_khz;
+
++ dcn35_smu_set_dispclk(clk_mgr, requested_dispclk_khz);
+ clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz;
+- dcn35_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz);
++
+ dcn35_disable_otg_wa(clk_mgr_base, context, safe_to_lower, false);
+
+ update_dispclk = true;
+--
+2.39.5
+
--- /dev/null
+From e40ee048a9c140040aaf99fad6d7055bffa017b8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 12 Feb 2025 15:17:56 -0500
+Subject: drm/amd/display: handle max_downscale_src_width fail check
+
+From: Yihan Zhu <Yihan.Zhu@amd.com>
+
+[ Upstream commit 02a940da2ccc0cc0299811379580852b405a0ea2 ]
+
+[WHY]
+If max_downscale_src_width check fails, we exit early from TAP calculation and left a NULL
+value to the scaling data structure to cause the zero divide in the DML validation.
+
+[HOW]
+Call set default TAP calculation before early exit in get_optimal_number_of_taps due to
+max downscale limit exceed.
+
+Reviewed-by: Samson Tam <samson.tam@amd.com>
+Signed-off-by: Yihan Zhu <Yihan.Zhu@amd.com>
+Signed-off-by: Zaeem Mohamed <zaeem.mohamed@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp.c | 11 ++++++-----
+ 1 file changed, 6 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp.c b/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp.c
+index 40acebd13e46d..abf439e743f23 100644
+--- a/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp.c
++++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp.c
+@@ -425,11 +425,6 @@ bool dpp3_get_optimal_number_of_taps(
+ int min_taps_y, min_taps_c;
+ enum lb_memory_config lb_config;
+
+- if (scl_data->viewport.width > scl_data->h_active &&
+- dpp->ctx->dc->debug.max_downscale_src_width != 0 &&
+- scl_data->viewport.width > dpp->ctx->dc->debug.max_downscale_src_width)
+- return false;
+-
+ /*
+ * Set default taps if none are provided
+ * From programming guide: taps = min{ ceil(2*H_RATIO,1), 8} for downscaling
+@@ -467,6 +462,12 @@ bool dpp3_get_optimal_number_of_taps(
+ else
+ scl_data->taps.h_taps_c = in_taps->h_taps_c;
+
++ // Avoid null data in the scl data with this early return, proceed non-adaptive calcualtion first
++ if (scl_data->viewport.width > scl_data->h_active &&
++ dpp->ctx->dc->debug.max_downscale_src_width != 0 &&
++ scl_data->viewport.width > dpp->ctx->dc->debug.max_downscale_src_width)
++ return false;
++
+ /*Ensure we can support the requested number of vtaps*/
+ min_taps_y = dc_fixpt_ceil(scl_data->ratios.vert);
+ min_taps_c = dc_fixpt_ceil(scl_data->ratios.vert_c);
+--
+2.39.5
+
--- /dev/null
+From d411a33e856ffb64190d600158f92692d1d4a85e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 8 Jan 2025 12:03:23 -0500
+Subject: drm/amd/display: Increase block_sequence array size
+
+From: Joshua Aberback <joshua.aberback@amd.com>
+
+[ Upstream commit 3a7810c212bcf2f722671dadf4b23ff70a7d23ee ]
+
+[Why]
+It's possible to generate more than 50 steps in hwss_build_fast_sequence,
+for example with a 6-pipe asic where all pipes are in one MPC chain. This
+overflows the block_sequence buffer and corrupts block_sequence_steps,
+causing a crash.
+
+[How]
+Expand block_sequence to 100 items. A naive upper bound on the possible
+number of steps for a 6-pipe asic, ignoring the potential for steps to be
+mutually exclusive, is 91 with current code, therefore 100 is sufficient.
+
+Reviewed-by: Alvin Lee <alvin.lee2@amd.com>
+Signed-off-by: Joshua Aberback <joshua.aberback@amd.com>
+Signed-off-by: Wayne Lin <wayne.lin@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/inc/core_types.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h
+index d558efc6e12f9..652d52040f4e6 100644
+--- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h
++++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h
+@@ -627,7 +627,7 @@ struct dc_state {
+ */
+ struct bw_context bw_ctx;
+
+- struct block_sequence block_sequence[50];
++ struct block_sequence block_sequence[100];
+ unsigned int block_sequence_steps;
+ struct dc_dmub_cmd dc_dmub_cmd[10];
+ unsigned int dmub_cmd_count;
+--
+2.39.5
+
--- /dev/null
+From eb16a102ab24d94a411c8089eb263dd68a40d3de Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Jan 2025 14:22:31 +0800
+Subject: drm/amd/display: Initial psr_version with correct setting
+
+From: Tom Chung <chiahsuan.chung@amd.com>
+
+[ Upstream commit d8c782cac5007e68e7484d420168f12d3490def6 ]
+
+[Why & How]
+The initial setting for psr_version is not correct while
+create a virtual link.
+
+The default psr_version should be DC_PSR_VERSION_UNSUPPORTED.
+
+Reviewed-by: Roman Li <roman.li@amd.com>
+Signed-off-by: Tom Chung <chiahsuan.chung@amd.com>
+Signed-off-by: Zaeem Mohamed <zaeem.mohamed@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/core/dc.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
+index 167f9d99a5408..0ce0ad7f98396 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
+@@ -276,6 +276,7 @@ static bool create_links(
+ link->link_id.type = OBJECT_TYPE_CONNECTOR;
+ link->link_id.id = CONNECTOR_ID_VIRTUAL;
+ link->link_id.enum_id = ENUM_ID_1;
++ link->psr_settings.psr_version = DC_PSR_VERSION_UNSUPPORTED;
+ link->link_enc = kzalloc(sizeof(*link->link_enc), GFP_KERNEL);
+
+ if (!link->link_enc) {
+--
+2.39.5
+
--- /dev/null
+From a07154ee6627ce013cce21ab48e4f918b59ed4ea Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 25 Feb 2025 14:52:30 +0800
+Subject: drm/amd/display: not abort link train when bw is low
+
+From: Peichen Huang <PeiChen.Huang@amd.com>
+
+[ Upstream commit 8a21da2842bb22b2b80e5902d0438030d729bfd3 ]
+
+[WHY]
+DP tunneling should not abort link train even bandwidth become
+too low after downgrade. Otherwise, it would fail compliance test.
+
+[HOW}
+Do link train with downgrade settings even bandwidth is not enough
+
+Reviewed-by: Cruise Hung <cruise.hung@amd.com>
+Reviewed-by: Meenakshikumar Somasundaram <meenakshikumar.somasundaram@amd.com>
+Signed-off-by: Peichen Huang <PeiChen.Huang@amd.com>
+Signed-off-by: Tom Chung <chiahsuan.chung@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../gpu/drm/amd/display/dc/link/protocols/link_dp_training.c | 5 +----
+ 1 file changed, 1 insertion(+), 4 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c
+index 751c18e592ea5..7848ddb94456c 100644
+--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c
++++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c
+@@ -1782,13 +1782,10 @@ bool perform_link_training_with_retries(
+ is_link_bw_min = ((cur_link_settings.link_rate <= LINK_RATE_LOW) &&
+ (cur_link_settings.lane_count <= LANE_COUNT_ONE));
+
+- if (is_link_bw_low) {
++ if (is_link_bw_low)
+ DC_LOG_WARNING(
+ "%s: Link(%d) bandwidth too low after fallback req_bw(%d) > link_bw(%d)\n",
+ __func__, link->link_index, req_bw, link_bw);
+-
+- return false;
+- }
+ }
+
+ msleep(delay_between_attempts);
+--
+2.39.5
+
--- /dev/null
+From fd123424c6643669dca7ce6a0f2db3845cc67cd6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Jan 2025 11:57:54 -0500
+Subject: drm/amd/display: pass calculated dram_speed_mts to dml2
+
+From: Charlene Liu <Charlene.Liu@amd.com>
+
+[ Upstream commit b40d022ec06ade9f6c809091dc188422a0f0946d ]
+
+[why]
+currently dml2 is using a hard coded 16 to convert memclk to dram_speed_mts.
+for apu, this depends on wck_ratio.
+
+change to pass the already calculated dram_speed_mts from fpu to dml2.
+
+v2: use existing calculation of dram_speed_mts for now to avoid regression
+
+Signed-off-by: Charlene Liu <Charlene.Liu@amd.com>
+Signed-off-by: Aurabindo Pillai <aurabindo.pillai@amd.com>
+Reviewed-by: Roman Li <Roman.Li@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c | 2 ++
+ drivers/gpu/drm/amd/display/dc/dml/dcn351/dcn351_fpu.c | 1 +
+ drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.h | 1 +
+ 3 files changed, 4 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c
+index beed7adbbd43e..c90dee4e9116a 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c
++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c
+@@ -367,6 +367,8 @@ void dcn35_update_bw_bounding_box_fpu(struct dc *dc,
+ clock_limits[i].socclk_mhz;
+ dc->dml2_options.bbox_overrides.clks_table.clk_entries[i].memclk_mhz =
+ clk_table->entries[i].memclk_mhz * clk_table->entries[i].wck_ratio;
++
++ dc->dml2_options.bbox_overrides.clks_table.clk_entries[i].dram_speed_mts = clock_limits[i].dram_speed_mts;
+ dc->dml2_options.bbox_overrides.clks_table.clk_entries[i].dtbclk_mhz =
+ clock_limits[i].dtbclk_mhz;
+ dc->dml2_options.bbox_overrides.clks_table.num_entries_per_clk.num_dcfclk_levels =
+diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn351/dcn351_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn351/dcn351_fpu.c
+index d9e63c4fdd95c..17d0b4923b0cc 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml/dcn351/dcn351_fpu.c
++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn351/dcn351_fpu.c
+@@ -401,6 +401,7 @@ void dcn351_update_bw_bounding_box_fpu(struct dc *dc,
+ clock_limits[i].socclk_mhz;
+ dc->dml2_options.bbox_overrides.clks_table.clk_entries[i].memclk_mhz =
+ clk_table->entries[i].memclk_mhz * clk_table->entries[i].wck_ratio;
++ dc->dml2_options.bbox_overrides.clks_table.clk_entries[i].dram_speed_mts = clock_limits[i].dram_speed_mts;
+ dc->dml2_options.bbox_overrides.clks_table.clk_entries[i].dtbclk_mhz =
+ clock_limits[i].dtbclk_mhz;
+ dc->dml2_options.bbox_overrides.clks_table.num_entries_per_clk.num_dcfclk_levels =
+diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.h b/drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.h
+index 0f944fcfd5a5b..785226945699d 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.h
++++ b/drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.h
+@@ -159,6 +159,7 @@ struct dml2_clks_table_entry {
+ unsigned int dtbclk_mhz;
+ unsigned int dispclk_mhz;
+ unsigned int dppclk_mhz;
++ unsigned int dram_speed_mts; /*which is based on wck_ratio*/
+ };
+
+ struct dml2_clks_num_entries {
+--
+2.39.5
+
--- /dev/null
+From e32cbda00592d79dc6d64d5e58c10179ef06e94c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 8 Jan 2025 15:25:41 -0500
+Subject: drm/amd/display: Populate register address for dentist for dcn401
+
+From: Dillon Varone <dillon.varone@amd.com>
+
+[ Upstream commit 5f0d1ef6f16e150ee46cc00b8d233d9d271fe39e ]
+
+[WHY&HOW]
+Address was not previously populated which can result in incorrect
+clock frequencies being read on boot.
+
+Reviewed-by: Alvin Lee <alvin.lee2@amd.com>
+Signed-off-by: Dillon Varone <dillon.varone@amd.com>
+Signed-off-by: Wayne Lin <wayne.lin@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/clk_mgr/dcn401/dcn401_clk_mgr.c | 2 ++
+ drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr_internal.h | 1 +
+ 2 files changed, 3 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn401/dcn401_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn401/dcn401_clk_mgr.c
+index 8082bb8776114..a3b8e3d4a429e 100644
+--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn401/dcn401_clk_mgr.c
++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn401/dcn401_clk_mgr.c
+@@ -24,6 +24,8 @@
+
+ #include "dml/dcn401/dcn401_fpu.h"
+
++#define DCN_BASE__INST0_SEG1 0x000000C0
++
+ #define mmCLK01_CLK0_CLK_PLL_REQ 0x16E37
+ #define mmCLK01_CLK0_CLK0_DFS_CNTL 0x16E69
+ #define mmCLK01_CLK0_CLK1_DFS_CNTL 0x16E6C
+diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr_internal.h b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr_internal.h
+index 7a1ca1e98059b..221645c023b50 100644
+--- a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr_internal.h
++++ b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr_internal.h
+@@ -221,6 +221,7 @@ enum dentist_divider_range {
+ CLK_SF(CLK0_CLK_PLL_REQ, FbMult_frac, mask_sh)
+
+ #define CLK_REG_LIST_DCN401() \
++ SR(DENTIST_DISPCLK_CNTL), \
+ CLK_SR_DCN401(CLK0_CLK_PLL_REQ, CLK01, 0), \
+ CLK_SR_DCN401(CLK0_CLK0_DFS_CNTL, CLK01, 0), \
+ CLK_SR_DCN401(CLK0_CLK1_DFS_CNTL, CLK01, 0), \
+--
+2.39.5
+
--- /dev/null
+From acd1618700d0c4a4278a32968f614751d71b787a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Feb 2025 14:34:02 -0500
+Subject: drm/amd/display: Read LTTPR ALPM caps during link cap retrieval
+
+From: George Shen <george.shen@amd.com>
+
+[ Upstream commit de84d580126eb2214937df755cfec5ef0901479e ]
+
+[Why]
+The latest DP spec requires the DP TX to read DPCD F0000h through F0009h
+when detecting LTTPR capabilities for the first time.
+
+[How]
+Update LTTPR cap retrieval to read up to F0009h (two more bytes than the
+previous F0007h), and store the LTTPR ALPM capabilities.
+
+Reviewed-by: Wenjing Liu <wenjing.liu@amd.com>
+Signed-off-by: George Shen <george.shen@amd.com>
+Signed-off-by: Roman Li <roman.li@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/dc_dp_types.h | 12 ++++++++++++
+ .../display/dc/link/protocols/link_dp_capability.c | 6 +++++-
+ 2 files changed, 17 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
+index cc005da75ce4c..8bb628ab78554 100644
+--- a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
++++ b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
+@@ -959,6 +959,14 @@ union dp_128b_132b_supported_lttpr_link_rates {
+ uint8_t raw;
+ };
+
++union dp_alpm_lttpr_cap {
++ struct {
++ uint8_t AUX_LESS_ALPM_SUPPORTED :1;
++ uint8_t RESERVED :7;
++ } bits;
++ uint8_t raw;
++};
++
+ union dp_sink_video_fallback_formats {
+ struct {
+ uint8_t dp_1024x768_60Hz_24bpp_support :1;
+@@ -1118,6 +1126,7 @@ struct dc_lttpr_caps {
+ uint8_t max_ext_timeout;
+ union dp_main_link_channel_coding_lttpr_cap main_link_channel_coding;
+ union dp_128b_132b_supported_lttpr_link_rates supported_128b_132b_rates;
++ union dp_alpm_lttpr_cap alpm;
+ uint8_t aux_rd_interval[MAX_REPEATER_CNT - 1];
+ uint8_t lttpr_ieee_oui[3];
+ uint8_t lttpr_device_id[6];
+@@ -1372,6 +1381,9 @@ struct dp_trace {
+ #ifndef DPCD_MAX_UNCOMPRESSED_PIXEL_RATE_CAP
+ #define DPCD_MAX_UNCOMPRESSED_PIXEL_RATE_CAP 0x221c
+ #endif
++#ifndef DP_LTTPR_ALPM_CAPABILITIES
++#define DP_LTTPR_ALPM_CAPABILITIES 0xF0009
++#endif
+ #ifndef DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE
+ #define DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE 0x50
+ #endif
+diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c
+index 28843e9882d39..64e4ae379e346 100644
+--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c
++++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c
+@@ -1502,7 +1502,7 @@ static bool dpcd_read_sink_ext_caps(struct dc_link *link)
+
+ enum dc_status dp_retrieve_lttpr_cap(struct dc_link *link)
+ {
+- uint8_t lttpr_dpcd_data[8] = {0};
++ uint8_t lttpr_dpcd_data[10] = {0};
+ enum dc_status status;
+ bool is_lttpr_present;
+
+@@ -1552,6 +1552,10 @@ enum dc_status dp_retrieve_lttpr_cap(struct dc_link *link)
+ lttpr_dpcd_data[DP_PHY_REPEATER_128B132B_RATES -
+ DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
+
++ link->dpcd_caps.lttpr_caps.alpm.raw =
++ lttpr_dpcd_data[DP_LTTPR_ALPM_CAPABILITIES -
++ DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
++
+ /* If this chip cap is set, at least one retimer must exist in the chain
+ * Override count to 1 if we receive a known bad count (0 or an invalid value) */
+ if (((link->chip_caps & AMD_EXT_DISPLAY_PATH_CAPS__EXT_CHIP_MASK) == AMD_EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) &&
+--
+2.39.5
+
--- /dev/null
+From 376417c750d9d4eb845a64da5eb4d735684c31e9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Mar 2025 13:53:16 -0500
+Subject: drm/amd/display: remove minimum Dispclk and apply oem panel timing.
+
+From: Charlene Liu <Charlene.Liu@amd.com>
+
+[ Upstream commit 756e58e83e89d372b94269c0cde61fe55da76947 ]
+
+[why & how]
+1. apply oem panel timing (not only on OLED)
+2. remove MIN_DPP_DISP_CLK request in driver.
+
+This fix will apply for dcn31x but not
+sync with DML's output.
+
+Reviewed-by: Ovidiu Bunea <ovidiu.bunea@amd.com>
+Signed-off-by: Charlene Liu <Charlene.Liu@amd.com>
+Signed-off-by: Tom Chung <chiahsuan.chung@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c | 2 --
+ drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c | 2 --
+ drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c | 3 ++-
+ 3 files changed, 2 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c
+index 827b24b3442ad..e4d22f74f9869 100644
+--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c
++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c
+@@ -194,8 +194,6 @@ static void dcn315_update_clocks(struct clk_mgr *clk_mgr_base,
+ // workaround: Limit dppclk to 100Mhz to avoid lower eDP panel switch to plus 4K monitor underflow.
+ if (new_clocks->dppclk_khz < MIN_DPP_DISP_CLK)
+ new_clocks->dppclk_khz = MIN_DPP_DISP_CLK;
+- if (new_clocks->dispclk_khz < MIN_DPP_DISP_CLK)
+- new_clocks->dispclk_khz = MIN_DPP_DISP_CLK;
+
+ if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr->base.clks.dppclk_khz)) {
+ if (clk_mgr->base.clks.dppclk_khz > new_clocks->dppclk_khz)
+diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c
+index 37c39756fece4..49efea0c8fcff 100644
+--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c
++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c
+@@ -201,8 +201,6 @@ static void dcn316_update_clocks(struct clk_mgr *clk_mgr_base,
+ // workaround: Limit dppclk to 100Mhz to avoid lower eDP panel switch to plus 4K monitor underflow.
+ if (new_clocks->dppclk_khz < 100000)
+ new_clocks->dppclk_khz = 100000;
+- if (new_clocks->dispclk_khz < 100000)
+- new_clocks->dispclk_khz = 100000;
+
+ if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr->base.clks.dppclk_khz)) {
+ if (clk_mgr->base.clks.dppclk_khz > new_clocks->dppclk_khz)
+diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
+index fc4fb4055ab00..94ceccfc04982 100644
+--- a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
++++ b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
+@@ -1065,7 +1065,8 @@ void dce110_edp_backlight_control(
+ DC_LOG_DC("edp_receiver_ready_T9 skipped\n");
+ }
+
+- if (!enable && link->dpcd_sink_ext_caps.bits.oled) {
++ if (!enable) {
++ /*follow oem panel config's requirement*/
+ pre_T11_delay += link->panel_config.pps.extra_pre_t11_ms;
+ msleep(pre_T11_delay);
+ }
+--
+2.39.5
+
--- /dev/null
+From 22c561a70d92fa70cb5db37f649893ac2dfd27d9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jan 2025 18:27:06 -0500
+Subject: drm/amd/display: remove TF check for LLS policy
+
+From: Samson Tam <Samson.Tam@amd.com>
+
+[ Upstream commit 2a4519c4e9b2e1f622ab4c5f5841abdb9760cb0b ]
+
+[Why & How]
+LLS policy not affected by TF.
+Remove check in don't care case and use
+ pixel format only.
+
+Reviewed-by: Navid Assadian <navid.assadian@amd.com>
+Signed-off-by: Samson Tam <Samson.Tam@amd.com>
+Signed-off-by: Aurabindo Pillai <aurabindo.pillai@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/spl/dc_spl.c | 31 +++++----------------
+ 1 file changed, 7 insertions(+), 24 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/spl/dc_spl.c b/drivers/gpu/drm/amd/display/dc/spl/dc_spl.c
+index 153b7a8904e1e..047f05ab01810 100644
+--- a/drivers/gpu/drm/amd/display/dc/spl/dc_spl.c
++++ b/drivers/gpu/drm/amd/display/dc/spl/dc_spl.c
+@@ -784,25 +784,13 @@ static enum scl_mode spl_get_dscl_mode(const struct spl_in *spl_in,
+ return SCL_MODE_SCALING_420_YCBCR_ENABLE;
+ }
+
+-static bool spl_choose_lls_policy(enum spl_pixel_format format,
+- enum spl_transfer_func_type tf_type,
+- enum spl_transfer_func_predefined tf_predefined_type,
++static void spl_choose_lls_policy(enum spl_pixel_format format,
+ enum linear_light_scaling *lls_pref)
+ {
+- if (spl_is_video_format(format)) {
++ if (spl_is_subsampled_format(format))
+ *lls_pref = LLS_PREF_NO;
+- if ((tf_type == SPL_TF_TYPE_PREDEFINED) ||
+- (tf_type == SPL_TF_TYPE_DISTRIBUTED_POINTS))
+- return true;
+- } else { /* RGB or YUV444 */
+- if ((tf_type == SPL_TF_TYPE_PREDEFINED) ||
+- (tf_type == SPL_TF_TYPE_BYPASS)) {
+- *lls_pref = LLS_PREF_YES;
+- return true;
+- }
+- }
+- *lls_pref = LLS_PREF_NO;
+- return false;
++ else /* RGB or YUV444 */
++ *lls_pref = LLS_PREF_YES;
+ }
+
+ /* Enable EASF ?*/
+@@ -811,7 +799,6 @@ static bool enable_easf(struct spl_in *spl_in, struct spl_scratch *spl_scratch)
+ int vratio = 0;
+ int hratio = 0;
+ bool skip_easf = false;
+- bool lls_enable_easf = true;
+
+ if (spl_in->disable_easf)
+ skip_easf = true;
+@@ -827,17 +814,13 @@ static bool enable_easf(struct spl_in *spl_in, struct spl_scratch *spl_scratch)
+ skip_easf = true;
+
+ /*
+- * If lls_pref is LLS_PREF_DONT_CARE, then use pixel format and transfer
+- * function to determine whether to use LINEAR or NONLINEAR scaling
++ * If lls_pref is LLS_PREF_DONT_CARE, then use pixel format
++ * to determine whether to use LINEAR or NONLINEAR scaling
+ */
+ if (spl_in->lls_pref == LLS_PREF_DONT_CARE)
+- lls_enable_easf = spl_choose_lls_policy(spl_in->basic_in.format,
+- spl_in->basic_in.tf_type, spl_in->basic_in.tf_predefined_type,
++ spl_choose_lls_policy(spl_in->basic_in.format,
+ &spl_in->lls_pref);
+
+- if (!lls_enable_easf)
+- skip_easf = true;
+-
+ /* Check for linear scaling or EASF preferred */
+ if (spl_in->lls_pref != LLS_PREF_YES && !spl_in->prefer_easf)
+ skip_easf = true;
+--
+2.39.5
+
--- /dev/null
+From 407cb3bd580cf0a9ae24db7e1981ad819c55f8e1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 23 Jan 2025 16:39:52 -0500
+Subject: drm/amd/display: Request HW cursor on DCN3.2 with SubVP
+
+From: Aric Cyr <Aric.Cyr@amd.com>
+
+[ Upstream commit b74f46f3ce1e5f6336645f1e9ff47c56d5dfdef1 ]
+
+[why]
+When SubVP is active the HW cursor size is limited to 64x64, and
+anything larger will force composition which is bad for gaming on
+DCN3.2 if the game uses a larger cursor.
+
+[how]
+If HW cursor is requested, typically by a fullscreen game, do not
+enable SubVP so that up to 256x256 cursor sizes are available for
+DCN3.2.
+
+Reviewed-by: Aric Cyr <aric.cyr@amd.com>
+Signed-off-by: Aric Cyr <Aric.Cyr@amd.com>
+Signed-off-by: Wayne Lin <wayne.lin@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/core/dc.c | 3 ++-
+ drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c | 1 +
+ 2 files changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
+index 722175e347fdc..167f9d99a5408 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
+@@ -4912,7 +4912,8 @@ static bool full_update_required(struct dc *dc,
+ stream_update->lut3d_func ||
+ stream_update->pending_test_pattern ||
+ stream_update->crtc_timing_adjust ||
+- stream_update->scaler_sharpener_update))
++ stream_update->scaler_sharpener_update ||
++ stream_update->hw_cursor_req))
+ return true;
+
+ if (stream) {
+diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
+index 6f490d8d7038c..56dda686e2992 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
+@@ -626,6 +626,7 @@ static bool dcn32_assign_subvp_pipe(struct dc *dc,
+ * - Not TMZ surface
+ */
+ if (pipe->plane_state && !pipe->top_pipe && !pipe->prev_odm_pipe && !dcn32_is_center_timing(pipe) &&
++ !pipe->stream->hw_cursor_req &&
+ !(pipe->stream->timing.pix_clk_100hz / 10000 > DCN3_2_MAX_SUBVP_PIXEL_RATE_MHZ) &&
+ (!dcn32_is_psr_capable(pipe) || (context->stream_count == 1 && dc->caps.dmub_caps.subvp_psr)) &&
+ dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_NONE &&
+--
+2.39.5
+
--- /dev/null
+From b9369a6077bfd332e8764ef17626f08b3951dd85 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 5 Dec 2024 18:51:25 -0500
+Subject: drm/amd/display: Reverse the visual confirm recouts
+
+From: Peterson Guo <peterson.guo@amd.com>
+
+[ Upstream commit 3c50bf2196aaddcaffe2c7a1a7080470380cbfdd ]
+
+[WHY]
+When checking if a pipe can disable cursor to prevent duplicate cursors,
+having visual confirm on will prevent disabling cursors on planes which
+cover the bottom of the screen.
+
+[HOW]
+When checking if a plane can disable visual confirm, the pipe first
+reverses these calculations before doing the checks.
+
+Reviewed-by: Alvin Lee <alvin.lee2@amd.com>
+Signed-off-by: Peterson Guo <peterson.guo@amd.com>
+Signed-off-by: Wayne Lin <wayne.lin@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../gpu/drm/amd/display/dc/core/dc_resource.c | 67 +++++++++++++++++++
+ drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c | 50 +-------------
+ .../amd/display/dc/hwss/dcn10/dcn10_hwseq.c | 48 +------------
+ .../amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 48 +------------
+ drivers/gpu/drm/amd/display/dc/inc/resource.h | 2 +
+ 5 files changed, 73 insertions(+), 142 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+index 3367030da3414..375b3b1d1d182 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+@@ -941,6 +941,17 @@ static void calculate_adjust_recout_for_visual_confirm(struct pipe_ctx *pipe_ctx
+ *base_offset = VISUAL_CONFIRM_BASE_DEFAULT;
+ }
+
++static void reverse_adjust_recout_for_visual_confirm(struct rect *recout,
++ struct pipe_ctx *pipe_ctx)
++{
++ int dpp_offset, base_offset;
++
++ calculate_adjust_recout_for_visual_confirm(pipe_ctx, &base_offset,
++ &dpp_offset);
++ recout->height += base_offset;
++ recout->height += dpp_offset;
++}
++
+ static void adjust_recout_for_visual_confirm(struct rect *recout,
+ struct pipe_ctx *pipe_ctx)
+ {
+@@ -1642,6 +1653,62 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
+ return res;
+ }
+
++bool resource_can_pipe_disable_cursor(struct pipe_ctx *pipe_ctx)
++{
++ struct pipe_ctx *test_pipe, *split_pipe;
++ struct rect r1 = pipe_ctx->plane_res.scl_data.recout;
++ int r1_right, r1_bottom;
++ int cur_layer = pipe_ctx->plane_state->layer_index;
++
++ reverse_adjust_recout_for_visual_confirm(&r1, pipe_ctx);
++ r1_right = r1.x + r1.width;
++ r1_bottom = r1.y + r1.height;
++
++ /**
++ * Disable the cursor if there's another pipe above this with a
++ * plane that contains this pipe's viewport to prevent double cursor
++ * and incorrect scaling artifacts.
++ */
++ for (test_pipe = pipe_ctx->top_pipe; test_pipe;
++ test_pipe = test_pipe->top_pipe) {
++ struct rect r2;
++ int r2_right, r2_bottom;
++ // Skip invisible layer and pipe-split plane on same layer
++ if (!test_pipe->plane_state ||
++ !test_pipe->plane_state->visible ||
++ test_pipe->plane_state->layer_index == cur_layer)
++ continue;
++
++ r2 = test_pipe->plane_res.scl_data.recout;
++ reverse_adjust_recout_for_visual_confirm(&r2, test_pipe);
++ r2_right = r2.x + r2.width;
++ r2_bottom = r2.y + r2.height;
++
++ /**
++ * There is another half plane on same layer because of
++ * pipe-split, merge together per same height.
++ */
++ for (split_pipe = pipe_ctx->top_pipe; split_pipe;
++ split_pipe = split_pipe->top_pipe)
++ if (split_pipe->plane_state->layer_index == test_pipe->plane_state->layer_index) {
++ struct rect r2_half;
++
++ r2_half = split_pipe->plane_res.scl_data.recout;
++ reverse_adjust_recout_for_visual_confirm(&r2_half, split_pipe);
++ r2.x = min(r2_half.x, r2.x);
++ r2.width = r2.width + r2_half.width;
++ r2_right = r2.x + r2.width;
++ r2_bottom = min(r2_bottom, r2_half.y + r2_half.height);
++ break;
++ }
++
++ if (r1.x >= r2.x && r1.y >= r2.y && r1_right <= r2_right && r1_bottom <= r2_bottom)
++ return true;
++ }
++
++ return false;
++}
++
+
+ enum dc_status resource_build_scaling_params_for_context(
+ const struct dc *dc,
+diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
+index 44ff9abe2880f..87b4c2793df3c 100644
+--- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
++++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
+@@ -991,57 +991,11 @@ void dc_dmub_srv_log_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv)
+ DC_LOG_DEBUG(" is_cw6_en : %d", diag_data.is_cw6_enabled);
+ }
+
+-static bool dc_can_pipe_disable_cursor(struct pipe_ctx *pipe_ctx)
+-{
+- struct pipe_ctx *test_pipe, *split_pipe;
+- const struct scaler_data *scl_data = &pipe_ctx->plane_res.scl_data;
+- struct rect r1 = scl_data->recout, r2, r2_half;
+- int r1_r = r1.x + r1.width, r1_b = r1.y + r1.height, r2_r, r2_b;
+- int cur_layer = pipe_ctx->plane_state->layer_index;
+-
+- /**
+- * Disable the cursor if there's another pipe above this with a
+- * plane that contains this pipe's viewport to prevent double cursor
+- * and incorrect scaling artifacts.
+- */
+- for (test_pipe = pipe_ctx->top_pipe; test_pipe;
+- test_pipe = test_pipe->top_pipe) {
+- // Skip invisible layer and pipe-split plane on same layer
+- if (!test_pipe->plane_state->visible || test_pipe->plane_state->layer_index == cur_layer)
+- continue;
+-
+- r2 = test_pipe->plane_res.scl_data.recout;
+- r2_r = r2.x + r2.width;
+- r2_b = r2.y + r2.height;
+-
+- /**
+- * There is another half plane on same layer because of
+- * pipe-split, merge together per same height.
+- */
+- for (split_pipe = pipe_ctx->top_pipe; split_pipe;
+- split_pipe = split_pipe->top_pipe)
+- if (split_pipe->plane_state->layer_index == test_pipe->plane_state->layer_index) {
+- r2_half = split_pipe->plane_res.scl_data.recout;
+- r2.x = (r2_half.x < r2.x) ? r2_half.x : r2.x;
+- r2.width = r2.width + r2_half.width;
+- r2_r = r2.x + r2.width;
+- break;
+- }
+-
+- if (r1.x >= r2.x && r1.y >= r2.y && r1_r <= r2_r && r1_b <= r2_b)
+- return true;
+- }
+-
+- return false;
+-}
+-
+ static bool dc_dmub_should_update_cursor_data(struct pipe_ctx *pipe_ctx)
+ {
+ if (pipe_ctx->plane_state != NULL) {
+- if (pipe_ctx->plane_state->address.type == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE)
+- return false;
+-
+- if (dc_can_pipe_disable_cursor(pipe_ctx))
++ if (pipe_ctx->plane_state->address.type == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE ||
++ resource_can_pipe_disable_cursor(pipe_ctx))
+ return false;
+ }
+
+diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
+index 4c89bf6725b3b..bbeaefe1ef0db 100644
+--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
+@@ -3424,52 +3424,6 @@ void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data)
+ hubbub->funcs->update_dchub(hubbub, dh_data);
+ }
+
+-static bool dcn10_can_pipe_disable_cursor(struct pipe_ctx *pipe_ctx)
+-{
+- struct pipe_ctx *test_pipe, *split_pipe;
+- const struct scaler_data *scl_data = &pipe_ctx->plane_res.scl_data;
+- struct rect r1 = scl_data->recout, r2, r2_half;
+- int r1_r = r1.x + r1.width, r1_b = r1.y + r1.height, r2_r, r2_b;
+- int cur_layer = pipe_ctx->plane_state->layer_index;
+-
+- /**
+- * Disable the cursor if there's another pipe above this with a
+- * plane that contains this pipe's viewport to prevent double cursor
+- * and incorrect scaling artifacts.
+- */
+- for (test_pipe = pipe_ctx->top_pipe; test_pipe;
+- test_pipe = test_pipe->top_pipe) {
+- // Skip invisible layer and pipe-split plane on same layer
+- if (!test_pipe->plane_state ||
+- !test_pipe->plane_state->visible ||
+- test_pipe->plane_state->layer_index == cur_layer)
+- continue;
+-
+- r2 = test_pipe->plane_res.scl_data.recout;
+- r2_r = r2.x + r2.width;
+- r2_b = r2.y + r2.height;
+-
+- /**
+- * There is another half plane on same layer because of
+- * pipe-split, merge together per same height.
+- */
+- for (split_pipe = pipe_ctx->top_pipe; split_pipe;
+- split_pipe = split_pipe->top_pipe)
+- if (split_pipe->plane_state->layer_index == test_pipe->plane_state->layer_index) {
+- r2_half = split_pipe->plane_res.scl_data.recout;
+- r2.x = (r2_half.x < r2.x) ? r2_half.x : r2.x;
+- r2.width = r2.width + r2_half.width;
+- r2_r = r2.x + r2.width;
+- break;
+- }
+-
+- if (r1.x >= r2.x && r1.y >= r2.y && r1_r <= r2_r && r1_b <= r2_b)
+- return true;
+- }
+-
+- return false;
+-}
+-
+ void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx)
+ {
+ struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position;
+@@ -3569,7 +3523,7 @@ void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx)
+ == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE)
+ pos_cpy.enable = false;
+
+- if (pos_cpy.enable && dcn10_can_pipe_disable_cursor(pipe_ctx))
++ if (pos_cpy.enable && resource_can_pipe_disable_cursor(pipe_ctx))
+ pos_cpy.enable = false;
+
+
+diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
+index a6f2aff84267d..da8afb08b9201 100644
+--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
+@@ -972,52 +972,6 @@ void dcn401_setup_hpo_hw_control(const struct dce_hwseq *hws, bool enable)
+ REG_UPDATE(HPO_TOP_HW_CONTROL, HPO_IO_EN, enable);
+ }
+
+-static bool dcn401_can_pipe_disable_cursor(struct pipe_ctx *pipe_ctx)
+-{
+- struct pipe_ctx *test_pipe, *split_pipe;
+- const struct scaler_data *scl_data = &pipe_ctx->plane_res.scl_data;
+- struct rect r1 = scl_data->recout, r2, r2_half;
+- int r1_r = r1.x + r1.width, r1_b = r1.y + r1.height, r2_r, r2_b;
+- int cur_layer = pipe_ctx->plane_state->layer_index;
+-
+- /**
+- * Disable the cursor if there's another pipe above this with a
+- * plane that contains this pipe's viewport to prevent double cursor
+- * and incorrect scaling artifacts.
+- */
+- for (test_pipe = pipe_ctx->top_pipe; test_pipe;
+- test_pipe = test_pipe->top_pipe) {
+- // Skip invisible layer and pipe-split plane on same layer
+- if (!test_pipe->plane_state ||
+- !test_pipe->plane_state->visible ||
+- test_pipe->plane_state->layer_index == cur_layer)
+- continue;
+-
+- r2 = test_pipe->plane_res.scl_data.recout;
+- r2_r = r2.x + r2.width;
+- r2_b = r2.y + r2.height;
+-
+- /**
+- * There is another half plane on same layer because of
+- * pipe-split, merge together per same height.
+- */
+- for (split_pipe = pipe_ctx->top_pipe; split_pipe;
+- split_pipe = split_pipe->top_pipe)
+- if (split_pipe->plane_state->layer_index == test_pipe->plane_state->layer_index) {
+- r2_half = split_pipe->plane_res.scl_data.recout;
+- r2.x = (r2_half.x < r2.x) ? r2_half.x : r2.x;
+- r2.width = r2.width + r2_half.width;
+- r2_r = r2.x + r2.width;
+- break;
+- }
+-
+- if (r1.x >= r2.x && r1.y >= r2.y && r1_r <= r2_r && r1_b <= r2_b)
+- return true;
+- }
+-
+- return false;
+-}
+-
+ void adjust_hotspot_between_slices_for_2x_magnify(uint32_t cursor_width, struct dc_cursor_position *pos_cpy)
+ {
+ if (cursor_width <= 128) {
+@@ -1208,7 +1162,7 @@ void dcn401_set_cursor_position(struct pipe_ctx *pipe_ctx)
+ pos_cpy.x = (uint32_t)x_pos;
+ pos_cpy.y = (uint32_t)y_pos;
+
+- if (pos_cpy.enable && dcn401_can_pipe_disable_cursor(pipe_ctx))
++ if (pos_cpy.enable && resource_can_pipe_disable_cursor(pipe_ctx))
+ pos_cpy.enable = false;
+
+ x_pos = pos_cpy.x - param.recout.x;
+diff --git a/drivers/gpu/drm/amd/display/dc/inc/resource.h b/drivers/gpu/drm/amd/display/dc/inc/resource.h
+index cd1157d225abe..b32d07ce0f087 100644
+--- a/drivers/gpu/drm/amd/display/dc/inc/resource.h
++++ b/drivers/gpu/drm/amd/display/dc/inc/resource.h
+@@ -152,6 +152,8 @@ bool resource_attach_surfaces_to_context(
+ struct dc_state *context,
+ const struct resource_pool *pool);
+
++bool resource_can_pipe_disable_cursor(struct pipe_ctx *pipe_ctx);
++
+ #define FREE_PIPE_INDEX_NOT_FOUND -1
+
+ /*
+--
+2.39.5
+
--- /dev/null
+From d0223a85cdaa761da8c2c41d607b2cd480796383 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 14 Feb 2025 22:00:13 -0500
+Subject: drm/amd/display: Skip checking FRL_MODE bit for PCON BW determination
+
+From: George Shen <george.shen@amd.com>
+
+[ Upstream commit 0584bbcf0c53c133081100e4f4c9fe41e598d045 ]
+
+[Why/How]
+Certain PCON will clear the FRL_MODE bit despite supporting the link BW
+indicated in the other bits.
+
+Thus, skip checking the FRL_MODE bit when interpreting the
+hdmi_encoded_link_bw struct.
+
+Reviewed-by: Wenjing Liu <wenjing.liu@amd.com>
+Signed-off-by: George Shen <george.shen@amd.com>
+Signed-off-by: Wayne Lin <wayne.lin@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../dc/link/protocols/link_dp_capability.c | 30 +++++++++----------
+ 1 file changed, 15 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c
+index 44f33e3bc1c59..6d7131369f00b 100644
+--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c
++++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c
+@@ -250,21 +250,21 @@ static uint32_t intersect_frl_link_bw_support(
+ {
+ uint32_t supported_bw_in_kbps = max_supported_frl_bw_in_kbps;
+
+- // HDMI_ENCODED_LINK_BW bits are only valid if HDMI Link Configuration bit is 1 (FRL mode)
+- if (hdmi_encoded_link_bw.bits.FRL_MODE) {
+- if (hdmi_encoded_link_bw.bits.BW_48Gbps)
+- supported_bw_in_kbps = 48000000;
+- else if (hdmi_encoded_link_bw.bits.BW_40Gbps)
+- supported_bw_in_kbps = 40000000;
+- else if (hdmi_encoded_link_bw.bits.BW_32Gbps)
+- supported_bw_in_kbps = 32000000;
+- else if (hdmi_encoded_link_bw.bits.BW_24Gbps)
+- supported_bw_in_kbps = 24000000;
+- else if (hdmi_encoded_link_bw.bits.BW_18Gbps)
+- supported_bw_in_kbps = 18000000;
+- else if (hdmi_encoded_link_bw.bits.BW_9Gbps)
+- supported_bw_in_kbps = 9000000;
+- }
++ /* Skip checking FRL_MODE bit, as certain PCON will clear
++ * it despite supporting the link BW indicated in the other bits.
++ */
++ if (hdmi_encoded_link_bw.bits.BW_48Gbps)
++ supported_bw_in_kbps = 48000000;
++ else if (hdmi_encoded_link_bw.bits.BW_40Gbps)
++ supported_bw_in_kbps = 40000000;
++ else if (hdmi_encoded_link_bw.bits.BW_32Gbps)
++ supported_bw_in_kbps = 32000000;
++ else if (hdmi_encoded_link_bw.bits.BW_24Gbps)
++ supported_bw_in_kbps = 24000000;
++ else if (hdmi_encoded_link_bw.bits.BW_18Gbps)
++ supported_bw_in_kbps = 18000000;
++ else if (hdmi_encoded_link_bw.bits.BW_9Gbps)
++ supported_bw_in_kbps = 9000000;
+
+ return supported_bw_in_kbps;
+ }
+--
+2.39.5
+
--- /dev/null
+From 074d8af3e2defc78c6b439711acd17da1a3e6a78 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 20 Jan 2025 11:21:46 +0800
+Subject: drm/amd/display: Support multiple options during psr entry.
+
+From: Martin Tsai <Martin.Tsai@amd.com>
+
+[ Upstream commit 3a5fa55455db6a11248a25f24570c365f9246144 ]
+
+[WHY]
+Some panels may not handle idle pattern properly during PSR entry.
+
+[HOW]
+Add a condition to allow multiple options on power down
+sequence during PSR1 entry.
+
+Reviewed-by: Anthony Koo <anthony.koo@amd.com>
+Signed-off-by: Martin Tsai <Martin.Tsai@amd.com>
+Signed-off-by: Alex Hung <alex.hung@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/dc_types.h | 7 +++++++
+ drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c | 4 ++++
+ drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 6 ++++++
+ 3 files changed, 17 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h
+index 0c2aa91f0a111..e60898c2df01a 100644
+--- a/drivers/gpu/drm/amd/display/dc/dc_types.h
++++ b/drivers/gpu/drm/amd/display/dc/dc_types.h
+@@ -1033,6 +1033,13 @@ struct psr_settings {
+ unsigned int psr_sdp_transmit_line_num_deadline;
+ uint8_t force_ffu_mode;
+ unsigned int psr_power_opt;
++
++ /**
++ * Some panels cannot handle idle pattern during PSR entry.
++ * To power down phy before disable stream to avoid sending
++ * idle pattern.
++ */
++ uint8_t power_down_phy_before_disable_stream;
+ };
+
+ enum replay_coasting_vtotal_type {
+diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c
+index 88c75c243bf8a..ff3b8244ba3d0 100644
+--- a/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c
++++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c
+@@ -418,6 +418,10 @@ static bool dmub_psr_copy_settings(struct dmub_psr *dmub,
+ copy_settings_data->relock_delay_frame_cnt = 0;
+ if (link->dpcd_caps.sink_dev_id == DP_BRANCH_DEVICE_ID_001CF8)
+ copy_settings_data->relock_delay_frame_cnt = 2;
++
++ copy_settings_data->power_down_phy_before_disable_stream =
++ link->psr_settings.power_down_phy_before_disable_stream;
++
+ copy_settings_data->dsc_slice_height = psr_context->dsc_slice_height;
+
+ dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
+diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
+index d0fe324cb5371..8cf89aed024b7 100644
+--- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
++++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
+@@ -3118,6 +3118,12 @@ struct dmub_cmd_psr_copy_settings_data {
+ * Some panels request main link off before xth vertical line
+ */
+ uint16_t poweroff_before_vertical_line;
++ /**
++ * Some panels cannot handle idle pattern during PSR entry.
++ * To power down phy before disable stream to avoid sending
++ * idle pattern.
++ */
++ uint8_t power_down_phy_before_disable_stream;
+ };
+
+ /**
+--
+2.39.5
+
--- /dev/null
+From c4ff5cbc1c826c0bf0359346d362c61e308541f3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 10 Jan 2025 11:35:46 -0500
+Subject: drm/amd/display: Update CR AUX RD interval interpretation
+
+From: George Shen <george.shen@amd.com>
+
+[ Upstream commit 6a7fde433231c18164c117592d3e18ced648ad58 ]
+
+[Why]
+DP spec updated to have the CR AUX RD interval match the EQ AUX RD
+interval interpretation of DPCD 0000Eh/0220Eh for 8b/10b non-LTTPR mode
+and LTTPR transparent mode cases.
+
+[How]
+Update interpretation of DPCD 0000Eh/0220Eh for CR AUX RD interval
+during 8b/10b link training.
+
+Reviewed-by: Michael Strauss <michael.strauss@amd.com>
+Reviewed-by: Wenjing Liu <wenjing.liu@amd.com>
+Signed-off-by: George Shen <george.shen@amd.com>
+Signed-off-by: Zaeem Mohamed <zaeem.mohamed@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../display/dc/link/protocols/link_dp_training_8b_10b.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_8b_10b.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_8b_10b.c
+index 3bdce32a85e3c..ae95ec48e5721 100644
+--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_8b_10b.c
++++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_8b_10b.c
+@@ -36,7 +36,8 @@
+ link->ctx->logger
+
+ static int32_t get_cr_training_aux_rd_interval(struct dc_link *link,
+- const struct dc_link_settings *link_settings)
++ const struct dc_link_settings *link_settings,
++ enum lttpr_mode lttpr_mode)
+ {
+ union training_aux_rd_interval training_rd_interval;
+ uint32_t wait_in_micro_secs = 100;
+@@ -49,6 +50,8 @@ static int32_t get_cr_training_aux_rd_interval(struct dc_link *link,
+ DP_TRAINING_AUX_RD_INTERVAL,
+ (uint8_t *)&training_rd_interval,
+ sizeof(training_rd_interval));
++ if (lttpr_mode != LTTPR_MODE_NON_TRANSPARENT)
++ wait_in_micro_secs = 400;
+ if (training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL)
+ wait_in_micro_secs = training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL * 4000;
+ }
+@@ -110,7 +113,6 @@ void decide_8b_10b_training_settings(
+ */
+ lt_settings->link_settings.link_spread = link->dp_ss_off ?
+ LINK_SPREAD_DISABLED : LINK_SPREAD_05_DOWNSPREAD_30KHZ;
+- lt_settings->cr_pattern_time = get_cr_training_aux_rd_interval(link, link_setting);
+ lt_settings->eq_pattern_time = get_eq_training_aux_rd_interval(link, link_setting);
+ lt_settings->pattern_for_cr = decide_cr_training_pattern(link_setting);
+ lt_settings->pattern_for_eq = decide_eq_training_pattern(link, link_setting);
+@@ -119,6 +121,7 @@ void decide_8b_10b_training_settings(
+ lt_settings->disallow_per_lane_settings = true;
+ lt_settings->always_match_dpcd_with_hw_lane_settings = true;
+ lt_settings->lttpr_mode = dp_decide_8b_10b_lttpr_mode(link);
++ lt_settings->cr_pattern_time = get_cr_training_aux_rd_interval(link, link_setting, lt_settings->lttpr_mode);
+ dp_hw_to_dpcd_lane_settings(lt_settings, lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
+ }
+
+--
+2.39.5
+
--- /dev/null
+From 0af786cc9408dbba5afaa59b43f135f256bdeb6d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 7 Jan 2025 17:49:36 -0500
+Subject: drm/amd/display: Use Nominal vBlank If Provided Instead Of Capping It
+
+From: Austin Zheng <Austin.Zheng@amd.com>
+
+[ Upstream commit 41df56b1fc24cc36fffb10e437385b3a49fbb5e2 ]
+
+[Why/How]
+vBlank used to determine the max vStartup is based on the smallest between
+the vblank provided by the timing and vblank in ip_caps.
+Extra vblank time is not considered if the vblank provided by the timing ends
+up being higher than what's defined by the ip_caps
+
+Use 1 less than the vblank size in case the timing is interlaced
+so vstartup will always be less than vblank_nom.
+
+Reviewed-by: Dillon Varone <dillon.varone@amd.com>
+Signed-off-by: Austin Zheng <Austin.Zheng@amd.com>
+Signed-off-by: Wayne Lin <wayne.lin@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c b/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c
+index 913f33c31cf38..a72b4c05e1fbf 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c
++++ b/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c
+@@ -3713,13 +3713,12 @@ static unsigned int CalculateMaxVStartup(
+ double line_time_us = (double)timing->h_total / ((double)timing->pixel_clock_khz / 1000);
+ unsigned int vblank_actual = timing->v_total - timing->v_active;
+ unsigned int vblank_nom_default_in_line = (unsigned int)math_floor2((double)vblank_nom_default_us / line_time_us, 1.0);
+- unsigned int vblank_nom_input = (unsigned int)math_min2(timing->vblank_nom, vblank_nom_default_in_line);
+- unsigned int vblank_avail = (vblank_nom_input == 0) ? vblank_nom_default_in_line : vblank_nom_input;
++ unsigned int vblank_avail = (timing->vblank_nom == 0) ? vblank_nom_default_in_line : (unsigned int)timing->vblank_nom;
+
+ vblank_size = (unsigned int)math_min2(vblank_actual, vblank_avail);
+
+ if (timing->interlaced && !ptoi_supported)
+- max_vstartup_lines = (unsigned int)(math_floor2(vblank_size / 2.0, 1.0));
++ max_vstartup_lines = (unsigned int)(math_floor2((vblank_size - 1) / 2.0, 1.0));
+ else
+ max_vstartup_lines = vblank_size - (unsigned int)math_max2(1.0, math_ceil2(write_back_delay_us / line_time_us, 1.0));
+ #ifdef __DML_VBA_DEBUG__
+--
+2.39.5
+
--- /dev/null
+From efd02a91000dab42c895ab5b4ee3d4d4748411da Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Feb 2025 17:43:01 +0530
+Subject: drm/amd/pm: Fetch current power limit from PMFW
+
+From: Lijo Lazar <lijo.lazar@amd.com>
+
+[ Upstream commit b2a9e562dfa156bd53e62ce571f3f8f65d243f14 ]
+
+On SMU v13.0.12, always query the firmware to get the current power
+limit as it could be updated through other means also.
+
+Signed-off-by: Lijo Lazar <lijo.lazar@amd.com>
+Reviewed-by: Asad Kamal <asad.kamal@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
+index ed9dac00ebfb1..f3f5b7dd15ccc 100644
+--- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
++++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
+@@ -2802,6 +2802,7 @@ int smu_get_power_limit(void *handle,
+ switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) {
+ case IP_VERSION(13, 0, 2):
+ case IP_VERSION(13, 0, 6):
++ case IP_VERSION(13, 0, 12):
+ case IP_VERSION(13, 0, 14):
+ case IP_VERSION(11, 0, 7):
+ case IP_VERSION(11, 0, 11):
+--
+2.39.5
+
--- /dev/null
+From c02e63e0d9f6534a519ade21153b7052bebefd41 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 19 Dec 2024 19:16:37 +0800
+Subject: drm/amd/pm: Skip P2S load for SMU v13.0.12
+
+From: Asad Kamal <asad.kamal@amd.com>
+
+[ Upstream commit 1fb85819d629676f1d53f40c3fffa25a33a881e4 ]
+
+Skip P2S table load for SMU v13.0.12
+
+Signed-off-by: Asad Kamal <asad.kamal@amd.com>
+Reviewed-by: Lijo Lazar <lijo.lazar@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c
+index da7bd9227afeb..5f2a824918e3b 100644
+--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c
++++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c
+@@ -450,8 +450,9 @@ static int smu_v13_0_6_init_microcode(struct smu_context *smu)
+ int var = (adev->pdev->device & 0xF);
+ char ucode_prefix[15];
+
+- /* No need to load P2S tables in IOV mode */
+- if (amdgpu_sriov_vf(adev))
++ /* No need to load P2S tables in IOV mode or for smu v13.0.12 */
++ if (amdgpu_sriov_vf(adev) ||
++ (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 12)))
+ return 0;
+
+ if (!(adev->flags & AMD_IS_APU)) {
+--
+2.39.5
+
--- /dev/null
+From 1c2c44642f12b5c84c61e60074e9611c759dd16a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 28 Feb 2025 23:11:20 -0500
+Subject: drm/amdgpu: add dce_v6_0_soft_reset() to DCE6
+
+From: Alexandre Demers <alexandre.f.demers@gmail.com>
+
+[ Upstream commit ab23db6d08efdda5d13d01a66c593d0e57f8917f ]
+
+DCE6 was missing soft reset, but it was easily identifiable under radeon.
+This should be it, pretty much as it is done under DCE8 and DCE10.
+
+Signed-off-by: Alexandre Demers <alexandre.f.demers@gmail.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/dce_v6_0.c | 53 ++++++++++++++++++++++++++-
+ 1 file changed, 51 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
+index 915804a6a1d7d..ed5e06b677df1 100644
+--- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
+@@ -370,13 +370,41 @@ static u32 dce_v6_0_hpd_get_gpio_reg(struct amdgpu_device *adev)
+ return mmDC_GPIO_HPD_A;
+ }
+
++static bool dce_v6_0_is_display_hung(struct amdgpu_device *adev)
++{
++ u32 crtc_hung = 0;
++ u32 crtc_status[6];
++ u32 i, j, tmp;
++
++ for (i = 0; i < adev->mode_info.num_crtc; i++) {
++ if (RREG32(mmCRTC_CONTROL + crtc_offsets[i]) & CRTC_CONTROL__CRTC_MASTER_EN_MASK) {
++ crtc_status[i] = RREG32(mmCRTC_STATUS_HV_COUNT + crtc_offsets[i]);
++ crtc_hung |= (1 << i);
++ }
++ }
++
++ for (j = 0; j < 10; j++) {
++ for (i = 0; i < adev->mode_info.num_crtc; i++) {
++ if (crtc_hung & (1 << i)) {
++ tmp = RREG32(mmCRTC_STATUS_HV_COUNT + crtc_offsets[i]);
++ if (tmp != crtc_status[i])
++ crtc_hung &= ~(1 << i);
++ }
++ }
++ if (crtc_hung == 0)
++ return false;
++ udelay(100);
++ }
++
++ return true;
++}
++
+ static void dce_v6_0_set_vga_render_state(struct amdgpu_device *adev,
+ bool render)
+ {
+ if (!render)
+ WREG32(mmVGA_RENDER_CONTROL,
+ RREG32(mmVGA_RENDER_CONTROL) & VGA_VSTATUS_CNTL);
+-
+ }
+
+ static int dce_v6_0_get_num_crtc(struct amdgpu_device *adev)
+@@ -2872,7 +2900,28 @@ static bool dce_v6_0_is_idle(void *handle)
+
+ static int dce_v6_0_soft_reset(struct amdgpu_ip_block *ip_block)
+ {
+- DRM_INFO("xxxx: dce_v6_0_soft_reset --- no impl!!\n");
++ u32 srbm_soft_reset = 0, tmp;
++ struct amdgpu_device *adev = ip_block->adev;
++
++ if (dce_v6_0_is_display_hung(adev))
++ srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_DC_MASK;
++
++ if (srbm_soft_reset) {
++ tmp = RREG32(mmSRBM_SOFT_RESET);
++ tmp |= srbm_soft_reset;
++ dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp);
++ WREG32(mmSRBM_SOFT_RESET, tmp);
++ tmp = RREG32(mmSRBM_SOFT_RESET);
++
++ udelay(50);
++
++ tmp &= ~srbm_soft_reset;
++ WREG32(mmSRBM_SOFT_RESET, tmp);
++ tmp = RREG32(mmSRBM_SOFT_RESET);
++
++ /* Wait a little for things to settle down */
++ udelay(50);
++ }
+ return 0;
+ }
+
+--
+2.39.5
+
--- /dev/null
+From 409b0097dfe7df3c64aa2be27a4250c00e97a66f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 20 Feb 2025 13:40:31 +0530
+Subject: drm/amdgpu: Add offset normalization in VCN v5.0.1
+
+From: Lijo Lazar <lijo.lazar@amd.com>
+
+[ Upstream commit 0b9647d40ef82837d5025de6daad64db775ea1c5 ]
+
+VCN v5.0.1 also will need register offset normalization. Reuse the logic
+from VCN v4.0.3. Also, avoid HDP flush similar to VCN v4.0.3
+
+Signed-off-by: Lijo Lazar <lijo.lazar@amd.com>
+Reviewed-by: Hawking Zhang <Hawking.Zhang@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c | 14 ++++++++------
+ drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.h | 9 +++++++++
+ drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c | 20 +++++++++++---------
+ 3 files changed, 28 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
+index a2d1a4b2f03a5..855da1149c5c8 100644
+--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
+@@ -31,6 +31,7 @@
+ #include "soc15d.h"
+ #include "soc15_hw_ip.h"
+ #include "vcn_v2_0.h"
++#include "vcn_v4_0_3.h"
+ #include "mmsch_v4_0_3.h"
+
+ #include "vcn/vcn_4_0_3_offset.h"
+@@ -1462,8 +1463,8 @@ static uint64_t vcn_v4_0_3_unified_ring_get_wptr(struct amdgpu_ring *ring)
+ regUVD_RB_WPTR);
+ }
+
+-static void vcn_v4_0_3_enc_ring_emit_reg_wait(struct amdgpu_ring *ring, uint32_t reg,
+- uint32_t val, uint32_t mask)
++void vcn_v4_0_3_enc_ring_emit_reg_wait(struct amdgpu_ring *ring, uint32_t reg,
++ uint32_t val, uint32_t mask)
+ {
+ /* Use normalized offsets when required */
+ if (vcn_v4_0_3_normalizn_reqd(ring->adev))
+@@ -1475,7 +1476,8 @@ static void vcn_v4_0_3_enc_ring_emit_reg_wait(struct amdgpu_ring *ring, uint32_t
+ amdgpu_ring_write(ring, val);
+ }
+
+-static void vcn_v4_0_3_enc_ring_emit_wreg(struct amdgpu_ring *ring, uint32_t reg, uint32_t val)
++void vcn_v4_0_3_enc_ring_emit_wreg(struct amdgpu_ring *ring, uint32_t reg,
++ uint32_t val)
+ {
+ /* Use normalized offsets when required */
+ if (vcn_v4_0_3_normalizn_reqd(ring->adev))
+@@ -1486,8 +1488,8 @@ static void vcn_v4_0_3_enc_ring_emit_wreg(struct amdgpu_ring *ring, uint32_t reg
+ amdgpu_ring_write(ring, val);
+ }
+
+-static void vcn_v4_0_3_enc_ring_emit_vm_flush(struct amdgpu_ring *ring,
+- unsigned int vmid, uint64_t pd_addr)
++void vcn_v4_0_3_enc_ring_emit_vm_flush(struct amdgpu_ring *ring,
++ unsigned int vmid, uint64_t pd_addr)
+ {
+ struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->vm_hub];
+
+@@ -1499,7 +1501,7 @@ static void vcn_v4_0_3_enc_ring_emit_vm_flush(struct amdgpu_ring *ring,
+ lower_32_bits(pd_addr), 0xffffffff);
+ }
+
+-static void vcn_v4_0_3_ring_emit_hdp_flush(struct amdgpu_ring *ring)
++void vcn_v4_0_3_ring_emit_hdp_flush(struct amdgpu_ring *ring)
+ {
+ /* VCN engine access for HDP flush doesn't work when RRMT is enabled.
+ * This is a workaround to avoid any HDP flush through VCN ring.
+diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.h b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.h
+index 0b046114373ae..03572a1d0c9cb 100644
+--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.h
++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.h
+@@ -26,4 +26,13 @@
+
+ extern const struct amdgpu_ip_block_version vcn_v4_0_3_ip_block;
+
++void vcn_v4_0_3_enc_ring_emit_reg_wait(struct amdgpu_ring *ring, uint32_t reg,
++ uint32_t val, uint32_t mask);
++
++void vcn_v4_0_3_enc_ring_emit_wreg(struct amdgpu_ring *ring, uint32_t reg,
++ uint32_t val);
++void vcn_v4_0_3_enc_ring_emit_vm_flush(struct amdgpu_ring *ring,
++ unsigned int vmid, uint64_t pd_addr);
++void vcn_v4_0_3_ring_emit_hdp_flush(struct amdgpu_ring *ring);
++
+ #endif /* __VCN_V4_0_3_H__ */
+diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c
+index cdbc10d7c9fb7..f893a84282832 100644
+--- a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c
++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c
+@@ -29,6 +29,7 @@
+ #include "soc15d.h"
+ #include "soc15_hw_ip.h"
+ #include "vcn_v2_0.h"
++#include "vcn_v4_0_3.h"
+
+ #include "vcn/vcn_5_0_0_offset.h"
+ #include "vcn/vcn_5_0_0_sh_mask.h"
+@@ -905,16 +906,17 @@ static const struct amdgpu_ring_funcs vcn_v5_0_1_unified_ring_vm_funcs = {
+ .get_rptr = vcn_v5_0_1_unified_ring_get_rptr,
+ .get_wptr = vcn_v5_0_1_unified_ring_get_wptr,
+ .set_wptr = vcn_v5_0_1_unified_ring_set_wptr,
+- .emit_frame_size =
+- SOC15_FLUSH_GPU_TLB_NUM_WREG * 3 +
+- SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 4 +
+- 4 + /* vcn_v2_0_enc_ring_emit_vm_flush */
+- 5 + 5 + /* vcn_v2_0_enc_ring_emit_fence x2 vm fence */
+- 1, /* vcn_v2_0_enc_ring_insert_end */
++ .emit_frame_size = SOC15_FLUSH_GPU_TLB_NUM_WREG * 3 +
++ SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 4 +
++ 4 + /* vcn_v2_0_enc_ring_emit_vm_flush */
++ 5 +
++ 5 + /* vcn_v2_0_enc_ring_emit_fence x2 vm fence */
++ 1, /* vcn_v2_0_enc_ring_insert_end */
+ .emit_ib_size = 5, /* vcn_v2_0_enc_ring_emit_ib */
+ .emit_ib = vcn_v2_0_enc_ring_emit_ib,
+ .emit_fence = vcn_v2_0_enc_ring_emit_fence,
+- .emit_vm_flush = vcn_v2_0_enc_ring_emit_vm_flush,
++ .emit_vm_flush = vcn_v4_0_3_enc_ring_emit_vm_flush,
++ .emit_hdp_flush = vcn_v4_0_3_ring_emit_hdp_flush,
+ .test_ring = amdgpu_vcn_enc_ring_test_ring,
+ .test_ib = amdgpu_vcn_unified_ring_test_ib,
+ .insert_nop = amdgpu_ring_insert_nop,
+@@ -922,8 +924,8 @@ static const struct amdgpu_ring_funcs vcn_v5_0_1_unified_ring_vm_funcs = {
+ .pad_ib = amdgpu_ring_generic_pad_ib,
+ .begin_use = amdgpu_vcn_ring_begin_use,
+ .end_use = amdgpu_vcn_ring_end_use,
+- .emit_wreg = vcn_v2_0_enc_ring_emit_wreg,
+- .emit_reg_wait = vcn_v2_0_enc_ring_emit_reg_wait,
++ .emit_wreg = vcn_v4_0_3_enc_ring_emit_wreg,
++ .emit_reg_wait = vcn_v4_0_3_enc_ring_emit_reg_wait,
+ .emit_reg_write_reg_wait = amdgpu_ring_emit_reg_write_reg_wait_helper,
+ };
+
+--
+2.39.5
+
--- /dev/null
+From 21d69279617ffebaa8e8d958b4df338c6e1ff3c1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 13 Mar 2025 20:52:38 -0400
+Subject: drm/amdgpu: adjust drm_firmware_drivers_only() handling
+
+From: Alex Deucher <alexander.deucher@amd.com>
+
+[ Upstream commit e00e5c223878a60e391e5422d173c3382d378f87 ]
+
+Move to probe so we can check the PCI device type and
+only apply the drm_firmware_drivers_only() check for
+PCI DISPLAY classes. Also add a module parameter to
+override the nomodeset kernel parameter as a workaround
+for platforms that have this hardcoded on their kernel
+command lines.
+
+Reviewed-by: Kent Russell <kent.russell@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+index bb8ab25ea76ad..e4ce33e69a48b 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+@@ -173,6 +173,7 @@ uint amdgpu_sdma_phase_quantum = 32;
+ char *amdgpu_disable_cu;
+ char *amdgpu_virtual_display;
+ bool enforce_isolation;
++int amdgpu_modeset = -1;
+
+ /* Specifies the default granularity for SVM, used in buffer
+ * migration and restoration of backing memory when handling
+@@ -1033,6 +1034,13 @@ module_param_named(user_partt_mode, amdgpu_user_partt_mode, uint, 0444);
+ module_param(enforce_isolation, bool, 0444);
+ MODULE_PARM_DESC(enforce_isolation, "enforce process isolation between graphics and compute . enforce_isolation = on");
+
++/**
++ * DOC: modeset (int)
++ * Override nomodeset (1 = override, -1 = auto). The default is -1 (auto).
++ */
++MODULE_PARM_DESC(modeset, "Override nomodeset (1 = enable, -1 = auto)");
++module_param_named(modeset, amdgpu_modeset, int, 0444);
++
+ /**
+ * DOC: seamless (int)
+ * Seamless boot will keep the image on the screen during the boot process.
+@@ -2244,6 +2252,12 @@ static int amdgpu_pci_probe(struct pci_dev *pdev,
+ int ret, retry = 0, i;
+ bool supports_atomic = false;
+
++ if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA ||
++ (pdev->class >> 8) == PCI_CLASS_DISPLAY_OTHER) {
++ if (drm_firmware_drivers_only() && amdgpu_modeset == -1)
++ return -EINVAL;
++ }
++
+ /* skip devices which are owned by radeon */
+ for (i = 0; i < ARRAY_SIZE(amdgpu_unsupported_pciidlist); i++) {
+ if (amdgpu_unsupported_pciidlist[i] == pdev->device)
+--
+2.39.5
+
--- /dev/null
+From 8216a1e33ef74729288036e44a874b3c8df2aff3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 16 Apr 2025 00:19:13 -0400
+Subject: drm/amdgpu: Allow P2P access through XGMI
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Felix Kuehling <felix.kuehling@amd.com>
+
+[ Upstream commit a92741e72f91b904c1d8c3d409ed8dbe9c1f2b26 ]
+
+If peer memory is accessible through XGMI, allow leaving it in VRAM
+rather than forcing its migration to GTT on DMABuf attachment.
+
+Signed-off-by: Felix Kuehling <felix.kuehling@amd.com>
+Tested-by: Hao (Claire) Zhou <hao.zhou@amd.com>
+Reviewed-by: Christian König <christian.koenig@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+(cherry picked from commit 372c8d72c3680fdea3fbb2d6b089f76b4a6d596a)
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c | 30 ++++++++++++++++++++-
+ 1 file changed, 29 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
+index c9842a0e2a1cd..cb043296f9aec 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
+@@ -43,6 +43,29 @@
+ #include <linux/dma-fence-array.h>
+ #include <linux/pci-p2pdma.h>
+
++static const struct dma_buf_attach_ops amdgpu_dma_buf_attach_ops;
++
++/**
++ * dma_buf_attach_adev - Helper to get adev of an attachment
++ *
++ * @attach: attachment
++ *
++ * Returns:
++ * A struct amdgpu_device * if the attaching device is an amdgpu device or
++ * partition, NULL otherwise.
++ */
++static struct amdgpu_device *dma_buf_attach_adev(struct dma_buf_attachment *attach)
++{
++ if (attach->importer_ops == &amdgpu_dma_buf_attach_ops) {
++ struct drm_gem_object *obj = attach->importer_priv;
++ struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
++
++ return amdgpu_ttm_adev(bo->tbo.bdev);
++ }
++
++ return NULL;
++}
++
+ /**
+ * amdgpu_dma_buf_attach - &dma_buf_ops.attach implementation
+ *
+@@ -54,11 +77,13 @@
+ static int amdgpu_dma_buf_attach(struct dma_buf *dmabuf,
+ struct dma_buf_attachment *attach)
+ {
++ struct amdgpu_device *attach_adev = dma_buf_attach_adev(attach);
+ struct drm_gem_object *obj = dmabuf->priv;
+ struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
+ struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
+
+- if (pci_p2pdma_distance(adev->pdev, attach->dev, false) < 0)
++ if (!amdgpu_dmabuf_is_xgmi_accessible(attach_adev, bo) &&
++ pci_p2pdma_distance(adev->pdev, attach->dev, false) < 0)
+ attach->peer2peer = false;
+
+ amdgpu_vm_bo_update_shared(bo);
+@@ -459,6 +484,9 @@ bool amdgpu_dmabuf_is_xgmi_accessible(struct amdgpu_device *adev,
+ struct drm_gem_object *obj = &bo->tbo.base;
+ struct drm_gem_object *gobj;
+
++ if (!adev)
++ return false;
++
+ if (obj->import_attach) {
+ struct dma_buf *dma_buf = obj->import_attach->dmabuf;
+
+--
+2.39.5
+
--- /dev/null
+From c1e8ee5df7c5571a5a7630e80c44aa84f9b2e052 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 20 Feb 2025 13:38:06 +0530
+Subject: drm/amdgpu: Avoid HDP flush on JPEG v5.0.1
+
+From: Lijo Lazar <lijo.lazar@amd.com>
+
+[ Upstream commit a734a717dcfe1ce618301775034e598cb456665b ]
+
+Similar to JPEG v4.0.3, HDP flush shouldn't be performed by JPEG engine.
+Keep it empty.
+
+Signed-off-by: Lijo Lazar <lijo.lazar@amd.com>
+Reviewed-by: Hawking Zhang <Hawking.Zhang@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c | 2 +-
+ drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.h | 1 +
+ drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c | 1 +
+ 3 files changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c
+index 88f9771c16869..b2904ee494e04 100644
+--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c
++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c
+@@ -637,7 +637,7 @@ static uint64_t jpeg_v4_0_3_dec_ring_get_wptr(struct amdgpu_ring *ring)
+ ring->pipe ? (0x40 * ring->pipe - 0xc80) : 0);
+ }
+
+-static void jpeg_v4_0_3_ring_emit_hdp_flush(struct amdgpu_ring *ring)
++void jpeg_v4_0_3_ring_emit_hdp_flush(struct amdgpu_ring *ring)
+ {
+ /* JPEG engine access for HDP flush doesn't work when RRMT is enabled.
+ * This is a workaround to avoid any HDP flush through JPEG ring.
+diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.h b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.h
+index 747a3e5f68564..a90bf370a0025 100644
+--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.h
++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.h
+@@ -56,6 +56,7 @@ void jpeg_v4_0_3_dec_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq
+ unsigned int flags);
+ void jpeg_v4_0_3_dec_ring_emit_vm_flush(struct amdgpu_ring *ring,
+ unsigned int vmid, uint64_t pd_addr);
++void jpeg_v4_0_3_ring_emit_hdp_flush(struct amdgpu_ring *ring);
+ void jpeg_v4_0_3_dec_ring_nop(struct amdgpu_ring *ring, uint32_t count);
+ void jpeg_v4_0_3_dec_ring_insert_start(struct amdgpu_ring *ring);
+ void jpeg_v4_0_3_dec_ring_insert_end(struct amdgpu_ring *ring);
+diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c
+index 40d4c32a8c2a6..f2cc11b3fd68b 100644
+--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c
++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c
+@@ -655,6 +655,7 @@ static const struct amdgpu_ring_funcs jpeg_v5_0_1_dec_ring_vm_funcs = {
+ .emit_ib = jpeg_v4_0_3_dec_ring_emit_ib,
+ .emit_fence = jpeg_v4_0_3_dec_ring_emit_fence,
+ .emit_vm_flush = jpeg_v4_0_3_dec_ring_emit_vm_flush,
++ .emit_hdp_flush = jpeg_v4_0_3_ring_emit_hdp_flush,
+ .test_ring = amdgpu_jpeg_dec_ring_test_ring,
+ .test_ib = amdgpu_jpeg_dec_ring_test_ib,
+ .insert_nop = jpeg_v4_0_3_dec_ring_nop,
+--
+2.39.5
+
--- /dev/null
+From 0fe1af026c0d0bc2857fba33bd7eed8e2da7c281 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Feb 2025 10:39:27 +0800
+Subject: drm/amdgpu/discovery: check ip_discovery fw file available
+
+From: Flora Cui <flora.cui@amd.com>
+
+[ Upstream commit 017fbb6690c2245b1b4ef39b66c79d2990fe63dd ]
+
+Signed-off-by: Flora Cui <flora.cui@amd.com>
+Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c | 31 ++++++++++---------
+ 1 file changed, 16 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
+index 949d74eff2946..6a6dc15273dc7 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
+@@ -113,8 +113,7 @@
+ #include "amdgpu_isp.h"
+ #endif
+
+-#define FIRMWARE_IP_DISCOVERY "amdgpu/ip_discovery.bin"
+-MODULE_FIRMWARE(FIRMWARE_IP_DISCOVERY);
++MODULE_FIRMWARE("amdgpu/ip_discovery.bin");
+
+ #define mmIP_DISCOVERY_VERSION 0x16A00
+ #define mmRCC_CONFIG_MEMSIZE 0xde3
+@@ -297,21 +296,13 @@ static int amdgpu_discovery_read_binary_from_mem(struct amdgpu_device *adev,
+ return ret;
+ }
+
+-static int amdgpu_discovery_read_binary_from_file(struct amdgpu_device *adev, uint8_t *binary)
++static int amdgpu_discovery_read_binary_from_file(struct amdgpu_device *adev,
++ uint8_t *binary,
++ const char *fw_name)
+ {
+ const struct firmware *fw;
+- const char *fw_name;
+ int r;
+
+- switch (amdgpu_discovery) {
+- case 2:
+- fw_name = FIRMWARE_IP_DISCOVERY;
+- break;
+- default:
+- dev_warn(adev->dev, "amdgpu_discovery is not set properly\n");
+- return -EINVAL;
+- }
+-
+ r = request_firmware(&fw, fw_name, adev->dev);
+ if (r) {
+ dev_err(adev->dev, "can't load firmware \"%s\"\n",
+@@ -404,10 +395,19 @@ static int amdgpu_discovery_verify_npsinfo(struct amdgpu_device *adev,
+ return 0;
+ }
+
++static const char *amdgpu_discovery_get_fw_name(struct amdgpu_device *adev)
++{
++ if (amdgpu_discovery == 2)
++ return "amdgpu/ip_discovery.bin";
++
++ return NULL;
++}
++
+ static int amdgpu_discovery_init(struct amdgpu_device *adev)
+ {
+ struct table_info *info;
+ struct binary_header *bhdr;
++ const char *fw_name;
+ uint16_t offset;
+ uint16_t size;
+ uint16_t checksum;
+@@ -419,9 +419,10 @@ static int amdgpu_discovery_init(struct amdgpu_device *adev)
+ return -ENOMEM;
+
+ /* Read from file if it is the preferred option */
+- if (amdgpu_discovery == 2) {
++ fw_name = amdgpu_discovery_get_fw_name(adev);
++ if (fw_name != NULL) {
+ dev_info(adev->dev, "use ip discovery information from file");
+- r = amdgpu_discovery_read_binary_from_file(adev, adev->mman.discovery_bin);
++ r = amdgpu_discovery_read_binary_from_file(adev, adev->mman.discovery_bin, fw_name);
+
+ if (r) {
+ dev_err(adev->dev, "failed to read ip discovery binary from file\n");
+--
+2.39.5
+
--- /dev/null
+From 22ce2f5ee68442539d6f766f0f77e73029340b06 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 13 Feb 2025 18:38:28 -0500
+Subject: drm/amdgpu: Do not program AGP BAR regs under SRIOV in gfxhub_v1_0.c
+
+From: Victor Lu <victorchengchi.lu@amd.com>
+
+[ Upstream commit 057fef20b8401110a7bc1c2fe9d804a8a0bf0d24 ]
+
+SRIOV VF does not have write access to AGP BAR regs.
+Skip the writes to avoid a dmesg warning.
+
+Signed-off-by: Victor Lu <victorchengchi.lu@amd.com>
+Acked-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c
+index 0e3ddea7b8e0f..a7bfc9f41d0e3 100644
+--- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c
+@@ -92,12 +92,12 @@ static void gfxhub_v1_0_init_system_aperture_regs(struct amdgpu_device *adev)
+ {
+ uint64_t value;
+
+- /* Program the AGP BAR */
+- WREG32_SOC15_RLC(GC, 0, mmMC_VM_AGP_BASE, 0);
+- WREG32_SOC15_RLC(GC, 0, mmMC_VM_AGP_BOT, adev->gmc.agp_start >> 24);
+- WREG32_SOC15_RLC(GC, 0, mmMC_VM_AGP_TOP, adev->gmc.agp_end >> 24);
+-
+ if (!amdgpu_sriov_vf(adev) || adev->asic_type <= CHIP_VEGA10) {
++ /* Program the AGP BAR */
++ WREG32_SOC15_RLC(GC, 0, mmMC_VM_AGP_BASE, 0);
++ WREG32_SOC15_RLC(GC, 0, mmMC_VM_AGP_BOT, adev->gmc.agp_start >> 24);
++ WREG32_SOC15_RLC(GC, 0, mmMC_VM_AGP_TOP, adev->gmc.agp_end >> 24);
++
+ /* Program the system aperture low logical page number. */
+ WREG32_SOC15_RLC(GC, 0, mmMC_VM_SYSTEM_APERTURE_LOW_ADDR,
+ min(adev->gmc.fb_start, adev->gmc.agp_start) >> 18);
+--
+2.39.5
+
--- /dev/null
+From 084bdf49bfdc76f7187c5a71c16bfb2cd47847e7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Sep 2024 10:29:31 -0400
+Subject: drm/amdgpu: don't free conflicting apertures for non-display devices
+
+From: Alex Deucher <alexander.deucher@amd.com>
+
+[ Upstream commit 9deacd6c55f1b31e5ab20db79df2e14ac480203c ]
+
+PCI_CLASS_ACCELERATOR_PROCESSING devices won't ever be
+the sysfb, so there is no need to free conflicting
+apertures.
+
+Reviewed-by: Kent Russell <kent.russell@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 15 +++++++++++----
+ 1 file changed, 11 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+index ea50f82b547d9..28190b0ac5fca 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+@@ -4370,10 +4370,17 @@ int amdgpu_device_init(struct amdgpu_device *adev,
+ if (r)
+ return r;
+
+- /* Get rid of things like offb */
+- r = aperture_remove_conflicting_pci_devices(adev->pdev, amdgpu_kms_driver.name);
+- if (r)
+- return r;
++ /*
++ * No need to remove conflicting FBs for non-display class devices.
++ * This prevents the sysfb from being freed accidently.
++ */
++ if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA ||
++ (pdev->class >> 8) == PCI_CLASS_DISPLAY_OTHER) {
++ /* Get rid of things like offb */
++ r = aperture_remove_conflicting_pci_devices(adev->pdev, amdgpu_kms_driver.name);
++ if (r)
++ return r;
++ }
+
+ /* Enable TMZ based on IP_VERSION */
+ amdgpu_gmc_tmz_set(adev);
+--
+2.39.5
+
--- /dev/null
+From d5db35a354d56558989a1b8bf52efe072c365ac9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 19 Nov 2024 15:58:39 +0800
+Subject: drm/amdgpu: enlarge the VBIOS binary size limit
+
+From: Shiwu Zhang <shiwu.zhang@amd.com>
+
+[ Upstream commit 667b96134c9e206aebe40985650bf478935cbe04 ]
+
+Some chips have a larger VBIOS file so raise the size limit to support
+the flashing tool.
+
+Signed-off-by: Shiwu Zhang <shiwu.zhang@amd.com>
+Reviewed-by: Hawking Zhang <Hawking.Zhang@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
+index 665cc277cdc05..6dded11a23acf 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
+@@ -44,7 +44,7 @@
+ #include "amdgpu_securedisplay.h"
+ #include "amdgpu_atomfirmware.h"
+
+-#define AMD_VBIOS_FILE_MAX_SIZE_B (1024*1024*3)
++#define AMD_VBIOS_FILE_MAX_SIZE_B (1024*1024*16)
+
+ static int psp_load_smu_fw(struct psp_context *psp);
+ static int psp_rap_terminate(struct psp_context *psp);
+--
+2.39.5
+
--- /dev/null
+From bbdc9428e1903fad5f65a378b232d64db661bb44 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Mar 2025 15:10:22 +0800
+Subject: drm/amdgpu: Fix missing drain retry fault the last entry
+
+From: Emily Deng <Emily.Deng@amd.com>
+
+[ Upstream commit fe2fa3be3d59ba67d6de54a0064441ec233cb50c ]
+
+While the entry get in svm_range_unmap_from_cpu is the last entry, and
+the entry is page fault, it also need to be dropped. So for equal case,
+it also need to be dropped.
+
+v2:
+Only modify the svm_range_restore_pages.
+
+Signed-off-by: Emily Deng <Emily.Deng@amd.com>
+Reviewed-by: Xiaogang Chen<xiaogang.chen@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h | 3 +++
+ drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 2 +-
+ 2 files changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h
+index 7d4395a5d8ac9..b0a88f92cd821 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h
+@@ -78,6 +78,9 @@ struct amdgpu_ih_ring {
+ #define amdgpu_ih_ts_after(t1, t2) \
+ (((int64_t)((t2) << 16) - (int64_t)((t1) << 16)) > 0LL)
+
++#define amdgpu_ih_ts_after_or_equal(t1, t2) \
++ (((int64_t)((t2) << 16) - (int64_t)((t1) << 16)) >= 0LL)
++
+ /* provided by the ih block */
+ struct amdgpu_ih_funcs {
+ /* ring read/write ptr handling, called from interrupt context */
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
+index d1cf9dd352904..47189453b20c3 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
+@@ -3024,7 +3024,7 @@ svm_range_restore_pages(struct amdgpu_device *adev, unsigned int pasid,
+
+ /* check if this page fault time stamp is before svms->checkpoint_ts */
+ if (svms->checkpoint_ts[gpuidx] != 0) {
+- if (amdgpu_ih_ts_after(ts, svms->checkpoint_ts[gpuidx])) {
++ if (amdgpu_ih_ts_after_or_equal(ts, svms->checkpoint_ts[gpuidx])) {
+ pr_debug("draining retry fault, drop fault 0x%llx\n", addr);
+ r = -EAGAIN;
+ goto out_unlock_svms;
+--
+2.39.5
+
--- /dev/null
+From a468fc121bf5b746da2eec75c8811be27f9a3c47 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 21 Jan 2025 12:32:07 +0530
+Subject: drm/amdgpu/gfx10: Add cleaner shader for GFX10.1.10
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+
+[ Upstream commit 25961bad9212476983c570438366e1f5e9a9cf21 ]
+
+This commit adds the cleaner shader microcode for GFX10.1.0 GPUs. The
+cleaner shader is a piece of GPU code that is used to clear or
+initialize certain GPU resources, such as Local Data Share (LDS), Vector
+General Purpose Registers (VGPRs), and Scalar General Purpose Registers
+(SGPRs).
+
+Clearing these resources is important for ensuring data isolation
+between different workloads running on the GPU. Without the cleaner
+shader, residual data from a previous workload could potentially be
+accessed by a subsequent workload, leading to data leaks and incorrect
+computation results.
+
+The cleaner shader microcode is represented as an array of 32-bit words
+(`gfx_10_1_0_cleaner_shader_hex`). This array is the binary
+representation of the cleaner shader code, which is written in a
+low-level GPU instruction set.
+
+When the cleaner shader feature is enabled, the AMDGPU driver loads this
+array into a specific location in the GPU memory. The GPU then reads
+this memory location to fetch and execute the cleaner shader
+instructions.
+
+The cleaner shader is executed automatically by the GPU at the end of
+each workload, before the next workload starts. This ensures that all
+GPU resources are in a clean state before the start of each workload.
+
+This addition is part of the cleaner shader feature implementation. The
+cleaner shader feature helps resource utilization by cleaning up GPU
+resources after they are used. It also enhances security and reliability
+by preventing data leaks between workloads.
+
+Cc: Christian König <christian.koenig@amd.com>
+Cc: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+Suggested-by: Alex Deucher <alexander.deucher@amd.com>
+Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c | 14 ++
+ .../drm/amd/amdgpu/gfx_v10_0_cleaner_shader.h | 35 +++++
+ .../amdgpu/gfx_v10_1_10_cleaner_shader.asm | 126 ++++++++++++++++++
+ 3 files changed, 175 insertions(+)
+ create mode 100644 drivers/gpu/drm/amd/amdgpu/gfx_v10_1_10_cleaner_shader.asm
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
+index 1f32c531f610e..09178d56afbf6 100644
+--- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
+@@ -4739,6 +4739,20 @@ static int gfx_v10_0_sw_init(struct amdgpu_ip_block *ip_block)
+ break;
+ }
+ switch (amdgpu_ip_version(adev, GC_HWIP, 0)) {
++ case IP_VERSION(10, 1, 10):
++ adev->gfx.cleaner_shader_ptr = gfx_10_1_10_cleaner_shader_hex;
++ adev->gfx.cleaner_shader_size = sizeof(gfx_10_1_10_cleaner_shader_hex);
++ if (adev->gfx.me_fw_version >= 101 &&
++ adev->gfx.pfp_fw_version >= 158 &&
++ adev->gfx.mec_fw_version >= 152) {
++ adev->gfx.enable_cleaner_shader = true;
++ r = amdgpu_gfx_cleaner_shader_sw_init(adev, adev->gfx.cleaner_shader_size);
++ if (r) {
++ adev->gfx.enable_cleaner_shader = false;
++ dev_err(adev->dev, "Failed to initialize cleaner shader\n");
++ }
++ }
++ break;
+ case IP_VERSION(10, 3, 0):
+ case IP_VERSION(10, 3, 2):
+ case IP_VERSION(10, 3, 4):
+diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0_cleaner_shader.h b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0_cleaner_shader.h
+index 663c2572d440a..5255378af53c0 100644
+--- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0_cleaner_shader.h
++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0_cleaner_shader.h
+@@ -21,6 +21,41 @@
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
++/* Define the cleaner shader gfx_10_1_10 */
++static const u32 gfx_10_1_10_cleaner_shader_hex[] = {
++ 0xb0804004, 0xbf8a0000,
++ 0xbf068100, 0xbf840023,
++ 0xbe8203b8, 0xbefc0380,
++ 0x7e008480, 0x7e028480,
++ 0x7e048480, 0x7e068480,
++ 0x7e088480, 0x7e0a8480,
++ 0x7e0c8480, 0x7e0e8480,
++ 0xbefc0302, 0x80828802,
++ 0xbf84fff5, 0xbe8203ff,
++ 0x80000000, 0x87020102,
++ 0xbf840012, 0xbefe03c1,
++ 0xbeff03c1, 0xd7650001,
++ 0x0001007f, 0xd7660001,
++ 0x0002027e, 0x16020288,
++ 0xbe8203bf, 0xbefc03c1,
++ 0xd9382000, 0x00020201,
++ 0xd9386040, 0x00040401,
++ 0xd70f6a01, 0x000202ff,
++ 0x00000400, 0x80828102,
++ 0xbf84fff7, 0xbefc03ff,
++ 0x00000068, 0xbe803080,
++ 0xbe813080, 0xbe823080,
++ 0xbe833080, 0x80fc847c,
++ 0xbf84fffa, 0xbeea0480,
++ 0xbeec0480, 0xbeee0480,
++ 0xbef00480, 0xbef20480,
++ 0xbef40480, 0xbef60480,
++ 0xbef80480, 0xbefa0480,
++ 0xbf810000, 0xbf9f0000,
++ 0xbf9f0000, 0xbf9f0000,
++ 0xbf9f0000, 0xbf9f0000,
++};
++
+ /* Define the cleaner shader gfx_10_3_0 */
+ static const u32 gfx_10_3_0_cleaner_shader_hex[] = {
+ 0xb0804004, 0xbf8a0000,
+diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_1_10_cleaner_shader.asm b/drivers/gpu/drm/amd/amdgpu/gfx_v10_1_10_cleaner_shader.asm
+new file mode 100644
+index 0000000000000..9ba3359253c95
+--- /dev/null
++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_1_10_cleaner_shader.asm
+@@ -0,0 +1,126 @@
++/* SPDX-License-Identifier: MIT */
++/*
++ * Copyright 2025 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ */
++
++// This shader is to clean LDS, SGPRs and VGPRs. It is first 64 Dwords or 256 bytes of 256 Dwords cleaner shader.
++
++// GFX10.1 : Clear SGPRs, VGPRs and LDS
++// Launch 32 waves per CU (16 per SIMD) as a workgroup (threadgroup) to fill every wave slot
++// Waves are "wave32" and have 64 VGPRs each, which uses all 1024 VGPRs per SIMD
++// Waves are launched in "CU" mode, and the workgroup shares 64KB of LDS (half of the WGP's LDS)
++// It takes 2 workgroups to use all of LDS: one on each CU of the WGP
++// Each wave clears SGPRs 0 - 107
++// Each wave clears VGPRs 0 - 63
++// The first wave of the workgroup clears its 64KB of LDS
++// The shader starts with "S_BARRIER" to ensure SPI has launched all waves of the workgroup
++// before any wave in the workgroup could end. Without this, it is possible not all SGPRs get cleared.
++
++
++shader main
++ asic(GFX10.1)
++ type(CS)
++ wave_size(32)
++// Note: original source code from SQ team
++
++//
++// Create 32 waves in a threadgroup (CS waves)
++// Each allocates 64 VGPRs
++// The workgroup allocates all of LDS (64kbytes)
++//
++// Takes about 2500 clocks to run.
++// (theorhetical fastest = 1024clks vgpr + 640lds = 1660 clks)
++//
++ S_BARRIER
++ s_cmp_eq_u32 s0, 1 // Bit0 is set, sgpr0 is set then clear VGPRS and LDS as FW set COMPUTE_USER_DATA_0
++ s_cbranch_scc0 label_0023 // Clean VGPRs and LDS if sgpr0 of wave is set, scc = (s0 == 1)
++
++ s_mov_b32 s2, 0x00000038 // Loop 64/8=8 times (loop unrolled for performance)
++ s_mov_b32 m0, 0
++ //
++ // CLEAR VGPRs
++ //
++label_0005:
++ v_movreld_b32 v0, 0
++ v_movreld_b32 v1, 0
++ v_movreld_b32 v2, 0
++ v_movreld_b32 v3, 0
++ v_movreld_b32 v4, 0
++ v_movreld_b32 v5, 0
++ v_movreld_b32 v6, 0
++ v_movreld_b32 v7, 0
++ s_mov_b32 m0, s2
++ s_sub_u32 s2, s2, 8
++ s_cbranch_scc0 label_0005
++ //
++ s_mov_b32 s2, 0x80000000 // Bit31 is first_wave
++ s_and_b32 s2, s2, s0 // sgpr0 has tg_size (first_wave) term as in ucode only COMPUTE_PGM_RSRC2.tg_size_en is set
++ s_cbranch_scc0 label_0023 // Clean LDS if its first wave of ThreadGroup/WorkGroup
++ // CLEAR LDS
++ //
++ s_mov_b32 exec_lo, 0xffffffff
++ s_mov_b32 exec_hi, 0xffffffff
++ v_mbcnt_lo_u32_b32 v1, exec_hi, 0 // Set V1 to thread-ID (0..63)
++ v_mbcnt_hi_u32_b32 v1, exec_lo, v1 // Set V1 to thread-ID (0..63)
++ v_mul_u32_u24 v1, 0x00000008, v1 // * 8, so each thread is a double-dword address (8byte)
++ s_mov_b32 s2, 0x00000003f // 64 loop iterations
++ s_mov_b32 m0, 0xffffffff
++ // Clear all of LDS space
++ // Each FirstWave of WorkGroup clears 64kbyte block
++
++label_001F:
++ ds_write2_b64 v1, v[2:3], v[2:3] offset1:32
++ ds_write2_b64 v1, v[4:5], v[4:5] offset0:64 offset1:96
++ v_add_co_u32 v1, vcc, 0x00000400, v1
++ s_sub_u32 s2, s2, 1
++ s_cbranch_scc0 label_001F
++
++ //
++ // CLEAR SGPRs
++ //
++label_0023:
++ s_mov_b32 m0, 0x00000068 // Loop 108/4=27 times (loop unrolled for performance)
++label_sgpr_loop:
++ s_movreld_b32 s0, 0
++ s_movreld_b32 s1, 0
++ s_movreld_b32 s2, 0
++ s_movreld_b32 s3, 0
++ s_sub_u32 m0, m0, 4
++ s_cbranch_scc0 label_sgpr_loop
++
++ //clear vcc
++ s_mov_b64 vcc, 0 //clear vcc
++ //s_setreg_imm32_b32 hw_reg_shader_flat_scratch_lo, 0 //clear flat scratch lo SGPR
++ //s_setreg_imm32_b32 hw_reg_shader_flat_scratch_hi, 0 //clear flat scratch hi SGPR
++ s_mov_b64 ttmp0, 0 //Clear ttmp0 and ttmp1
++ s_mov_b64 ttmp2, 0 //Clear ttmp2 and ttmp3
++ s_mov_b64 ttmp4, 0 //Clear ttmp4 and ttmp5
++ s_mov_b64 ttmp6, 0 //Clear ttmp6 and ttmp7
++ s_mov_b64 ttmp8, 0 //Clear ttmp8 and ttmp9
++ s_mov_b64 ttmp10, 0 //Clear ttmp10 and ttmp11
++ s_mov_b64 ttmp12, 0 //Clear ttmp12 and ttmp13
++ s_mov_b64 ttmp14, 0 //Clear ttmp14 and ttmp15
++
++ s_endpgm
++
++end
++
++
+--
+2.39.5
+
--- /dev/null
+From 4fc8d1aa9cec5adb3a058ac605dfa07d0549dfd5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Feb 2025 15:55:33 -0500
+Subject: drm/amdgpu/gfx11: don't read registers in mqd init
+
+From: Alex Deucher <alexander.deucher@amd.com>
+
+[ Upstream commit e27b36ea6ba5f29e91fcfb375ea29503708fcf43 ]
+
+Just use the default values. There's not need to
+get the value from hardware and it could cause problems
+if we do that at runtime and gfxoff is active.
+
+Reviewed-by: Mukul Joshi <mukul.joshi@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 47 ++++++++++++++++++--------
+ 1 file changed, 32 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
+index f1f53c7687410..e050c2e4ea734 100644
+--- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
+@@ -64,6 +64,23 @@
+ #define regPC_CONFIG_CNTL_1 0x194d
+ #define regPC_CONFIG_CNTL_1_BASE_IDX 1
+
++#define regCP_GFX_MQD_CONTROL_DEFAULT 0x00000100
++#define regCP_GFX_HQD_VMID_DEFAULT 0x00000000
++#define regCP_GFX_HQD_QUEUE_PRIORITY_DEFAULT 0x00000000
++#define regCP_GFX_HQD_QUANTUM_DEFAULT 0x00000a01
++#define regCP_GFX_HQD_CNTL_DEFAULT 0x00a00000
++#define regCP_RB_DOORBELL_CONTROL_DEFAULT 0x00000000
++#define regCP_GFX_HQD_RPTR_DEFAULT 0x00000000
++
++#define regCP_HQD_EOP_CONTROL_DEFAULT 0x00000006
++#define regCP_HQD_PQ_DOORBELL_CONTROL_DEFAULT 0x00000000
++#define regCP_MQD_CONTROL_DEFAULT 0x00000100
++#define regCP_HQD_PQ_CONTROL_DEFAULT 0x00308509
++#define regCP_HQD_PQ_DOORBELL_CONTROL_DEFAULT 0x00000000
++#define regCP_HQD_PQ_RPTR_DEFAULT 0x00000000
++#define regCP_HQD_PERSISTENT_STATE_DEFAULT 0x0be05501
++#define regCP_HQD_IB_CONTROL_DEFAULT 0x00300000
++
+ MODULE_FIRMWARE("amdgpu/gc_11_0_0_pfp.bin");
+ MODULE_FIRMWARE("amdgpu/gc_11_0_0_me.bin");
+ MODULE_FIRMWARE("amdgpu/gc_11_0_0_mec.bin");
+@@ -3958,7 +3975,7 @@ static void gfx_v11_0_gfx_mqd_set_priority(struct amdgpu_device *adev,
+ if (prop->hqd_pipe_priority == AMDGPU_GFX_PIPE_PRIO_HIGH)
+ priority = 1;
+
+- tmp = RREG32_SOC15(GC, 0, regCP_GFX_HQD_QUEUE_PRIORITY);
++ tmp = regCP_GFX_HQD_QUEUE_PRIORITY_DEFAULT;
+ tmp = REG_SET_FIELD(tmp, CP_GFX_HQD_QUEUE_PRIORITY, PRIORITY_LEVEL, priority);
+ mqd->cp_gfx_hqd_queue_priority = tmp;
+ }
+@@ -3980,14 +3997,14 @@ static int gfx_v11_0_gfx_mqd_init(struct amdgpu_device *adev, void *m,
+ mqd->cp_mqd_base_addr_hi = upper_32_bits(prop->mqd_gpu_addr);
+
+ /* set up mqd control */
+- tmp = RREG32_SOC15(GC, 0, regCP_GFX_MQD_CONTROL);
++ tmp = regCP_GFX_MQD_CONTROL_DEFAULT;
+ tmp = REG_SET_FIELD(tmp, CP_GFX_MQD_CONTROL, VMID, 0);
+ tmp = REG_SET_FIELD(tmp, CP_GFX_MQD_CONTROL, PRIV_STATE, 1);
+ tmp = REG_SET_FIELD(tmp, CP_GFX_MQD_CONTROL, CACHE_POLICY, 0);
+ mqd->cp_gfx_mqd_control = tmp;
+
+ /* set up gfx_hqd_vimd with 0x0 to indicate the ring buffer's vmid */
+- tmp = RREG32_SOC15(GC, 0, regCP_GFX_HQD_VMID);
++ tmp = regCP_GFX_HQD_VMID_DEFAULT;
+ tmp = REG_SET_FIELD(tmp, CP_GFX_HQD_VMID, VMID, 0);
+ mqd->cp_gfx_hqd_vmid = 0;
+
+@@ -3995,7 +4012,7 @@ static int gfx_v11_0_gfx_mqd_init(struct amdgpu_device *adev, void *m,
+ gfx_v11_0_gfx_mqd_set_priority(adev, mqd, prop);
+
+ /* set up time quantum */
+- tmp = RREG32_SOC15(GC, 0, regCP_GFX_HQD_QUANTUM);
++ tmp = regCP_GFX_HQD_QUANTUM_DEFAULT;
+ tmp = REG_SET_FIELD(tmp, CP_GFX_HQD_QUANTUM, QUANTUM_EN, 1);
+ mqd->cp_gfx_hqd_quantum = tmp;
+
+@@ -4017,7 +4034,7 @@ static int gfx_v11_0_gfx_mqd_init(struct amdgpu_device *adev, void *m,
+
+ /* set up the gfx_hqd_control, similar as CP_RB0_CNTL */
+ rb_bufsz = order_base_2(prop->queue_size / 4) - 1;
+- tmp = RREG32_SOC15(GC, 0, regCP_GFX_HQD_CNTL);
++ tmp = regCP_GFX_HQD_CNTL_DEFAULT;
+ tmp = REG_SET_FIELD(tmp, CP_GFX_HQD_CNTL, RB_BUFSZ, rb_bufsz);
+ tmp = REG_SET_FIELD(tmp, CP_GFX_HQD_CNTL, RB_BLKSZ, rb_bufsz - 2);
+ #ifdef __BIG_ENDIAN
+@@ -4026,7 +4043,7 @@ static int gfx_v11_0_gfx_mqd_init(struct amdgpu_device *adev, void *m,
+ mqd->cp_gfx_hqd_cntl = tmp;
+
+ /* set up cp_doorbell_control */
+- tmp = RREG32_SOC15(GC, 0, regCP_RB_DOORBELL_CONTROL);
++ tmp = regCP_RB_DOORBELL_CONTROL_DEFAULT;
+ if (prop->use_doorbell) {
+ tmp = REG_SET_FIELD(tmp, CP_RB_DOORBELL_CONTROL,
+ DOORBELL_OFFSET, prop->doorbell_index);
+@@ -4038,7 +4055,7 @@ static int gfx_v11_0_gfx_mqd_init(struct amdgpu_device *adev, void *m,
+ mqd->cp_rb_doorbell_control = tmp;
+
+ /* reset read and write pointers, similar to CP_RB0_WPTR/_RPTR */
+- mqd->cp_gfx_hqd_rptr = RREG32_SOC15(GC, 0, regCP_GFX_HQD_RPTR);
++ mqd->cp_gfx_hqd_rptr = regCP_GFX_HQD_RPTR_DEFAULT;
+
+ /* active the queue */
+ mqd->cp_gfx_hqd_active = 1;
+@@ -4124,14 +4141,14 @@ static int gfx_v11_0_compute_mqd_init(struct amdgpu_device *adev, void *m,
+ mqd->cp_hqd_eop_base_addr_hi = upper_32_bits(eop_base_addr);
+
+ /* set the EOP size, register value is 2^(EOP_SIZE+1) dwords */
+- tmp = RREG32_SOC15(GC, 0, regCP_HQD_EOP_CONTROL);
++ tmp = regCP_HQD_EOP_CONTROL_DEFAULT;
+ tmp = REG_SET_FIELD(tmp, CP_HQD_EOP_CONTROL, EOP_SIZE,
+ (order_base_2(GFX11_MEC_HPD_SIZE / 4) - 1));
+
+ mqd->cp_hqd_eop_control = tmp;
+
+ /* enable doorbell? */
+- tmp = RREG32_SOC15(GC, 0, regCP_HQD_PQ_DOORBELL_CONTROL);
++ tmp = regCP_HQD_PQ_DOORBELL_CONTROL_DEFAULT;
+
+ if (prop->use_doorbell) {
+ tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_DOORBELL_CONTROL,
+@@ -4160,7 +4177,7 @@ static int gfx_v11_0_compute_mqd_init(struct amdgpu_device *adev, void *m,
+ mqd->cp_mqd_base_addr_hi = upper_32_bits(prop->mqd_gpu_addr);
+
+ /* set MQD vmid to 0 */
+- tmp = RREG32_SOC15(GC, 0, regCP_MQD_CONTROL);
++ tmp = regCP_MQD_CONTROL_DEFAULT;
+ tmp = REG_SET_FIELD(tmp, CP_MQD_CONTROL, VMID, 0);
+ mqd->cp_mqd_control = tmp;
+
+@@ -4170,7 +4187,7 @@ static int gfx_v11_0_compute_mqd_init(struct amdgpu_device *adev, void *m,
+ mqd->cp_hqd_pq_base_hi = upper_32_bits(hqd_gpu_addr);
+
+ /* set up the HQD, this is similar to CP_RB0_CNTL */
+- tmp = RREG32_SOC15(GC, 0, regCP_HQD_PQ_CONTROL);
++ tmp = regCP_HQD_PQ_CONTROL_DEFAULT;
+ tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, QUEUE_SIZE,
+ (order_base_2(prop->queue_size / 4) - 1));
+ tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, RPTR_BLOCK_SIZE,
+@@ -4196,7 +4213,7 @@ static int gfx_v11_0_compute_mqd_init(struct amdgpu_device *adev, void *m,
+ tmp = 0;
+ /* enable the doorbell if requested */
+ if (prop->use_doorbell) {
+- tmp = RREG32_SOC15(GC, 0, regCP_HQD_PQ_DOORBELL_CONTROL);
++ tmp = regCP_HQD_PQ_DOORBELL_CONTROL_DEFAULT;
+ tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_DOORBELL_CONTROL,
+ DOORBELL_OFFSET, prop->doorbell_index);
+
+@@ -4211,17 +4228,17 @@ static int gfx_v11_0_compute_mqd_init(struct amdgpu_device *adev, void *m,
+ mqd->cp_hqd_pq_doorbell_control = tmp;
+
+ /* reset read and write pointers, similar to CP_RB0_WPTR/_RPTR */
+- mqd->cp_hqd_pq_rptr = RREG32_SOC15(GC, 0, regCP_HQD_PQ_RPTR);
++ mqd->cp_hqd_pq_rptr = regCP_HQD_PQ_RPTR_DEFAULT;
+
+ /* set the vmid for the queue */
+ mqd->cp_hqd_vmid = 0;
+
+- tmp = RREG32_SOC15(GC, 0, regCP_HQD_PERSISTENT_STATE);
++ tmp = regCP_HQD_PERSISTENT_STATE_DEFAULT;
+ tmp = REG_SET_FIELD(tmp, CP_HQD_PERSISTENT_STATE, PRELOAD_SIZE, 0x55);
+ mqd->cp_hqd_persistent_state = tmp;
+
+ /* set MIN_IB_AVAIL_SIZE */
+- tmp = RREG32_SOC15(GC, 0, regCP_HQD_IB_CONTROL);
++ tmp = regCP_HQD_IB_CONTROL_DEFAULT;
+ tmp = REG_SET_FIELD(tmp, CP_HQD_IB_CONTROL, MIN_IB_AVAIL_SIZE, 3);
+ mqd->cp_hqd_ib_control = tmp;
+
+--
+2.39.5
+
--- /dev/null
+From 09118a6e6ea3d7cbb3e8ab59eed5e1d9453cddd1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Feb 2025 16:08:03 -0500
+Subject: drm/amdgpu/gfx12: don't read registers in mqd init
+
+From: Alex Deucher <alexander.deucher@amd.com>
+
+[ Upstream commit fc3c139cf0432b79fd08e23100a559ee51cd0be4 ]
+
+Just use the default values. There's not need to
+get the value from hardware and it could cause problems
+if we do that at runtime and gfxoff is active.
+
+Reviewed-by: Mukul Joshi <mukul.joshi@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c | 48 ++++++++++++++++++--------
+ 1 file changed, 33 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c
+index 0c08785099f32..2ec900d50d7f8 100644
+--- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c
+@@ -52,6 +52,24 @@
+
+ #define RLCG_UCODE_LOADING_START_ADDRESS 0x00002000L
+
++#define regCP_GFX_MQD_CONTROL_DEFAULT 0x00000100
++#define regCP_GFX_HQD_VMID_DEFAULT 0x00000000
++#define regCP_GFX_HQD_QUEUE_PRIORITY_DEFAULT 0x00000000
++#define regCP_GFX_HQD_QUANTUM_DEFAULT 0x00000a01
++#define regCP_GFX_HQD_CNTL_DEFAULT 0x00f00000
++#define regCP_RB_DOORBELL_CONTROL_DEFAULT 0x00000000
++#define regCP_GFX_HQD_RPTR_DEFAULT 0x00000000
++
++#define regCP_HQD_EOP_CONTROL_DEFAULT 0x00000006
++#define regCP_HQD_PQ_DOORBELL_CONTROL_DEFAULT 0x00000000
++#define regCP_MQD_CONTROL_DEFAULT 0x00000100
++#define regCP_HQD_PQ_CONTROL_DEFAULT 0x00308509
++#define regCP_HQD_PQ_DOORBELL_CONTROL_DEFAULT 0x00000000
++#define regCP_HQD_PQ_RPTR_DEFAULT 0x00000000
++#define regCP_HQD_PERSISTENT_STATE_DEFAULT 0x0be05501
++#define regCP_HQD_IB_CONTROL_DEFAULT 0x00300000
++
++
+ MODULE_FIRMWARE("amdgpu/gc_12_0_0_pfp.bin");
+ MODULE_FIRMWARE("amdgpu/gc_12_0_0_me.bin");
+ MODULE_FIRMWARE("amdgpu/gc_12_0_0_mec.bin");
+@@ -2891,25 +2909,25 @@ static int gfx_v12_0_gfx_mqd_init(struct amdgpu_device *adev, void *m,
+ mqd->cp_mqd_base_addr_hi = upper_32_bits(prop->mqd_gpu_addr);
+
+ /* set up mqd control */
+- tmp = RREG32_SOC15(GC, 0, regCP_GFX_MQD_CONTROL);
++ tmp = regCP_GFX_MQD_CONTROL_DEFAULT;
+ tmp = REG_SET_FIELD(tmp, CP_GFX_MQD_CONTROL, VMID, 0);
+ tmp = REG_SET_FIELD(tmp, CP_GFX_MQD_CONTROL, PRIV_STATE, 1);
+ tmp = REG_SET_FIELD(tmp, CP_GFX_MQD_CONTROL, CACHE_POLICY, 0);
+ mqd->cp_gfx_mqd_control = tmp;
+
+ /* set up gfx_hqd_vimd with 0x0 to indicate the ring buffer's vmid */
+- tmp = RREG32_SOC15(GC, 0, regCP_GFX_HQD_VMID);
++ tmp = regCP_GFX_HQD_VMID_DEFAULT;
+ tmp = REG_SET_FIELD(tmp, CP_GFX_HQD_VMID, VMID, 0);
+ mqd->cp_gfx_hqd_vmid = 0;
+
+ /* set up default queue priority level
+ * 0x0 = low priority, 0x1 = high priority */
+- tmp = RREG32_SOC15(GC, 0, regCP_GFX_HQD_QUEUE_PRIORITY);
++ tmp = regCP_GFX_HQD_QUEUE_PRIORITY_DEFAULT;
+ tmp = REG_SET_FIELD(tmp, CP_GFX_HQD_QUEUE_PRIORITY, PRIORITY_LEVEL, 0);
+ mqd->cp_gfx_hqd_queue_priority = tmp;
+
+ /* set up time quantum */
+- tmp = RREG32_SOC15(GC, 0, regCP_GFX_HQD_QUANTUM);
++ tmp = regCP_GFX_HQD_QUANTUM_DEFAULT;
+ tmp = REG_SET_FIELD(tmp, CP_GFX_HQD_QUANTUM, QUANTUM_EN, 1);
+ mqd->cp_gfx_hqd_quantum = tmp;
+
+@@ -2931,7 +2949,7 @@ static int gfx_v12_0_gfx_mqd_init(struct amdgpu_device *adev, void *m,
+
+ /* set up the gfx_hqd_control, similar as CP_RB0_CNTL */
+ rb_bufsz = order_base_2(prop->queue_size / 4) - 1;
+- tmp = RREG32_SOC15(GC, 0, regCP_GFX_HQD_CNTL);
++ tmp = regCP_GFX_HQD_CNTL_DEFAULT;
+ tmp = REG_SET_FIELD(tmp, CP_GFX_HQD_CNTL, RB_BUFSZ, rb_bufsz);
+ tmp = REG_SET_FIELD(tmp, CP_GFX_HQD_CNTL, RB_BLKSZ, rb_bufsz - 2);
+ #ifdef __BIG_ENDIAN
+@@ -2940,7 +2958,7 @@ static int gfx_v12_0_gfx_mqd_init(struct amdgpu_device *adev, void *m,
+ mqd->cp_gfx_hqd_cntl = tmp;
+
+ /* set up cp_doorbell_control */
+- tmp = RREG32_SOC15(GC, 0, regCP_RB_DOORBELL_CONTROL);
++ tmp = regCP_RB_DOORBELL_CONTROL_DEFAULT;
+ if (prop->use_doorbell) {
+ tmp = REG_SET_FIELD(tmp, CP_RB_DOORBELL_CONTROL,
+ DOORBELL_OFFSET, prop->doorbell_index);
+@@ -2952,7 +2970,7 @@ static int gfx_v12_0_gfx_mqd_init(struct amdgpu_device *adev, void *m,
+ mqd->cp_rb_doorbell_control = tmp;
+
+ /* reset read and write pointers, similar to CP_RB0_WPTR/_RPTR */
+- mqd->cp_gfx_hqd_rptr = RREG32_SOC15(GC, 0, regCP_GFX_HQD_RPTR);
++ mqd->cp_gfx_hqd_rptr = regCP_GFX_HQD_RPTR_DEFAULT;
+
+ /* active the queue */
+ mqd->cp_gfx_hqd_active = 1;
+@@ -3047,14 +3065,14 @@ static int gfx_v12_0_compute_mqd_init(struct amdgpu_device *adev, void *m,
+ mqd->cp_hqd_eop_base_addr_hi = upper_32_bits(eop_base_addr);
+
+ /* set the EOP size, register value is 2^(EOP_SIZE+1) dwords */
+- tmp = RREG32_SOC15(GC, 0, regCP_HQD_EOP_CONTROL);
++ tmp = regCP_HQD_EOP_CONTROL_DEFAULT;
+ tmp = REG_SET_FIELD(tmp, CP_HQD_EOP_CONTROL, EOP_SIZE,
+ (order_base_2(GFX12_MEC_HPD_SIZE / 4) - 1));
+
+ mqd->cp_hqd_eop_control = tmp;
+
+ /* enable doorbell? */
+- tmp = RREG32_SOC15(GC, 0, regCP_HQD_PQ_DOORBELL_CONTROL);
++ tmp = regCP_HQD_PQ_DOORBELL_CONTROL_DEFAULT;
+
+ if (prop->use_doorbell) {
+ tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_DOORBELL_CONTROL,
+@@ -3083,7 +3101,7 @@ static int gfx_v12_0_compute_mqd_init(struct amdgpu_device *adev, void *m,
+ mqd->cp_mqd_base_addr_hi = upper_32_bits(prop->mqd_gpu_addr);
+
+ /* set MQD vmid to 0 */
+- tmp = RREG32_SOC15(GC, 0, regCP_MQD_CONTROL);
++ tmp = regCP_MQD_CONTROL_DEFAULT;
+ tmp = REG_SET_FIELD(tmp, CP_MQD_CONTROL, VMID, 0);
+ mqd->cp_mqd_control = tmp;
+
+@@ -3093,7 +3111,7 @@ static int gfx_v12_0_compute_mqd_init(struct amdgpu_device *adev, void *m,
+ mqd->cp_hqd_pq_base_hi = upper_32_bits(hqd_gpu_addr);
+
+ /* set up the HQD, this is similar to CP_RB0_CNTL */
+- tmp = RREG32_SOC15(GC, 0, regCP_HQD_PQ_CONTROL);
++ tmp = regCP_HQD_PQ_CONTROL_DEFAULT;
+ tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, QUEUE_SIZE,
+ (order_base_2(prop->queue_size / 4) - 1));
+ tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, RPTR_BLOCK_SIZE,
+@@ -3118,7 +3136,7 @@ static int gfx_v12_0_compute_mqd_init(struct amdgpu_device *adev, void *m,
+ tmp = 0;
+ /* enable the doorbell if requested */
+ if (prop->use_doorbell) {
+- tmp = RREG32_SOC15(GC, 0, regCP_HQD_PQ_DOORBELL_CONTROL);
++ tmp = regCP_HQD_PQ_DOORBELL_CONTROL_DEFAULT;
+ tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_DOORBELL_CONTROL,
+ DOORBELL_OFFSET, prop->doorbell_index);
+
+@@ -3133,17 +3151,17 @@ static int gfx_v12_0_compute_mqd_init(struct amdgpu_device *adev, void *m,
+ mqd->cp_hqd_pq_doorbell_control = tmp;
+
+ /* reset read and write pointers, similar to CP_RB0_WPTR/_RPTR */
+- mqd->cp_hqd_pq_rptr = RREG32_SOC15(GC, 0, regCP_HQD_PQ_RPTR);
++ mqd->cp_hqd_pq_rptr = regCP_HQD_PQ_RPTR_DEFAULT;
+
+ /* set the vmid for the queue */
+ mqd->cp_hqd_vmid = 0;
+
+- tmp = RREG32_SOC15(GC, 0, regCP_HQD_PERSISTENT_STATE);
++ tmp = regCP_HQD_PERSISTENT_STATE_DEFAULT;
+ tmp = REG_SET_FIELD(tmp, CP_HQD_PERSISTENT_STATE, PRELOAD_SIZE, 0x55);
+ mqd->cp_hqd_persistent_state = tmp;
+
+ /* set MIN_IB_AVAIL_SIZE */
+- tmp = RREG32_SOC15(GC, 0, regCP_HQD_IB_CONTROL);
++ tmp = regCP_HQD_IB_CONTROL_DEFAULT;
+ tmp = REG_SET_FIELD(tmp, CP_HQD_IB_CONTROL, MIN_IB_AVAIL_SIZE, 3);
+ mqd->cp_hqd_ib_control = tmp;
+
+--
+2.39.5
+
--- /dev/null
+From 1bbd787a90591867ac528b59796b0ebd42a07d6f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Mar 2025 11:36:49 +0800
+Subject: drm/amdgpu: increase RAS bad page threshold
+
+From: Tao Zhou <tao.zhou1@amd.com>
+
+[ Upstream commit 334dc5fcc3f177823115ec4e075259997c16d4a7 ]
+
+For default policy, driver will issue an RMA event when the number of
+bad pages is greater than 8 physical rows, rather than reaches 8
+physical rows, don't rely on threshold configurable parameters in
+default mode.
+
+Signed-off-by: Tao Zhou <tao.zhou1@amd.com>
+Reviewed-by: Hawking Zhang <Hawking.Zhang@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c
+index 52c16bfeccaad..12ffe4a963d31 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c
+@@ -748,7 +748,7 @@ amdgpu_ras_eeprom_update_header(struct amdgpu_ras_eeprom_control *control)
+ /* Modify the header if it exceeds.
+ */
+ if (amdgpu_bad_page_threshold != 0 &&
+- control->ras_num_bad_pages >= ras->bad_page_cnt_threshold) {
++ control->ras_num_bad_pages > ras->bad_page_cnt_threshold) {
+ dev_warn(adev->dev,
+ "Saved bad pages %d reaches threshold value %d\n",
+ control->ras_num_bad_pages, ras->bad_page_cnt_threshold);
+@@ -806,7 +806,7 @@ amdgpu_ras_eeprom_update_header(struct amdgpu_ras_eeprom_control *control)
+ */
+ if (amdgpu_bad_page_threshold != 0 &&
+ control->tbl_hdr.version == RAS_TABLE_VER_V2_1 &&
+- control->ras_num_bad_pages < ras->bad_page_cnt_threshold)
++ control->ras_num_bad_pages <= ras->bad_page_cnt_threshold)
+ control->tbl_rai.health_percent = ((ras->bad_page_cnt_threshold -
+ control->ras_num_bad_pages) * 100) /
+ ras->bad_page_cnt_threshold;
+@@ -1451,7 +1451,7 @@ int amdgpu_ras_eeprom_check(struct amdgpu_ras_eeprom_control *control)
+ res);
+ return -EINVAL;
+ }
+- if (ras->bad_page_cnt_threshold > control->ras_num_bad_pages) {
++ if (ras->bad_page_cnt_threshold >= control->ras_num_bad_pages) {
+ /* This means that, the threshold was increased since
+ * the last time the system was booted, and now,
+ * ras->bad_page_cnt_threshold - control->num_recs > 0,
+--
+2.39.5
+
--- /dev/null
+From eeb8b48cfbac1452bc29c85c39d7862c6ad2000d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 7 Feb 2025 09:39:24 -0500
+Subject: drm/amdgpu/mes11: fix set_hw_resources_1 calculation
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Alex Deucher <alexander.deucher@amd.com>
+
+[ Upstream commit 1350dd3691b5f757a948e5b9895d62c422baeb90 ]
+
+It's GPU page size not CPU page size. In most cases they
+are the same, but not always. This can lead to overallocation
+on systems with larger pages.
+
+Cc: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+Cc: Christian König <christian.koenig@amd.com>
+Reviewed-by: Christian König <christian.koenig@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/mes_v11_0.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c
+index 0f808ffcab943..68bb334393bb6 100644
+--- a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c
+@@ -730,7 +730,7 @@ static int mes_v11_0_set_hw_resources(struct amdgpu_mes *mes)
+
+ static int mes_v11_0_set_hw_resources_1(struct amdgpu_mes *mes)
+ {
+- int size = 128 * PAGE_SIZE;
++ int size = 128 * AMDGPU_GPU_PAGE_SIZE;
+ int ret = 0;
+ struct amdgpu_device *adev = mes->adev;
+ union MESAPI_SET_HW_RESOURCES_1 mes_set_hw_res_pkt;
+--
+2.39.5
+
--- /dev/null
+From 7c550480ca0b4ba5624fd7c13dd0f5fb4812cb0c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Feb 2025 12:53:48 +0530
+Subject: drm/amdgpu: Reinit FW shared flags on VCN v5.0.1
+
+From: Lijo Lazar <lijo.lazar@amd.com>
+
+[ Upstream commit 6ef5ccaad76d907d4257f20de992f89c0f7a7f8e ]
+
+After a full device reset, shared memory region will clear out and it's
+not possible to reliably save the region in case of RAS errors.
+Reinitialize the flags if required.
+
+Signed-off-by: Lijo Lazar <lijo.lazar@amd.com>
+Reviewed-by: Hawking Zhang <Hawking.Zhang@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c | 28 ++++++++++++++++++-------
+ 1 file changed, 20 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c
+index 8b0b3739a5377..cdbc10d7c9fb7 100644
+--- a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c
++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c
+@@ -65,6 +65,22 @@ static int vcn_v5_0_1_early_init(struct amdgpu_ip_block *ip_block)
+ return amdgpu_vcn_early_init(adev);
+ }
+
++static void vcn_v5_0_1_fw_shared_init(struct amdgpu_device *adev, int inst_idx)
++{
++ struct amdgpu_vcn5_fw_shared *fw_shared;
++
++ fw_shared = adev->vcn.inst[inst_idx].fw_shared.cpu_addr;
++
++ if (fw_shared->sq.is_enabled)
++ return;
++ fw_shared->present_flag_0 =
++ cpu_to_le32(AMDGPU_FW_SHARED_FLAG_0_UNIFIED_QUEUE);
++ fw_shared->sq.is_enabled = 1;
++
++ if (amdgpu_vcnfw_log)
++ amdgpu_vcn_fwlog_init(&adev->vcn.inst[inst_idx]);
++}
++
+ /**
+ * vcn_v5_0_1_sw_init - sw init for VCN block
+ *
+@@ -95,8 +111,6 @@ static int vcn_v5_0_1_sw_init(struct amdgpu_ip_block *ip_block)
+ return r;
+
+ for (i = 0; i < adev->vcn.num_vcn_inst; i++) {
+- volatile struct amdgpu_vcn5_fw_shared *fw_shared;
+-
+ vcn_inst = GET_INST(VCN, i);
+
+ ring = &adev->vcn.inst[i].ring_enc[0];
+@@ -111,12 +125,7 @@ static int vcn_v5_0_1_sw_init(struct amdgpu_ip_block *ip_block)
+ if (r)
+ return r;
+
+- fw_shared = adev->vcn.inst[i].fw_shared.cpu_addr;
+- fw_shared->present_flag_0 = cpu_to_le32(AMDGPU_FW_SHARED_FLAG_0_UNIFIED_QUEUE);
+- fw_shared->sq.is_enabled = true;
+-
+- if (amdgpu_vcnfw_log)
+- amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
++ vcn_v5_0_1_fw_shared_init(adev, i);
+ }
+
+ /* TODO: Add queue reset mask when FW fully supports it */
+@@ -188,6 +197,9 @@ static int vcn_v5_0_1_hw_init(struct amdgpu_ip_block *ip_block)
+ 9 * vcn_inst),
+ adev->vcn.inst[i].aid_id);
+
++ /* Re-init fw_shared, if required */
++ vcn_v5_0_1_fw_shared_init(adev, i);
++
+ r = amdgpu_ring_test_helper(ring);
+ if (r)
+ return r;
+--
+2.39.5
+
--- /dev/null
+From 91b46ec06a5895e75f639882a627500009c229b3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 14 Mar 2025 10:27:55 +0800
+Subject: drm/amdgpu: release xcp_mgr on exit
+
+From: Flora Cui <flora.cui@amd.com>
+
+[ Upstream commit b5aaa82e2b12feaaa6958f7fa0917ddcc03c24ee ]
+
+Free on driver cleanup.
+
+Reviewed-by: Lijo Lazar <lijo.lazar@amd.com>
+Signed-off-by: Flora Cui <flora.cui@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+index c00a01c62724a..ea50f82b547d9 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+@@ -4778,6 +4778,9 @@ void amdgpu_device_fini_sw(struct amdgpu_device *adev)
+ kfree(adev->fru_info);
+ adev->fru_info = NULL;
+
++ kfree(adev->xcp_mgr);
++ adev->xcp_mgr = NULL;
++
+ px = amdgpu_device_supports_px(adev_to_drm(adev));
+
+ if (px || (!dev_is_removable(&adev->pdev->dev) &&
+--
+2.39.5
+
--- /dev/null
+From be5eede0e596af1e3235b4930e0eb99c82893b57 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jan 2025 16:28:49 +0100
+Subject: drm/amdgpu: remove all KFD fences from the BO on release
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Christian König <christian.koenig@amd.com>
+
+[ Upstream commit cb0de06d1b0afb2d0c600ad748069f5ce27730ec ]
+
+Remove all KFD BOs from the private dma_resv object.
+
+This prevents the KFD from being evict unecessarily when an exported BO
+is released.
+
+Signed-off-by: Christian König <christian.koenig@amd.com>
+Signed-off-by: James Zhu <James.Zhu@amd.com>
+Reviewed-by: Felix Kuehling <felix.kuehling@amd.com>
+Reviewed-and-tested-by: James Zhu <James.Zhu@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h | 5 +-
+ .../gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c | 52 ++++++++-----------
+ drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 38 ++++++++------
+ 3 files changed, 47 insertions(+), 48 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
+index 8af67f18500a7..2f48dc5747aa2 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
+@@ -192,7 +192,7 @@ int kfd_debugfs_kfd_mem_limits(struct seq_file *m, void *data);
+ #if IS_ENABLED(CONFIG_HSA_AMD)
+ bool amdkfd_fence_check_mm(struct dma_fence *f, struct mm_struct *mm);
+ struct amdgpu_amdkfd_fence *to_amdgpu_amdkfd_fence(struct dma_fence *f);
+-int amdgpu_amdkfd_remove_fence_on_pt_pd_bos(struct amdgpu_bo *bo);
++void amdgpu_amdkfd_remove_all_eviction_fences(struct amdgpu_bo *bo);
+ int amdgpu_amdkfd_evict_userptr(struct mmu_interval_notifier *mni,
+ unsigned long cur_seq, struct kgd_mem *mem);
+ int amdgpu_amdkfd_bo_validate_and_fence(struct amdgpu_bo *bo,
+@@ -212,9 +212,8 @@ struct amdgpu_amdkfd_fence *to_amdgpu_amdkfd_fence(struct dma_fence *f)
+ }
+
+ static inline
+-int amdgpu_amdkfd_remove_fence_on_pt_pd_bos(struct amdgpu_bo *bo)
++void amdgpu_amdkfd_remove_all_eviction_fences(struct amdgpu_bo *bo)
+ {
+- return 0;
+ }
+
+ static inline
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
+index 70224b9f54f2f..c0aaa72b6c210 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
+@@ -370,40 +370,32 @@ static int amdgpu_amdkfd_remove_eviction_fence(struct amdgpu_bo *bo,
+ return 0;
+ }
+
+-int amdgpu_amdkfd_remove_fence_on_pt_pd_bos(struct amdgpu_bo *bo)
++/**
++ * amdgpu_amdkfd_remove_all_eviction_fences - Remove all eviction fences
++ * @bo: the BO where to remove the evictions fences from.
++ *
++ * This functions should only be used on release when all references to the BO
++ * are already dropped. We remove the eviction fence from the private copy of
++ * the dma_resv object here since that is what is used during release to
++ * determine of the BO is idle or not.
++ */
++void amdgpu_amdkfd_remove_all_eviction_fences(struct amdgpu_bo *bo)
+ {
+- struct amdgpu_bo *root = bo;
+- struct amdgpu_vm_bo_base *vm_bo;
+- struct amdgpu_vm *vm;
+- struct amdkfd_process_info *info;
+- struct amdgpu_amdkfd_fence *ef;
+- int ret;
+-
+- /* we can always get vm_bo from root PD bo.*/
+- while (root->parent)
+- root = root->parent;
++ struct dma_resv *resv = &bo->tbo.base._resv;
++ struct dma_fence *fence, *stub;
++ struct dma_resv_iter cursor;
+
+- vm_bo = root->vm_bo;
+- if (!vm_bo)
+- return 0;
++ dma_resv_assert_held(resv);
+
+- vm = vm_bo->vm;
+- if (!vm)
+- return 0;
+-
+- info = vm->process_info;
+- if (!info || !info->eviction_fence)
+- return 0;
+-
+- ef = container_of(dma_fence_get(&info->eviction_fence->base),
+- struct amdgpu_amdkfd_fence, base);
+-
+- BUG_ON(!dma_resv_trylock(bo->tbo.base.resv));
+- ret = amdgpu_amdkfd_remove_eviction_fence(bo, ef);
+- dma_resv_unlock(bo->tbo.base.resv);
++ stub = dma_fence_get_stub();
++ dma_resv_for_each_fence(&cursor, resv, DMA_RESV_USAGE_BOOKKEEP, fence) {
++ if (!to_amdgpu_amdkfd_fence(fence))
++ continue;
+
+- dma_fence_put(&ef->base);
+- return ret;
++ dma_resv_replace_fences(resv, fence->context, stub,
++ DMA_RESV_USAGE_BOOKKEEP);
++ }
++ dma_fence_put(stub);
+ }
+
+ static int amdgpu_amdkfd_bo_validate(struct amdgpu_bo *bo, uint32_t domain,
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
+index 00752e3f9d8ab..0b9987781f762 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
+@@ -1295,28 +1295,36 @@ void amdgpu_bo_release_notify(struct ttm_buffer_object *bo)
+ if (abo->kfd_bo)
+ amdgpu_amdkfd_release_notify(abo);
+
+- /* We only remove the fence if the resv has individualized. */
+- WARN_ON_ONCE(bo->type == ttm_bo_type_kernel
+- && bo->base.resv != &bo->base._resv);
+- if (bo->base.resv == &bo->base._resv)
+- amdgpu_amdkfd_remove_fence_on_pt_pd_bos(abo);
++ /*
++ * We lock the private dma_resv object here and since the BO is about to
++ * be released nobody else should have a pointer to it.
++ * So when this locking here fails something is wrong with the reference
++ * counting.
++ */
++ if (WARN_ON_ONCE(!dma_resv_trylock(&bo->base._resv)))
++ return;
++
++ amdgpu_amdkfd_remove_all_eviction_fences(abo);
+
+ if (!bo->resource || bo->resource->mem_type != TTM_PL_VRAM ||
+ !(abo->flags & AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE) ||
+ adev->in_suspend || drm_dev_is_unplugged(adev_to_drm(adev)))
+- return;
++ goto out;
+
+- if (WARN_ON_ONCE(!dma_resv_trylock(bo->base.resv)))
+- return;
++ r = dma_resv_reserve_fences(&bo->base._resv, 1);
++ if (r)
++ goto out;
+
+- r = amdgpu_fill_buffer(abo, 0, bo->base.resv, &fence, true);
+- if (!WARN_ON(r)) {
+- amdgpu_vram_mgr_set_cleared(bo->resource);
+- amdgpu_bo_fence(abo, fence, false);
+- dma_fence_put(fence);
+- }
++ r = amdgpu_fill_buffer(abo, 0, &bo->base._resv, &fence, true);
++ if (WARN_ON(r))
++ goto out;
++
++ amdgpu_vram_mgr_set_cleared(bo->resource);
++ dma_resv_add_fence(&bo->base._resv, fence, DMA_RESV_USAGE_KERNEL);
++ dma_fence_put(fence);
+
+- dma_resv_unlock(bo->base.resv);
++out:
++ dma_resv_unlock(&bo->base._resv);
+ }
+
+ /**
+--
+2.39.5
+
--- /dev/null
+From 8c633a1f8cc2921a8376842cf1715fcf60311d71 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 7 Feb 2025 14:28:49 +0800
+Subject: drm/amdgpu: reset psp->cmd to NULL after releasing the buffer
+
+From: Jiang Liu <gerry@linux.alibaba.com>
+
+[ Upstream commit e92f3f94cad24154fd3baae30c6dfb918492278d ]
+
+Reset psp->cmd to NULL after releasing the buffer in function psp_sw_fini().
+
+Reviewed-by: Lijo Lazar <lijo.lazar@amd.com>
+Signed-off-by: Jiang Liu <gerry@linux.alibaba.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
+index e5fc80ed06eae..665cc277cdc05 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
+@@ -533,7 +533,6 @@ static int psp_sw_fini(struct amdgpu_ip_block *ip_block)
+ {
+ struct amdgpu_device *adev = ip_block->adev;
+ struct psp_context *psp = &adev->psp;
+- struct psp_gfx_cmd_resp *cmd = psp->cmd;
+
+ psp_memory_training_fini(psp);
+
+@@ -543,8 +542,8 @@ static int psp_sw_fini(struct amdgpu_ip_block *ip_block)
+ amdgpu_ucode_release(&psp->cap_fw);
+ amdgpu_ucode_release(&psp->toc_fw);
+
+- kfree(cmd);
+- cmd = NULL;
++ kfree(psp->cmd);
++ psp->cmd = NULL;
+
+ psp_free_shared_bufs(psp);
+
+--
+2.39.5
+
--- /dev/null
+From 9277ad4e70972c95f278c0da0f2f280d1603b5e1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 15 Jan 2025 13:44:26 +0100
+Subject: drm/amdgpu: rework how isolation is enforced v2
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Christian König <christian.koenig@amd.com>
+
+[ Upstream commit bd22e44ad415ac22e3a4f9a983d2a085f6cb4427 ]
+
+Limiting the number of available VMIDs to enforce isolation causes some
+issues with gang submit and applying certain HW workarounds which
+require multiple VMIDs to work correctly.
+
+So instead start to track all submissions to the relevant engines in a
+per partition data structure and use the dma_fences of the submissions
+to enforce isolation similar to what a VMID limit does.
+
+v2: use ~0l for jobs without isolation to distinct it from kernel
+ submissions which uses NULL for the owner. Add some warning when we
+ are OOM.
+
+Signed-off-by: Christian König <christian.koenig@amd.com>
+Acked-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu.h | 13 ++-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 98 +++++++++++++++++++++-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c | 43 ++++------
+ drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 16 +++-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c | 19 +++++
+ drivers/gpu/drm/amd/amdgpu/amdgpu_sync.h | 1 +
+ 6 files changed, 155 insertions(+), 35 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+index 416d2611fbf1c..90f688b3d9d36 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+@@ -1187,9 +1187,15 @@ struct amdgpu_device {
+ bool debug_enable_ras_aca;
+ bool debug_exp_resets;
+
+- bool enforce_isolation[MAX_XCP];
+- /* Added this mutex for cleaner shader isolation between GFX and compute processes */
++ /* Protection for the following isolation structure */
+ struct mutex enforce_isolation_mutex;
++ bool enforce_isolation[MAX_XCP];
++ struct amdgpu_isolation {
++ void *owner;
++ struct dma_fence *spearhead;
++ struct amdgpu_sync active;
++ struct amdgpu_sync prev;
++ } isolation[MAX_XCP];
+
+ struct amdgpu_init_level *init_lvl;
+ };
+@@ -1470,6 +1476,9 @@ void amdgpu_device_pcie_port_wreg(struct amdgpu_device *adev,
+ struct dma_fence *amdgpu_device_get_gang(struct amdgpu_device *adev);
+ struct dma_fence *amdgpu_device_switch_gang(struct amdgpu_device *adev,
+ struct dma_fence *gang);
++struct dma_fence *amdgpu_device_enforce_isolation(struct amdgpu_device *adev,
++ struct amdgpu_ring *ring,
++ struct amdgpu_job *job);
+ bool amdgpu_device_has_display_hardware(struct amdgpu_device *adev);
+ ssize_t amdgpu_get_soft_full_reset_mask(struct amdgpu_ring *ring);
+ ssize_t amdgpu_show_reset_mask(char *buf, uint32_t supported_reset);
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+index 34f0451b274c8..726c4854e6296 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+@@ -4232,6 +4232,11 @@ int amdgpu_device_init(struct amdgpu_device *adev,
+ mutex_init(&adev->gfx.reset_sem_mutex);
+ /* Initialize the mutex for cleaner shader isolation between GFX and compute processes */
+ mutex_init(&adev->enforce_isolation_mutex);
++ for (i = 0; i < MAX_XCP; ++i) {
++ adev->isolation[i].spearhead = dma_fence_get_stub();
++ amdgpu_sync_create(&adev->isolation[i].active);
++ amdgpu_sync_create(&adev->isolation[i].prev);
++ }
+ mutex_init(&adev->gfx.kfd_sch_mutex);
+
+ amdgpu_device_init_apu_flags(adev);
+@@ -4731,7 +4736,7 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev)
+
+ void amdgpu_device_fini_sw(struct amdgpu_device *adev)
+ {
+- int idx;
++ int i, idx;
+ bool px;
+
+ amdgpu_device_ip_fini(adev);
+@@ -4739,6 +4744,11 @@ void amdgpu_device_fini_sw(struct amdgpu_device *adev)
+ amdgpu_ucode_release(&adev->firmware.gpu_info_fw);
+ adev->accel_working = false;
+ dma_fence_put(rcu_dereference_protected(adev->gang_submit, true));
++ for (i = 0; i < MAX_XCP; ++i) {
++ dma_fence_put(adev->isolation[i].spearhead);
++ amdgpu_sync_free(&adev->isolation[i].active);
++ amdgpu_sync_free(&adev->isolation[i].prev);
++ }
+
+ amdgpu_reset_fini(adev);
+
+@@ -6860,6 +6870,92 @@ struct dma_fence *amdgpu_device_switch_gang(struct amdgpu_device *adev,
+ return NULL;
+ }
+
++/**
++ * amdgpu_device_enforce_isolation - enforce HW isolation
++ * @adev: the amdgpu device pointer
++ * @ring: the HW ring the job is supposed to run on
++ * @job: the job which is about to be pushed to the HW ring
++ *
++ * Makes sure that only one client at a time can use the GFX block.
++ * Returns: The dependency to wait on before the job can be pushed to the HW.
++ * The function is called multiple times until NULL is returned.
++ */
++struct dma_fence *amdgpu_device_enforce_isolation(struct amdgpu_device *adev,
++ struct amdgpu_ring *ring,
++ struct amdgpu_job *job)
++{
++ struct amdgpu_isolation *isolation = &adev->isolation[ring->xcp_id];
++ struct drm_sched_fence *f = job->base.s_fence;
++ struct dma_fence *dep;
++ void *owner;
++ int r;
++
++ /*
++ * For now enforce isolation only for the GFX block since we only need
++ * the cleaner shader on those rings.
++ */
++ if (ring->funcs->type != AMDGPU_RING_TYPE_GFX &&
++ ring->funcs->type != AMDGPU_RING_TYPE_COMPUTE)
++ return NULL;
++
++ /*
++ * All submissions where enforce isolation is false are handled as if
++ * they come from a single client. Use ~0l as the owner to distinct it
++ * from kernel submissions where the owner is NULL.
++ */
++ owner = job->enforce_isolation ? f->owner : (void *)~0l;
++
++ mutex_lock(&adev->enforce_isolation_mutex);
++
++ /*
++ * The "spearhead" submission is the first one which changes the
++ * ownership to its client. We always need to wait for it to be
++ * pushed to the HW before proceeding with anything.
++ */
++ if (&f->scheduled != isolation->spearhead &&
++ !dma_fence_is_signaled(isolation->spearhead)) {
++ dep = isolation->spearhead;
++ goto out_grab_ref;
++ }
++
++ if (isolation->owner != owner) {
++
++ /*
++ * Wait for any gang to be assembled before switching to a
++ * different owner or otherwise we could deadlock the
++ * submissions.
++ */
++ if (!job->gang_submit) {
++ dep = amdgpu_device_get_gang(adev);
++ if (!dma_fence_is_signaled(dep))
++ goto out_return_dep;
++ dma_fence_put(dep);
++ }
++
++ dma_fence_put(isolation->spearhead);
++ isolation->spearhead = dma_fence_get(&f->scheduled);
++ amdgpu_sync_move(&isolation->active, &isolation->prev);
++ isolation->owner = owner;
++ }
++
++ /*
++ * Specifying the ring here helps to pipeline submissions even when
++ * isolation is enabled. If that is not desired for testing NULL can be
++ * used instead of the ring to enforce a CPU round trip while switching
++ * between clients.
++ */
++ dep = amdgpu_sync_peek_fence(&isolation->prev, ring);
++ r = amdgpu_sync_fence(&isolation->active, &f->finished, GFP_NOWAIT);
++ if (r)
++ DRM_WARN("OOM tracking isolation\n");
++
++out_grab_ref:
++ dma_fence_get(dep);
++out_return_dep:
++ mutex_unlock(&adev->enforce_isolation_mutex);
++ return dep;
++}
++
+ bool amdgpu_device_has_display_hardware(struct amdgpu_device *adev)
+ {
+ switch (adev->asic_type) {
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
+index 8e712a11aba5d..9008b7388e897 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
+@@ -287,40 +287,27 @@ static int amdgpu_vmid_grab_reserved(struct amdgpu_vm *vm,
+ (*id)->flushed_updates < updates ||
+ !(*id)->last_flush ||
+ ((*id)->last_flush->context != fence_context &&
+- !dma_fence_is_signaled((*id)->last_flush))) {
++ !dma_fence_is_signaled((*id)->last_flush)))
++ needs_flush = true;
++
++ if ((*id)->owner != vm->immediate.fence_context ||
++ (!adev->vm_manager.concurrent_flush && needs_flush)) {
+ struct dma_fence *tmp;
+
+- /* Wait for the gang to be assembled before using a
+- * reserved VMID or otherwise the gang could deadlock.
++ /* Don't use per engine and per process VMID at the
++ * same time
+ */
+- tmp = amdgpu_device_get_gang(adev);
+- if (!dma_fence_is_signaled(tmp) && tmp != job->gang_submit) {
++ if (adev->vm_manager.concurrent_flush)
++ ring = NULL;
++
++ /* to prevent one context starved by another context */
++ (*id)->pd_gpu_addr = 0;
++ tmp = amdgpu_sync_peek_fence(&(*id)->active, ring);
++ if (tmp) {
+ *id = NULL;
+- *fence = tmp;
++ *fence = dma_fence_get(tmp);
+ return 0;
+ }
+- dma_fence_put(tmp);
+-
+- /* Make sure the id is owned by the gang before proceeding */
+- if (!job->gang_submit ||
+- (*id)->owner != vm->immediate.fence_context) {
+-
+- /* Don't use per engine and per process VMID at the
+- * same time
+- */
+- if (adev->vm_manager.concurrent_flush)
+- ring = NULL;
+-
+- /* to prevent one context starved by another context */
+- (*id)->pd_gpu_addr = 0;
+- tmp = amdgpu_sync_peek_fence(&(*id)->active, ring);
+- if (tmp) {
+- *id = NULL;
+- *fence = dma_fence_get(tmp);
+- return 0;
+- }
+- }
+- needs_flush = true;
+ }
+
+ /* Good we can use this VMID. Remember this submission as
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
+index 100f044759435..685c61a05af85 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
+@@ -342,17 +342,24 @@ amdgpu_job_prepare_job(struct drm_sched_job *sched_job,
+ {
+ struct amdgpu_ring *ring = to_amdgpu_ring(s_entity->rq->sched);
+ struct amdgpu_job *job = to_amdgpu_job(sched_job);
+- struct dma_fence *fence = NULL;
++ struct dma_fence *fence;
+ int r;
+
+ r = drm_sched_entity_error(s_entity);
+ if (r)
+ goto error;
+
+- if (job->gang_submit)
++ if (job->gang_submit) {
+ fence = amdgpu_device_switch_gang(ring->adev, job->gang_submit);
++ if (fence)
++ return fence;
++ }
++
++ fence = amdgpu_device_enforce_isolation(ring->adev, ring, job);
++ if (fence)
++ return fence;
+
+- if (!fence && job->vm && !job->vmid) {
++ if (job->vm && !job->vmid) {
+ r = amdgpu_vmid_grab(job->vm, ring, job, &fence);
+ if (r) {
+ dev_err(ring->adev->dev, "Error getting VM ID (%d)\n", r);
+@@ -365,9 +372,10 @@ amdgpu_job_prepare_job(struct drm_sched_job *sched_job,
+ */
+ if (!fence)
+ job->vm = NULL;
++ return fence;
+ }
+
+- return fence;
++ return NULL;
+
+ error:
+ dma_fence_set_error(&job->base.s_fence->finished, r);
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c
+index c586ab4c911bf..d75715b3f1870 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c
+@@ -399,6 +399,25 @@ int amdgpu_sync_clone(struct amdgpu_sync *source, struct amdgpu_sync *clone)
+ return 0;
+ }
+
++/**
++ * amdgpu_sync_move - move all fences from src to dst
++ *
++ * @src: source of the fences, empty after function
++ * @dst: destination for the fences
++ *
++ * Moves all fences from source to destination. All fences in destination are
++ * freed and source is empty after the function call.
++ */
++void amdgpu_sync_move(struct amdgpu_sync *src, struct amdgpu_sync *dst)
++{
++ unsigned int i;
++
++ amdgpu_sync_free(dst);
++
++ for (i = 0; i < HASH_SIZE(src->fences); ++i)
++ hlist_move_list(&src->fences[i], &dst->fences[i]);
++}
++
+ /**
+ * amdgpu_sync_push_to_job - push fences into job
+ * @sync: sync object to get the fences from
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.h
+index e3272dce798d7..a91a8eaf808b1 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.h
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.h
+@@ -56,6 +56,7 @@ struct dma_fence *amdgpu_sync_peek_fence(struct amdgpu_sync *sync,
+ struct amdgpu_ring *ring);
+ struct dma_fence *amdgpu_sync_get_fence(struct amdgpu_sync *sync);
+ int amdgpu_sync_clone(struct amdgpu_sync *source, struct amdgpu_sync *clone);
++void amdgpu_sync_move(struct amdgpu_sync *src, struct amdgpu_sync *dst);
+ int amdgpu_sync_push_to_job(struct amdgpu_sync *sync, struct amdgpu_job *job);
+ int amdgpu_sync_wait(struct amdgpu_sync *sync, bool intr);
+ void amdgpu_sync_free(struct amdgpu_sync *sync);
+--
+2.39.5
+
--- /dev/null
+From 4e5064159649a302cb84e0caac996f33c430bec1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jan 2025 15:09:45 +0100
+Subject: drm/amdgpu: rework how the cleaner shader is emitted v3
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Christian König <christian.koenig@amd.com>
+
+[ Upstream commit b7fbcd77bb467d09ba14cb4ec3b121dc85bb3100 ]
+
+Instead of emitting the cleaner shader for every job which has the
+enforce_isolation flag set only emit it for the first submission from
+every client.
+
+v2: add missing NULL check
+v3: fix another NULL pointer deref
+
+Signed-off-by: Christian König <christian.koenig@amd.com>
+Acked-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 27 ++++++++++++++++++++------
+ 1 file changed, 21 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+index 22aa4a8f11891..f0d675c0fc69c 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+@@ -754,6 +754,7 @@ int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job,
+ bool need_pipe_sync)
+ {
+ struct amdgpu_device *adev = ring->adev;
++ struct amdgpu_isolation *isolation = &adev->isolation[ring->xcp_id];
+ unsigned vmhub = ring->vm_hub;
+ struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub];
+ struct amdgpu_vmid *id = &id_mgr->ids[job->vmid];
+@@ -761,8 +762,9 @@ int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job,
+ bool gds_switch_needed = ring->funcs->emit_gds_switch &&
+ job->gds_switch_needed;
+ bool vm_flush_needed = job->vm_needs_flush;
+- struct dma_fence *fence = NULL;
++ bool cleaner_shader_needed = false;
+ bool pasid_mapping_needed = false;
++ struct dma_fence *fence = NULL;
+ unsigned int patch;
+ int r;
+
+@@ -785,8 +787,12 @@ int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job,
+ pasid_mapping_needed &= adev->gmc.gmc_funcs->emit_pasid_mapping &&
+ ring->funcs->emit_wreg;
+
++ cleaner_shader_needed = adev->gfx.enable_cleaner_shader &&
++ ring->funcs->emit_cleaner_shader && job->base.s_fence &&
++ &job->base.s_fence->scheduled == isolation->spearhead;
++
+ if (!vm_flush_needed && !gds_switch_needed && !need_pipe_sync &&
+- !(job->enforce_isolation && !job->vmid))
++ !cleaner_shader_needed)
+ return 0;
+
+ amdgpu_ring_ib_begin(ring);
+@@ -797,9 +803,7 @@ int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job,
+ if (need_pipe_sync)
+ amdgpu_ring_emit_pipeline_sync(ring);
+
+- if (adev->gfx.enable_cleaner_shader &&
+- ring->funcs->emit_cleaner_shader &&
+- job->enforce_isolation)
++ if (cleaner_shader_needed)
+ ring->funcs->emit_cleaner_shader(ring);
+
+ if (vm_flush_needed) {
+@@ -821,7 +825,7 @@ int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job,
+ job->oa_size);
+ }
+
+- if (vm_flush_needed || pasid_mapping_needed) {
++ if (vm_flush_needed || pasid_mapping_needed || cleaner_shader_needed) {
+ r = amdgpu_fence_emit(ring, &fence, NULL, 0);
+ if (r)
+ return r;
+@@ -843,6 +847,17 @@ int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job,
+ id->pasid_mapping = dma_fence_get(fence);
+ mutex_unlock(&id_mgr->lock);
+ }
++
++ /*
++ * Make sure that all other submissions wait for the cleaner shader to
++ * finish before we push them to the HW.
++ */
++ if (cleaner_shader_needed) {
++ mutex_lock(&adev->enforce_isolation_mutex);
++ dma_fence_put(isolation->spearhead);
++ isolation->spearhead = dma_fence_get(fence);
++ mutex_unlock(&adev->enforce_isolation_mutex);
++ }
+ dma_fence_put(fence);
+
+ amdgpu_ring_patch_cond_exec(ring, patch);
+--
+2.39.5
+
--- /dev/null
+From 7352224475466eb69abc7abc02f18c6e407dfc07 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Feb 2025 17:57:47 -0500
+Subject: drm/amdgpu: Set snoop bit for SDMA for MI series
+
+From: Harish Kasiviswanathan <Harish.Kasiviswanathan@amd.com>
+
+[ Upstream commit 3394b1f76d3f8adf695ceed350a5dae49003eb37 ]
+
+SDMA writes has to probe invalidate RW lines. Set snoop bit in mmhub for
+this to happen.
+
+v2: Missed a few mmhub_v9_4. Added now.
+v3: Calculate hub offset once since it doesn't change inside the loop
+ Modified function names based on review comments.
+
+Signed-off-by: Harish Kasiviswanathan <Harish.Kasiviswanathan@amd.com>
+Reviewed-by: Philip Yang <Philip.Yang@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/mmhub_v1_7.c | 25 ++++++++++
+ drivers/gpu/drm/amd/amdgpu/mmhub_v1_8.c | 27 +++++++++++
+ drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c | 31 ++++++++++++
+ .../asic_reg/mmhub/mmhub_9_4_1_offset.h | 32 +++++++++++++
+ .../asic_reg/mmhub/mmhub_9_4_1_sh_mask.h | 48 +++++++++++++++++++
+ 5 files changed, 163 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_7.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_7.c
+index 9689e2b5d4e51..2adee2b94c37d 100644
+--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_7.c
++++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_7.c
+@@ -172,6 +172,30 @@ static void mmhub_v1_7_init_tlb_regs(struct amdgpu_device *adev)
+ WREG32_SOC15(MMHUB, 0, regMC_VM_MX_L1_TLB_CNTL, tmp);
+ }
+
++/* Set snoop bit for SDMA so that SDMA writes probe-invalidates RW lines */
++static void mmhub_v1_7_init_snoop_override_regs(struct amdgpu_device *adev)
++{
++ uint32_t tmp;
++ int i;
++ uint32_t distance = regDAGB1_WRCLI_GPU_SNOOP_OVERRIDE -
++ regDAGB0_WRCLI_GPU_SNOOP_OVERRIDE;
++
++ for (i = 0; i < 5; i++) { /* DAGB instances */
++ tmp = RREG32_SOC15_OFFSET(MMHUB, 0,
++ regDAGB0_WRCLI_GPU_SNOOP_OVERRIDE, i * distance);
++ tmp |= (1 << 15); /* SDMA client is BIT15 */
++ WREG32_SOC15_OFFSET(MMHUB, 0,
++ regDAGB0_WRCLI_GPU_SNOOP_OVERRIDE, i * distance, tmp);
++
++ tmp = RREG32_SOC15_OFFSET(MMHUB, 0,
++ regDAGB0_WRCLI_GPU_SNOOP_OVERRIDE_VALUE, i * distance);
++ tmp |= (1 << 15);
++ WREG32_SOC15_OFFSET(MMHUB, 0,
++ regDAGB0_WRCLI_GPU_SNOOP_OVERRIDE_VALUE, i * distance, tmp);
++ }
++
++}
++
+ static void mmhub_v1_7_init_cache_regs(struct amdgpu_device *adev)
+ {
+ uint32_t tmp;
+@@ -337,6 +361,7 @@ static int mmhub_v1_7_gart_enable(struct amdgpu_device *adev)
+ mmhub_v1_7_init_system_aperture_regs(adev);
+ mmhub_v1_7_init_tlb_regs(adev);
+ mmhub_v1_7_init_cache_regs(adev);
++ mmhub_v1_7_init_snoop_override_regs(adev);
+
+ mmhub_v1_7_enable_system_domain(adev);
+ mmhub_v1_7_disable_identity_aperture(adev);
+diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_8.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_8.c
+index e646e5cef0a2e..ce013a715b864 100644
+--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_8.c
++++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_8.c
+@@ -213,6 +213,32 @@ static void mmhub_v1_8_init_tlb_regs(struct amdgpu_device *adev)
+ }
+ }
+
++/* Set snoop bit for SDMA so that SDMA writes probe-invalidates RW lines */
++static void mmhub_v1_8_init_snoop_override_regs(struct amdgpu_device *adev)
++{
++ uint32_t tmp, inst_mask;
++ int i, j;
++ uint32_t distance = regDAGB1_WRCLI_GPU_SNOOP_OVERRIDE -
++ regDAGB0_WRCLI_GPU_SNOOP_OVERRIDE;
++
++ inst_mask = adev->aid_mask;
++ for_each_inst(i, inst_mask) {
++ for (j = 0; j < 5; j++) { /* DAGB instances */
++ tmp = RREG32_SOC15_OFFSET(MMHUB, i,
++ regDAGB0_WRCLI_GPU_SNOOP_OVERRIDE, j * distance);
++ tmp |= (1 << 15); /* SDMA client is BIT15 */
++ WREG32_SOC15_OFFSET(MMHUB, i,
++ regDAGB0_WRCLI_GPU_SNOOP_OVERRIDE, j * distance, tmp);
++
++ tmp = RREG32_SOC15_OFFSET(MMHUB, i,
++ regDAGB0_WRCLI_GPU_SNOOP_OVERRIDE_VALUE, j * distance);
++ tmp |= (1 << 15);
++ WREG32_SOC15_OFFSET(MMHUB, i,
++ regDAGB0_WRCLI_GPU_SNOOP_OVERRIDE_VALUE, j * distance, tmp);
++ }
++ }
++}
++
+ static void mmhub_v1_8_init_cache_regs(struct amdgpu_device *adev)
+ {
+ uint32_t tmp, inst_mask;
+@@ -418,6 +444,7 @@ static int mmhub_v1_8_gart_enable(struct amdgpu_device *adev)
+ mmhub_v1_8_init_system_aperture_regs(adev);
+ mmhub_v1_8_init_tlb_regs(adev);
+ mmhub_v1_8_init_cache_regs(adev);
++ mmhub_v1_8_init_snoop_override_regs(adev);
+
+ mmhub_v1_8_enable_system_domain(adev);
+ mmhub_v1_8_disable_identity_aperture(adev);
+diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c
+index ff1b58e446892..fe0710b55c3ac 100644
+--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c
++++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c
+@@ -198,6 +198,36 @@ static void mmhub_v9_4_init_tlb_regs(struct amdgpu_device *adev, int hubid)
+ hubid * MMHUB_INSTANCE_REGISTER_OFFSET, tmp);
+ }
+
++/* Set snoop bit for SDMA so that SDMA writes probe-invalidates RW lines */
++static void mmhub_v9_4_init_snoop_override_regs(struct amdgpu_device *adev, int hubid)
++{
++ uint32_t tmp;
++ int i;
++ uint32_t distance = mmDAGB1_WRCLI_GPU_SNOOP_OVERRIDE -
++ mmDAGB0_WRCLI_GPU_SNOOP_OVERRIDE;
++ uint32_t huboffset = hubid * MMHUB_INSTANCE_REGISTER_OFFSET;
++
++ for (i = 0; i < 5 - (2 * hubid); i++) {
++ /* DAGB instances 0 to 4 are in hub0 and 5 to 7 are in hub1 */
++ tmp = RREG32_SOC15_OFFSET(MMHUB, 0,
++ mmDAGB0_WRCLI_GPU_SNOOP_OVERRIDE,
++ huboffset + i * distance);
++ tmp |= (1 << 15); /* SDMA client is BIT15 */
++ WREG32_SOC15_OFFSET(MMHUB, 0,
++ mmDAGB0_WRCLI_GPU_SNOOP_OVERRIDE,
++ huboffset + i * distance, tmp);
++
++ tmp = RREG32_SOC15_OFFSET(MMHUB, 0,
++ mmDAGB0_WRCLI_GPU_SNOOP_OVERRIDE_VALUE,
++ huboffset + i * distance);
++ tmp |= (1 << 15);
++ WREG32_SOC15_OFFSET(MMHUB, 0,
++ mmDAGB0_WRCLI_GPU_SNOOP_OVERRIDE_VALUE,
++ huboffset + i * distance, tmp);
++ }
++
++}
++
+ static void mmhub_v9_4_init_cache_regs(struct amdgpu_device *adev, int hubid)
+ {
+ uint32_t tmp;
+@@ -392,6 +422,7 @@ static int mmhub_v9_4_gart_enable(struct amdgpu_device *adev)
+ if (!amdgpu_sriov_vf(adev))
+ mmhub_v9_4_init_cache_regs(adev, i);
+
++ mmhub_v9_4_init_snoop_override_regs(adev, i);
+ mmhub_v9_4_enable_system_domain(adev, i);
+ if (!amdgpu_sriov_vf(adev))
+ mmhub_v9_4_disable_identity_aperture(adev, i);
+diff --git a/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_1_offset.h b/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_1_offset.h
+index c488d4a50cf46..b2252deabc17a 100644
+--- a/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_1_offset.h
++++ b/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_1_offset.h
+@@ -203,6 +203,10 @@
+ #define mmDAGB0_WR_DATA_CREDIT_BASE_IDX 1
+ #define mmDAGB0_WR_MISC_CREDIT 0x0058
+ #define mmDAGB0_WR_MISC_CREDIT_BASE_IDX 1
++#define mmDAGB0_WRCLI_GPU_SNOOP_OVERRIDE 0x005b
++#define mmDAGB0_WRCLI_GPU_SNOOP_OVERRIDE_BASE_IDX 1
++#define mmDAGB0_WRCLI_GPU_SNOOP_OVERRIDE_VALUE 0x005c
++#define mmDAGB0_WRCLI_GPU_SNOOP_OVERRIDE_VALUE_BASE_IDX 1
+ #define mmDAGB0_WRCLI_ASK_PENDING 0x005d
+ #define mmDAGB0_WRCLI_ASK_PENDING_BASE_IDX 1
+ #define mmDAGB0_WRCLI_GO_PENDING 0x005e
+@@ -455,6 +459,10 @@
+ #define mmDAGB1_WR_DATA_CREDIT_BASE_IDX 1
+ #define mmDAGB1_WR_MISC_CREDIT 0x00d8
+ #define mmDAGB1_WR_MISC_CREDIT_BASE_IDX 1
++#define mmDAGB1_WRCLI_GPU_SNOOP_OVERRIDE 0x00db
++#define mmDAGB1_WRCLI_GPU_SNOOP_OVERRIDE_BASE_IDX 1
++#define mmDAGB1_WRCLI_GPU_SNOOP_OVERRIDE_VALUE 0x00dc
++#define mmDAGB1_WRCLI_GPU_SNOOP_OVERRIDE_VALUE_BASE_IDX 1
+ #define mmDAGB1_WRCLI_ASK_PENDING 0x00dd
+ #define mmDAGB1_WRCLI_ASK_PENDING_BASE_IDX 1
+ #define mmDAGB1_WRCLI_GO_PENDING 0x00de
+@@ -707,6 +715,10 @@
+ #define mmDAGB2_WR_DATA_CREDIT_BASE_IDX 1
+ #define mmDAGB2_WR_MISC_CREDIT 0x0158
+ #define mmDAGB2_WR_MISC_CREDIT_BASE_IDX 1
++#define mmDAGB2_WRCLI_GPU_SNOOP_OVERRIDE 0x015b
++#define mmDAGB2_WRCLI_GPU_SNOOP_OVERRIDE_BASE_IDX 1
++#define mmDAGB2_WRCLI_GPU_SNOOP_OVERRIDE_VALUE 0x015c
++#define mmDAGB2_WRCLI_GPU_SNOOP_OVERRIDE_VALUE_BASE_IDX 1
+ #define mmDAGB2_WRCLI_ASK_PENDING 0x015d
+ #define mmDAGB2_WRCLI_ASK_PENDING_BASE_IDX 1
+ #define mmDAGB2_WRCLI_GO_PENDING 0x015e
+@@ -959,6 +971,10 @@
+ #define mmDAGB3_WR_DATA_CREDIT_BASE_IDX 1
+ #define mmDAGB3_WR_MISC_CREDIT 0x01d8
+ #define mmDAGB3_WR_MISC_CREDIT_BASE_IDX 1
++#define mmDAGB3_WRCLI_GPU_SNOOP_OVERRIDE 0x01db
++#define mmDAGB3_WRCLI_GPU_SNOOP_OVERRIDE_BASE_IDX 1
++#define mmDAGB3_WRCLI_GPU_SNOOP_OVERRIDE_VALUE 0x01dc
++#define mmDAGB3_WRCLI_GPU_SNOOP_OVERRIDE_VALUE_BASE_IDX 1
+ #define mmDAGB3_WRCLI_ASK_PENDING 0x01dd
+ #define mmDAGB3_WRCLI_ASK_PENDING_BASE_IDX 1
+ #define mmDAGB3_WRCLI_GO_PENDING 0x01de
+@@ -1211,6 +1227,10 @@
+ #define mmDAGB4_WR_DATA_CREDIT_BASE_IDX 1
+ #define mmDAGB4_WR_MISC_CREDIT 0x0258
+ #define mmDAGB4_WR_MISC_CREDIT_BASE_IDX 1
++#define mmDAGB4_WRCLI_GPU_SNOOP_OVERRIDE 0x025b
++#define mmDAGB4_WRCLI_GPU_SNOOP_OVERRIDE_BASE_IDX 1
++#define mmDAGB4_WRCLI_GPU_SNOOP_OVERRIDE_VALUE 0x025c
++#define mmDAGB4_WRCLI_GPU_SNOOP_OVERRIDE_VALUE_BASE_IDX 1
+ #define mmDAGB4_WRCLI_ASK_PENDING 0x025d
+ #define mmDAGB4_WRCLI_ASK_PENDING_BASE_IDX 1
+ #define mmDAGB4_WRCLI_GO_PENDING 0x025e
+@@ -4793,6 +4813,10 @@
+ #define mmDAGB5_WR_DATA_CREDIT_BASE_IDX 1
+ #define mmDAGB5_WR_MISC_CREDIT 0x3058
+ #define mmDAGB5_WR_MISC_CREDIT_BASE_IDX 1
++#define mmDAGB5_WRCLI_GPU_SNOOP_OVERRIDE 0x305b
++#define mmDAGB5_WRCLI_GPU_SNOOP_OVERRIDE_BASE_IDX 1
++#define mmDAGB5_WRCLI_GPU_SNOOP_OVERRIDE_VALUE 0x305c
++#define mmDAGB5_WRCLI_GPU_SNOOP_OVERRIDE_VALUE_BASE_IDX 1
+ #define mmDAGB5_WRCLI_ASK_PENDING 0x305d
+ #define mmDAGB5_WRCLI_ASK_PENDING_BASE_IDX 1
+ #define mmDAGB5_WRCLI_GO_PENDING 0x305e
+@@ -5045,6 +5069,10 @@
+ #define mmDAGB6_WR_DATA_CREDIT_BASE_IDX 1
+ #define mmDAGB6_WR_MISC_CREDIT 0x30d8
+ #define mmDAGB6_WR_MISC_CREDIT_BASE_IDX 1
++#define mmDAGB6_WRCLI_GPU_SNOOP_OVERRIDE 0x30db
++#define mmDAGB6_WRCLI_GPU_SNOOP_OVERRIDE_BASE_IDX 1
++#define mmDAGB6_WRCLI_GPU_SNOOP_OVERRIDE_VALUE 0x30dc
++#define mmDAGB6_WRCLI_GPU_SNOOP_OVERRIDE_VALUE_BASE_IDX 1
+ #define mmDAGB6_WRCLI_ASK_PENDING 0x30dd
+ #define mmDAGB6_WRCLI_ASK_PENDING_BASE_IDX 1
+ #define mmDAGB6_WRCLI_GO_PENDING 0x30de
+@@ -5297,6 +5325,10 @@
+ #define mmDAGB7_WR_DATA_CREDIT_BASE_IDX 1
+ #define mmDAGB7_WR_MISC_CREDIT 0x3158
+ #define mmDAGB7_WR_MISC_CREDIT_BASE_IDX 1
++#define mmDAGB7_WRCLI_GPU_SNOOP_OVERRIDE 0x315b
++#define mmDAGB7_WRCLI_GPU_SNOOP_OVERRIDE_BASE_IDX 1
++#define mmDAGB7_WRCLI_GPU_SNOOP_OVERRIDE_VALUE 0x315c
++#define mmDAGB7_WRCLI_GPU_SNOOP_OVERRIDE_VALUE_BASE_IDX 1
+ #define mmDAGB7_WRCLI_ASK_PENDING 0x315d
+ #define mmDAGB7_WRCLI_ASK_PENDING_BASE_IDX 1
+ #define mmDAGB7_WRCLI_GO_PENDING 0x315e
+diff --git a/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_1_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_1_sh_mask.h
+index 2969fbf282b7d..5069d2fd467f2 100644
+--- a/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_1_sh_mask.h
++++ b/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_1_sh_mask.h
+@@ -1532,6 +1532,12 @@
+ //DAGB0_WRCLI_DBUS_GO_PENDING
+ #define DAGB0_WRCLI_DBUS_GO_PENDING__BUSY__SHIFT 0x0
+ #define DAGB0_WRCLI_DBUS_GO_PENDING__BUSY_MASK 0xFFFFFFFFL
++//DAGB0_WRCLI_GPU_SNOOP_OVERRIDE
++#define DAGB0_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE__SHIFT 0x0
++#define DAGB0_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE_MASK 0xFFFFFFFFL
++//DAGB0_WRCLI_GPU_SNOOP_OVERRIDE_VALUE
++#define DAGB0_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE__SHIFT 0x0
++#define DAGB0_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE_MASK 0xFFFFFFFFL
+ //DAGB0_DAGB_DLY
+ #define DAGB0_DAGB_DLY__DLY__SHIFT 0x0
+ #define DAGB0_DAGB_DLY__CLI__SHIFT 0x8
+@@ -3207,6 +3213,12 @@
+ //DAGB1_WRCLI_DBUS_GO_PENDING
+ #define DAGB1_WRCLI_DBUS_GO_PENDING__BUSY__SHIFT 0x0
+ #define DAGB1_WRCLI_DBUS_GO_PENDING__BUSY_MASK 0xFFFFFFFFL
++//DAGB1_WRCLI_GPU_SNOOP_OVERRIDE
++#define DAGB1_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE__SHIFT 0x0
++#define DAGB1_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE_MASK 0xFFFFFFFFL
++//DAGB1_WRCLI_GPU_SNOOP_OVERRIDE_VALUE
++#define DAGB1_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE__SHIFT 0x0
++#define DAGB1_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE_MASK 0xFFFFFFFFL
+ //DAGB1_DAGB_DLY
+ #define DAGB1_DAGB_DLY__DLY__SHIFT 0x0
+ #define DAGB1_DAGB_DLY__CLI__SHIFT 0x8
+@@ -4882,6 +4894,12 @@
+ //DAGB2_WRCLI_DBUS_GO_PENDING
+ #define DAGB2_WRCLI_DBUS_GO_PENDING__BUSY__SHIFT 0x0
+ #define DAGB2_WRCLI_DBUS_GO_PENDING__BUSY_MASK 0xFFFFFFFFL
++//DAGB2_WRCLI_GPU_SNOOP_OVERRIDE
++#define DAGB2_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE__SHIFT 0x0
++#define DAGB2_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE_MASK 0xFFFFFFFFL
++//DAGB2_WRCLI_GPU_SNOOP_OVERRIDE_VALUE
++#define DAGB2_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE__SHIFT 0x0
++#define DAGB2_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE_MASK 0xFFFFFFFFL
+ //DAGB2_DAGB_DLY
+ #define DAGB2_DAGB_DLY__DLY__SHIFT 0x0
+ #define DAGB2_DAGB_DLY__CLI__SHIFT 0x8
+@@ -6557,6 +6575,12 @@
+ //DAGB3_WRCLI_DBUS_GO_PENDING
+ #define DAGB3_WRCLI_DBUS_GO_PENDING__BUSY__SHIFT 0x0
+ #define DAGB3_WRCLI_DBUS_GO_PENDING__BUSY_MASK 0xFFFFFFFFL
++//DAGB3_WRCLI_GPU_SNOOP_OVERRIDE
++#define DAGB3_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE__SHIFT 0x0
++#define DAGB3_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE_MASK 0xFFFFFFFFL
++//DAGB3_WRCLI_GPU_SNOOP_OVERRIDE_VALUE
++#define DAGB3_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE__SHIFT 0x0
++#define DAGB3_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE_MASK 0xFFFFFFFFL
+ //DAGB3_DAGB_DLY
+ #define DAGB3_DAGB_DLY__DLY__SHIFT 0x0
+ #define DAGB3_DAGB_DLY__CLI__SHIFT 0x8
+@@ -8232,6 +8256,12 @@
+ //DAGB4_WRCLI_DBUS_GO_PENDING
+ #define DAGB4_WRCLI_DBUS_GO_PENDING__BUSY__SHIFT 0x0
+ #define DAGB4_WRCLI_DBUS_GO_PENDING__BUSY_MASK 0xFFFFFFFFL
++//DAGB4_WRCLI_GPU_SNOOP_OVERRIDE
++#define DAGB4_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE__SHIFT 0x0
++#define DAGB4_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE_MASK 0xFFFFFFFFL
++//DAGB4_WRCLI_GPU_SNOOP_OVERRIDE_VALUE
++#define DAGB4_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE__SHIFT 0x0
++#define DAGB4_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE_MASK 0xFFFFFFFFL
+ //DAGB4_DAGB_DLY
+ #define DAGB4_DAGB_DLY__DLY__SHIFT 0x0
+ #define DAGB4_DAGB_DLY__CLI__SHIFT 0x8
+@@ -28737,6 +28767,12 @@
+ //DAGB5_WRCLI_DBUS_GO_PENDING
+ #define DAGB5_WRCLI_DBUS_GO_PENDING__BUSY__SHIFT 0x0
+ #define DAGB5_WRCLI_DBUS_GO_PENDING__BUSY_MASK 0xFFFFFFFFL
++//DAGB5_WRCLI_GPU_SNOOP_OVERRIDE
++#define DAGB5_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE__SHIFT 0x0
++#define DAGB5_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE_MASK 0xFFFFFFFFL
++//DAGB5_WRCLI_GPU_SNOOP_OVERRIDE_VALUE
++#define DAGB5_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE__SHIFT 0x0
++#define DAGB5_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE_MASK 0xFFFFFFFFL
+ //DAGB5_DAGB_DLY
+ #define DAGB5_DAGB_DLY__DLY__SHIFT 0x0
+ #define DAGB5_DAGB_DLY__CLI__SHIFT 0x8
+@@ -30412,6 +30448,12 @@
+ //DAGB6_WRCLI_DBUS_GO_PENDING
+ #define DAGB6_WRCLI_DBUS_GO_PENDING__BUSY__SHIFT 0x0
+ #define DAGB6_WRCLI_DBUS_GO_PENDING__BUSY_MASK 0xFFFFFFFFL
++//DAGB6_WRCLI_GPU_SNOOP_OVERRIDE
++#define DAGB6_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE__SHIFT 0x0
++#define DAGB6_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE_MASK 0xFFFFFFFFL
++//DAGB6_WRCLI_GPU_SNOOP_OVERRIDE_VALUE
++#define DAGB6_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE__SHIFT 0x0
++#define DAGB6_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE_MASK 0xFFFFFFFFL
+ //DAGB6_DAGB_DLY
+ #define DAGB6_DAGB_DLY__DLY__SHIFT 0x0
+ #define DAGB6_DAGB_DLY__CLI__SHIFT 0x8
+@@ -32087,6 +32129,12 @@
+ //DAGB7_WRCLI_DBUS_GO_PENDING
+ #define DAGB7_WRCLI_DBUS_GO_PENDING__BUSY__SHIFT 0x0
+ #define DAGB7_WRCLI_DBUS_GO_PENDING__BUSY_MASK 0xFFFFFFFFL
++//DAGB7_WRCLI_GPU_SNOOP_OVERRIDE
++#define DAGB7_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE__SHIFT 0x0
++#define DAGB7_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE_MASK 0xFFFFFFFFL
++//DAGB7_WRCLI_GPU_SNOOP_OVERRIDE_VALUE
++#define DAGB7_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE__SHIFT 0x0
++#define DAGB7_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE_MASK 0xFFFFFFFFL
+ //DAGB7_DAGB_DLY
+ #define DAGB7_DAGB_DLY__DLY__SHIFT 0x0
+ #define DAGB7_DAGB_DLY__CLI__SHIFT 0x8
+--
+2.39.5
+
--- /dev/null
+From bcbf7235d55d61a31c53cfd3de7f2fc43f340918 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 20 Jan 2025 22:00:22 -0500
+Subject: drm/amdgpu: Skip err_count sysfs creation on VF unsupported RAS
+ blocks
+
+From: Victor Skvortsov <victor.skvortsov@amd.com>
+
+[ Upstream commit 04893397766a2b2f1bc7fe5c6414e4c0846ed171 ]
+
+VFs are not able to query error counts for all RAS blocks. Rather than
+returning error for queries on these blocks, skip sysfs the creation
+all together.
+
+Signed-off-by: Victor Skvortsov <victor.skvortsov@amd.com>
+Reviewed-by: Hawking Zhang <Hawking.Zhang@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c | 3 +++
+ drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c | 17 ++++++++++++++++-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h | 2 ++
+ 3 files changed, 21 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
+index f0924aa3f4e48..0c338dcdde48a 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
+@@ -1864,6 +1864,9 @@ int amdgpu_ras_sysfs_create(struct amdgpu_device *adev,
+ if (!obj || obj->attr_inuse)
+ return -EINVAL;
+
++ if (amdgpu_sriov_vf(adev) && !amdgpu_virt_ras_telemetry_block_en(adev, head->block))
++ return 0;
++
+ get_obj(obj);
+
+ snprintf(obj->fs_data.sysfs_name, sizeof(obj->fs_data.sysfs_name),
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c
+index 13e5709ea1caa..e6f0152e5b087 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c
+@@ -1247,7 +1247,8 @@ amdgpu_ras_block_to_sriov(struct amdgpu_device *adev, enum amdgpu_ras_block bloc
+ case AMDGPU_RAS_BLOCK__MPIO:
+ return RAS_TELEMETRY_GPU_BLOCK_MPIO;
+ default:
+- dev_err(adev->dev, "Unsupported SRIOV RAS telemetry block 0x%x\n", block);
++ DRM_WARN_ONCE("Unsupported SRIOV RAS telemetry block 0x%x\n",
++ block);
+ return RAS_TELEMETRY_GPU_BLOCK_COUNT;
+ }
+ }
+@@ -1332,3 +1333,17 @@ int amdgpu_virt_ras_telemetry_post_reset(struct amdgpu_device *adev)
+
+ return 0;
+ }
++
++bool amdgpu_virt_ras_telemetry_block_en(struct amdgpu_device *adev,
++ enum amdgpu_ras_block block)
++{
++ enum amd_sriov_ras_telemetry_gpu_block sriov_block;
++
++ sriov_block = amdgpu_ras_block_to_sriov(adev, block);
++
++ if (sriov_block >= RAS_TELEMETRY_GPU_BLOCK_COUNT ||
++ !amdgpu_sriov_ras_telemetry_block_en(adev, sriov_block))
++ return false;
++
++ return true;
++}
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h
+index 0ca73343a7689..0f3ccae5c1ab3 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h
+@@ -407,4 +407,6 @@ bool amdgpu_virt_get_ras_capability(struct amdgpu_device *adev);
+ int amdgpu_virt_req_ras_err_count(struct amdgpu_device *adev, enum amdgpu_ras_block block,
+ struct ras_err_data *err_data);
+ int amdgpu_virt_ras_telemetry_post_reset(struct amdgpu_device *adev);
++bool amdgpu_virt_ras_telemetry_block_en(struct amdgpu_device *adev,
++ enum amdgpu_ras_block block);
+ #endif
+--
+2.39.5
+
--- /dev/null
+From a0f26bf2a056096fe9f38e337824dc26a05577dc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 17 Mar 2025 09:32:13 -0400
+Subject: drm/amdgpu: Skip pcie_replay_count sysfs creation for VF
+
+From: Victor Skvortsov <victor.skvortsov@amd.com>
+
+[ Upstream commit 9c05636ca72a2dbf41bf0900380f438a0de47319 ]
+
+VFs cannot read the NAK_COUNTER register. This information is only
+available through PMFW metrics.
+
+Signed-off-by: Victor Skvortsov <victor.skvortsov@amd.com>
+Reviewed-by: Lijo Lazar <lijo.lazar@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 27 ++++++++++++++++------
+ 1 file changed, 20 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+index 726c4854e6296..c00a01c62724a 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+@@ -224,6 +224,24 @@ static ssize_t amdgpu_device_get_pcie_replay_count(struct device *dev,
+ static DEVICE_ATTR(pcie_replay_count, 0444,
+ amdgpu_device_get_pcie_replay_count, NULL);
+
++static int amdgpu_device_attr_sysfs_init(struct amdgpu_device *adev)
++{
++ int ret = 0;
++
++ if (!amdgpu_sriov_vf(adev))
++ ret = sysfs_create_file(&adev->dev->kobj,
++ &dev_attr_pcie_replay_count.attr);
++
++ return ret;
++}
++
++static void amdgpu_device_attr_sysfs_fini(struct amdgpu_device *adev)
++{
++ if (!amdgpu_sriov_vf(adev))
++ sysfs_remove_file(&adev->dev->kobj,
++ &dev_attr_pcie_replay_count.attr);
++}
++
+ static ssize_t amdgpu_sysfs_reg_state_get(struct file *f, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf,
+ loff_t ppos, size_t count)
+@@ -4123,11 +4141,6 @@ static bool amdgpu_device_check_iommu_remap(struct amdgpu_device *adev)
+ }
+ #endif
+
+-static const struct attribute *amdgpu_dev_attributes[] = {
+- &dev_attr_pcie_replay_count.attr,
+- NULL
+-};
+-
+ static void amdgpu_device_set_mcbp(struct amdgpu_device *adev)
+ {
+ if (amdgpu_mcbp == 1)
+@@ -4572,7 +4585,7 @@ int amdgpu_device_init(struct amdgpu_device *adev,
+ } else
+ adev->ucode_sysfs_en = true;
+
+- r = sysfs_create_files(&adev->dev->kobj, amdgpu_dev_attributes);
++ r = amdgpu_device_attr_sysfs_init(adev);
+ if (r)
+ dev_err(adev->dev, "Could not create amdgpu device attr\n");
+
+@@ -4709,7 +4722,7 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev)
+ amdgpu_pm_sysfs_fini(adev);
+ if (adev->ucode_sysfs_en)
+ amdgpu_ucode_sysfs_fini(adev);
+- sysfs_remove_files(&adev->dev->kobj, amdgpu_dev_attributes);
++ amdgpu_device_attr_sysfs_fini(adev);
+ amdgpu_fru_sysfs_fini(adev);
+
+ amdgpu_reg_state_sysfs_fini(adev);
+--
+2.39.5
+
--- /dev/null
+From 11e66a26597f6fd958bdfbb6ffef450b581e6e1f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 28 Feb 2025 13:44:32 +0100
+Subject: drm/amdgpu: Update SRIOV video codec caps
+
+From: David Rosca <david.rosca@amd.com>
+
+[ Upstream commit 19478f2011f8b53dee401c91423c4e0b73753e4f ]
+
+There have been multiple fixes to the video caps that are missing for
+SRIOV. Update the SRIOV caps with correct values.
+
+Signed-off-by: David Rosca <david.rosca@amd.com>
+Acked-by: Alex Deucher <alexander.deucher@amd.com>
+Reviewed-by: Ruijing Dong <ruijing.dong@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/nv.c | 16 ++++++++--------
+ drivers/gpu/drm/amd/amdgpu/soc21.c | 10 ++--------
+ 2 files changed, 10 insertions(+), 16 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/nv.c b/drivers/gpu/drm/amd/amdgpu/nv.c
+index 95c609317a8d7..efca7dc27d68d 100644
+--- a/drivers/gpu/drm/amd/amdgpu/nv.c
++++ b/drivers/gpu/drm/amd/amdgpu/nv.c
+@@ -141,23 +141,23 @@ static struct amdgpu_video_codec_info sriov_sc_video_codecs_encode_array[] = {
+ };
+
+ static struct amdgpu_video_codec_info sriov_sc_video_codecs_decode_array_vcn0[] = {
+- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 4096, 4096, 3)},
+- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 4096, 4096, 5)},
++ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 1920, 1088, 3)},
++ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 1920, 1088, 5)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4096, 52)},
+- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VC1, 4096, 4096, 4)},
++ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VC1, 1920, 1088, 4)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 186)},
+- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 4096, 4096, 0)},
++ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 16384, 16384, 0)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VP9, 8192, 4352, 0)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_AV1, 8192, 4352, 0)},
+ };
+
+ static struct amdgpu_video_codec_info sriov_sc_video_codecs_decode_array_vcn1[] = {
+- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 4096, 4096, 3)},
+- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 4096, 4096, 5)},
++ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 1920, 1088, 3)},
++ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 1920, 1088, 5)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4096, 52)},
+- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VC1, 4096, 4096, 4)},
++ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VC1, 1920, 1088, 4)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 186)},
+- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 4096, 4096, 0)},
++ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 16384, 16384, 0)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VP9, 8192, 4352, 0)},
+ };
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/soc21.c b/drivers/gpu/drm/amd/amdgpu/soc21.c
+index 62ad67d0b598f..c66cff399f63d 100644
+--- a/drivers/gpu/drm/amd/amdgpu/soc21.c
++++ b/drivers/gpu/drm/amd/amdgpu/soc21.c
+@@ -117,23 +117,17 @@ static struct amdgpu_video_codecs sriov_vcn_4_0_0_video_codecs_encode_vcn1 = {
+ };
+
+ static struct amdgpu_video_codec_info sriov_vcn_4_0_0_video_codecs_decode_array_vcn0[] = {
+- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 4096, 4096, 3)},
+- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 4096, 4096, 5)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4096, 52)},
+- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VC1, 4096, 4096, 4)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 186)},
+- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 4096, 4096, 0)},
++ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 16384, 16384, 0)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VP9, 8192, 4352, 0)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_AV1, 8192, 4352, 0)},
+ };
+
+ static struct amdgpu_video_codec_info sriov_vcn_4_0_0_video_codecs_decode_array_vcn1[] = {
+- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 4096, 4096, 3)},
+- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 4096, 4096, 5)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4096, 52)},
+- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VC1, 4096, 4096, 4)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 186)},
+- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 4096, 4096, 0)},
++ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 16384, 16384, 0)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VP9, 8192, 4352, 0)},
+ };
+
+--
+2.39.5
+
--- /dev/null
+From b3e91a202c6c20b09304464738aa4e92300ab4ad Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 1 Jan 2025 14:23:31 +0530
+Subject: drm/amdgpu: Use active umc info from discovery
+
+From: Lijo Lazar <lijo.lazar@amd.com>
+
+[ Upstream commit f7a594e40517fa2ab25d5ca10e7b6a158f529fb5 ]
+
+There could be configs where some UMC instances are harvested. This
+information is obtained through discovery data and populated in
+umc.active_mask. Avoid reassigning this as AID mask, instead use the
+mask directly while iterating through umc instances. This is to avoid
+accesses to harvested UMC instances.
+
+v2: fix warning (Alex)
+
+Signed-off-by: Lijo Lazar <lijo.lazar@amd.com>
+Reviewed-by: Hawking Zhang <Hawking.Zhang@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c | 42 +++++++++++++++++++++++++
+ drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c | 1 -
+ 2 files changed, 42 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c
+index eafe20d8fe0b6..0a1ef95b28668 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c
+@@ -387,6 +387,45 @@ int amdgpu_umc_fill_error_record(struct ras_err_data *err_data,
+ return 0;
+ }
+
++static int amdgpu_umc_loop_all_aid(struct amdgpu_device *adev, umc_func func,
++ void *data)
++{
++ uint32_t umc_node_inst;
++ uint32_t node_inst;
++ uint32_t umc_inst;
++ uint32_t ch_inst;
++ int ret;
++
++ /*
++ * This loop is done based on the following -
++ * umc.active mask = mask of active umc instances across all nodes
++ * umc.umc_inst_num = maximum number of umc instancess per node
++ * umc.node_inst_num = maximum number of node instances
++ * Channel instances are not assumed to be harvested.
++ */
++ dev_dbg(adev->dev, "active umcs :%lx umc_inst per node: %d",
++ adev->umc.active_mask, adev->umc.umc_inst_num);
++ for_each_set_bit(umc_node_inst, &(adev->umc.active_mask),
++ adev->umc.node_inst_num * adev->umc.umc_inst_num) {
++ node_inst = umc_node_inst / adev->umc.umc_inst_num;
++ umc_inst = umc_node_inst % adev->umc.umc_inst_num;
++ LOOP_UMC_CH_INST(ch_inst) {
++ dev_dbg(adev->dev,
++ "node_inst :%d umc_inst: %d ch_inst: %d",
++ node_inst, umc_inst, ch_inst);
++ ret = func(adev, node_inst, umc_inst, ch_inst, data);
++ if (ret) {
++ dev_err(adev->dev,
++ "Node %d umc %d ch %d func returns %d\n",
++ node_inst, umc_inst, ch_inst, ret);
++ return ret;
++ }
++ }
++ }
++
++ return 0;
++}
++
+ int amdgpu_umc_loop_channels(struct amdgpu_device *adev,
+ umc_func func, void *data)
+ {
+@@ -395,6 +434,9 @@ int amdgpu_umc_loop_channels(struct amdgpu_device *adev,
+ uint32_t ch_inst = 0;
+ int ret = 0;
+
++ if (adev->aid_mask)
++ return amdgpu_umc_loop_all_aid(adev, func, data);
++
+ if (adev->umc.node_inst_num) {
+ LOOP_UMC_EACH_NODE_INST_AND_CH(node_inst, umc_inst, ch_inst) {
+ ret = func(adev, node_inst, umc_inst, ch_inst, data);
+diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
+index 5250b470e5ef3..f1dc9e50d67e7 100644
+--- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
+@@ -1504,7 +1504,6 @@ static void gmc_v9_0_set_umc_funcs(struct amdgpu_device *adev)
+ adev->umc.umc_inst_num = UMC_V12_0_UMC_INSTANCE_NUM;
+ adev->umc.node_inst_num /= UMC_V12_0_UMC_INSTANCE_NUM;
+ adev->umc.channel_offs = UMC_V12_0_PER_CHANNEL_OFFSET;
+- adev->umc.active_mask = adev->aid_mask;
+ adev->umc.retire_unit = UMC_V12_0_BAD_PAGE_NUM_PER_CHANNEL;
+ if (!adev->gmc.xgmi.connected_to_cpu && !adev->gmc.is_app_apu)
+ adev->umc.ras = &umc_v12_0_ras;
+--
+2.39.5
+
--- /dev/null
+From 0a6b0576117c0b5c18d6fbd8ad9bb761acfd4488 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 15 Jan 2025 15:10:13 +0100
+Subject: drm/amdgpu: use GFP_NOWAIT for memory allocations
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Christian König <christian.koenig@amd.com>
+
+[ Upstream commit 16590745b571c07869ef8958e0bbe44ab6f08d1f ]
+
+In the critical submission path memory allocations can't wait for
+reclaim since that can potentially wait for submissions to finish.
+
+Finally clean that up and mark most memory allocations in the critical
+path with GFP_NOWAIT. The only exception left is the dma_fence_array()
+used when no VMID is available, but that will be cleaned up later on.
+
+Signed-off-by: Christian König <christian.koenig@amd.com>
+Acked-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c | 8 ++++----
+ drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 18 +++++++++++-------
+ drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c | 11 +++++++----
+ drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c | 4 ++--
+ drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c | 11 ++++++-----
+ drivers/gpu/drm/amd/amdgpu/amdgpu_sync.h | 3 ++-
+ 6 files changed, 32 insertions(+), 23 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
+index 1e998f972c308..70224b9f54f2f 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
+@@ -499,7 +499,7 @@ static int vm_update_pds(struct amdgpu_vm *vm, struct amdgpu_sync *sync)
+ if (ret)
+ return ret;
+
+- return amdgpu_sync_fence(sync, vm->last_update);
++ return amdgpu_sync_fence(sync, vm->last_update, GFP_KERNEL);
+ }
+
+ static uint64_t get_pte_flags(struct amdgpu_device *adev, struct kgd_mem *mem)
+@@ -1263,7 +1263,7 @@ static int unmap_bo_from_gpuvm(struct kgd_mem *mem,
+
+ (void)amdgpu_vm_clear_freed(adev, vm, &bo_va->last_pt_update);
+
+- (void)amdgpu_sync_fence(sync, bo_va->last_pt_update);
++ (void)amdgpu_sync_fence(sync, bo_va->last_pt_update, GFP_KERNEL);
+
+ return 0;
+ }
+@@ -1287,7 +1287,7 @@ static int update_gpuvm_pte(struct kgd_mem *mem,
+ return ret;
+ }
+
+- return amdgpu_sync_fence(sync, bo_va->last_pt_update);
++ return amdgpu_sync_fence(sync, bo_va->last_pt_update, GFP_KERNEL);
+ }
+
+ static int map_bo_to_gpuvm(struct kgd_mem *mem,
+@@ -2969,7 +2969,7 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence __rcu *
+ }
+ dma_resv_for_each_fence(&cursor, bo->tbo.base.resv,
+ DMA_RESV_USAGE_KERNEL, fence) {
+- ret = amdgpu_sync_fence(&sync_obj, fence);
++ ret = amdgpu_sync_fence(&sync_obj, fence, GFP_KERNEL);
+ if (ret) {
+ pr_debug("Memory eviction: Sync BO fence failed. Try again\n");
+ goto validate_map_fail;
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+index 5cc5f59e30184..4a5b406601fa2 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+@@ -428,7 +428,7 @@ static int amdgpu_cs_p2_dependencies(struct amdgpu_cs_parser *p,
+ dma_fence_put(old);
+ }
+
+- r = amdgpu_sync_fence(&p->sync, fence);
++ r = amdgpu_sync_fence(&p->sync, fence, GFP_KERNEL);
+ dma_fence_put(fence);
+ if (r)
+ return r;
+@@ -450,7 +450,7 @@ static int amdgpu_syncobj_lookup_and_add(struct amdgpu_cs_parser *p,
+ return r;
+ }
+
+- r = amdgpu_sync_fence(&p->sync, fence);
++ r = amdgpu_sync_fence(&p->sync, fence, GFP_KERNEL);
+ dma_fence_put(fence);
+ return r;
+ }
+@@ -1124,7 +1124,8 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p)
+ if (r)
+ return r;
+
+- r = amdgpu_sync_fence(&p->sync, fpriv->prt_va->last_pt_update);
++ r = amdgpu_sync_fence(&p->sync, fpriv->prt_va->last_pt_update,
++ GFP_KERNEL);
+ if (r)
+ return r;
+
+@@ -1135,7 +1136,8 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p)
+ if (r)
+ return r;
+
+- r = amdgpu_sync_fence(&p->sync, bo_va->last_pt_update);
++ r = amdgpu_sync_fence(&p->sync, bo_va->last_pt_update,
++ GFP_KERNEL);
+ if (r)
+ return r;
+ }
+@@ -1154,7 +1156,8 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p)
+ if (r)
+ return r;
+
+- r = amdgpu_sync_fence(&p->sync, bo_va->last_pt_update);
++ r = amdgpu_sync_fence(&p->sync, bo_va->last_pt_update,
++ GFP_KERNEL);
+ if (r)
+ return r;
+ }
+@@ -1167,7 +1170,7 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p)
+ if (r)
+ return r;
+
+- r = amdgpu_sync_fence(&p->sync, vm->last_update);
++ r = amdgpu_sync_fence(&p->sync, vm->last_update, GFP_KERNEL);
+ if (r)
+ return r;
+
+@@ -1248,7 +1251,8 @@ static int amdgpu_cs_sync_rings(struct amdgpu_cs_parser *p)
+ continue;
+ }
+
+- r = amdgpu_sync_fence(&p->gang_leader->explicit_sync, fence);
++ r = amdgpu_sync_fence(&p->gang_leader->explicit_sync, fence,
++ GFP_KERNEL);
+ dma_fence_put(fence);
+ if (r)
+ return r;
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
+index 9008b7388e897..92ab821afc06a 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
+@@ -209,7 +209,7 @@ static int amdgpu_vmid_grab_idle(struct amdgpu_ring *ring,
+ return 0;
+ }
+
+- fences = kmalloc_array(id_mgr->num_ids, sizeof(void *), GFP_KERNEL);
++ fences = kmalloc_array(id_mgr->num_ids, sizeof(void *), GFP_NOWAIT);
+ if (!fences)
+ return -ENOMEM;
+
+@@ -313,7 +313,8 @@ static int amdgpu_vmid_grab_reserved(struct amdgpu_vm *vm,
+ /* Good we can use this VMID. Remember this submission as
+ * user of the VMID.
+ */
+- r = amdgpu_sync_fence(&(*id)->active, &job->base.s_fence->finished);
++ r = amdgpu_sync_fence(&(*id)->active, &job->base.s_fence->finished,
++ GFP_NOWAIT);
+ if (r)
+ return r;
+
+@@ -372,7 +373,8 @@ static int amdgpu_vmid_grab_used(struct amdgpu_vm *vm,
+ * user of the VMID.
+ */
+ r = amdgpu_sync_fence(&(*id)->active,
+- &job->base.s_fence->finished);
++ &job->base.s_fence->finished,
++ GFP_NOWAIT);
+ if (r)
+ return r;
+
+@@ -424,7 +426,8 @@ int amdgpu_vmid_grab(struct amdgpu_vm *vm, struct amdgpu_ring *ring,
+
+ /* Remember this submission as user of the VMID */
+ r = amdgpu_sync_fence(&id->active,
+- &job->base.s_fence->finished);
++ &job->base.s_fence->finished,
++ GFP_NOWAIT);
+ if (r)
+ goto error;
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c
+index 6fa20980a0b15..e4251d0691c9c 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c
+@@ -1335,14 +1335,14 @@ int amdgpu_mes_ctx_map_meta_data(struct amdgpu_device *adev,
+ DRM_ERROR("failed to do vm_bo_update on meta data\n");
+ goto error_del_bo_va;
+ }
+- amdgpu_sync_fence(&sync, bo_va->last_pt_update);
++ amdgpu_sync_fence(&sync, bo_va->last_pt_update, GFP_KERNEL);
+
+ r = amdgpu_vm_update_pdes(adev, vm, false);
+ if (r) {
+ DRM_ERROR("failed to update pdes on meta data\n");
+ goto error_del_bo_va;
+ }
+- amdgpu_sync_fence(&sync, vm->last_update);
++ amdgpu_sync_fence(&sync, vm->last_update, GFP_KERNEL);
+
+ amdgpu_sync_wait(&sync, false);
+ drm_exec_fini(&exec);
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c
+index d75715b3f1870..34fc742fda91d 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c
+@@ -152,7 +152,8 @@ static bool amdgpu_sync_add_later(struct amdgpu_sync *sync, struct dma_fence *f)
+ *
+ * Add the fence to the sync object.
+ */
+-int amdgpu_sync_fence(struct amdgpu_sync *sync, struct dma_fence *f)
++int amdgpu_sync_fence(struct amdgpu_sync *sync, struct dma_fence *f,
++ gfp_t flags)
+ {
+ struct amdgpu_sync_entry *e;
+
+@@ -162,7 +163,7 @@ int amdgpu_sync_fence(struct amdgpu_sync *sync, struct dma_fence *f)
+ if (amdgpu_sync_add_later(sync, f))
+ return 0;
+
+- e = kmem_cache_alloc(amdgpu_sync_slab, GFP_KERNEL);
++ e = kmem_cache_alloc(amdgpu_sync_slab, flags);
+ if (!e)
+ return -ENOMEM;
+
+@@ -249,7 +250,7 @@ int amdgpu_sync_resv(struct amdgpu_device *adev, struct amdgpu_sync *sync,
+ struct dma_fence *tmp = dma_fence_chain_contained(f);
+
+ if (amdgpu_sync_test_fence(adev, mode, owner, tmp)) {
+- r = amdgpu_sync_fence(sync, f);
++ r = amdgpu_sync_fence(sync, f, GFP_KERNEL);
+ dma_fence_put(f);
+ if (r)
+ return r;
+@@ -281,7 +282,7 @@ int amdgpu_sync_kfd(struct amdgpu_sync *sync, struct dma_resv *resv)
+ if (fence_owner != AMDGPU_FENCE_OWNER_KFD)
+ continue;
+
+- r = amdgpu_sync_fence(sync, f);
++ r = amdgpu_sync_fence(sync, f, GFP_KERNEL);
+ if (r)
+ break;
+ }
+@@ -388,7 +389,7 @@ int amdgpu_sync_clone(struct amdgpu_sync *source, struct amdgpu_sync *clone)
+ hash_for_each_safe(source->fences, i, tmp, e, node) {
+ f = e->fence;
+ if (!dma_fence_is_signaled(f)) {
+- r = amdgpu_sync_fence(clone, f);
++ r = amdgpu_sync_fence(clone, f, GFP_KERNEL);
+ if (r)
+ return r;
+ } else {
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.h
+index a91a8eaf808b1..51eb4382c91eb 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.h
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.h
+@@ -47,7 +47,8 @@ struct amdgpu_sync {
+ };
+
+ void amdgpu_sync_create(struct amdgpu_sync *sync);
+-int amdgpu_sync_fence(struct amdgpu_sync *sync, struct dma_fence *f);
++int amdgpu_sync_fence(struct amdgpu_sync *sync, struct dma_fence *f,
++ gfp_t flags);
+ int amdgpu_sync_resv(struct amdgpu_device *adev, struct amdgpu_sync *sync,
+ struct dma_resv *resv, enum amdgpu_sync_mode mode,
+ void *owner);
+--
+2.39.5
+
--- /dev/null
+From c1490690275925f3eea14045c9a66788a69eb4e6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 May 2024 17:06:48 -0500
+Subject: drm/amdkfd: clear F8_MODE for gfx950
+
+From: Alex Sierra <alex.sierra@amd.com>
+
+[ Upstream commit 59228c6631f902fa826dc61321ab377ba8aadec5 ]
+
+Default F8_MODE should be OCP format on gfx950.
+
+Signed-off-by: Alex Sierra <alex.sierra@amd.com>
+Reviewed-by: Harish Kasiviswanathan <Harish.Kasiviswanathan@amd.com>
+Signed-off-by: Amber Lin <Amber.Lin@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v9.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v9.c
+index c734eb9b505f8..3264509408bc8 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v9.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v9.c
+@@ -98,8 +98,7 @@ static int update_qpd_v9(struct device_queue_manager *dqm,
+ qpd->sh_mem_config |= 1 << SH_MEM_CONFIG__RETRY_DISABLE__SHIFT;
+
+ if (KFD_GC_VERSION(dqm->dev->kfd) == IP_VERSION(9, 4, 3) ||
+- KFD_GC_VERSION(dqm->dev->kfd) == IP_VERSION(9, 4, 4) ||
+- KFD_GC_VERSION(dqm->dev->kfd) == IP_VERSION(9, 5, 0))
++ KFD_GC_VERSION(dqm->dev->kfd) == IP_VERSION(9, 4, 4))
+ qpd->sh_mem_config |=
+ (1 << SH_MEM_CONFIG__F8_MODE__SHIFT);
+
+--
+2.39.5
+
--- /dev/null
+From 1f5a995ba38b88f8fb8ff09b8bc75b74488c0c58 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 12 Mar 2025 21:14:43 -0400
+Subject: drm/amdkfd: Correct F8_MODE for gfx950
+
+From: Amber Lin <Amber.Lin@amd.com>
+
+[ Upstream commit 0c7e053448945e5a4379dc4396c762d7422b11ca ]
+
+Correct F8_MODE setting for gfx950 that was removed
+
+Fixes: 61972cd93af7 ("drm/amdkfd: Set per-process flags only once for gfx9/10/11/12")
+Signed-off-by: Amber Lin <Amber.Lin@amd.com>
+Reviewed-by: Harish Kasiviswanathan <Harish.Kasiviwanathan@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v9.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v9.c
+index 3264509408bc8..d85eadaa1e11b 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v9.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v9.c
+@@ -69,8 +69,7 @@ static bool set_cache_memory_policy_v9(struct device_queue_manager *dqm,
+ qpd->sh_mem_config |= 1 << SH_MEM_CONFIG__RETRY_DISABLE__SHIFT;
+
+ if (KFD_GC_VERSION(dqm->dev->kfd) == IP_VERSION(9, 4, 3) ||
+- KFD_GC_VERSION(dqm->dev->kfd) == IP_VERSION(9, 4, 4) ||
+- KFD_GC_VERSION(dqm->dev->kfd) == IP_VERSION(9, 5, 0))
++ KFD_GC_VERSION(dqm->dev->kfd) == IP_VERSION(9, 4, 4))
+ qpd->sh_mem_config |= (1 << SH_MEM_CONFIG__F8_MODE__SHIFT);
+
+ qpd->sh_mem_ape1_limit = 0;
+--
+2.39.5
+
--- /dev/null
+From eb1753801e0e53dfefa4abd222be7ac509f9a651 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 17 Feb 2025 12:07:22 +0530
+Subject: drm/amdkfd: Fix error handling for missing PASID in
+ 'kfd_process_device_init_vm'
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+
+[ Upstream commit 2b04d04de956b44cc140d45cf8ebccfb378ce3bf ]
+
+In the kfd_process_device_init_vm function, a valid error code is now
+returned when the associated Process Address Space ID (PASID) is not
+present.
+
+If the address space virtual memory (avm) does not have an associated
+PASID, the function sets the ret variable to -EINVAL before proceeding
+to the error handling section. This ensures that the calling function,
+such as kfd_ioctl_acquire_vm, can appropriately handle the error,
+thereby preventing any issues during virtual memory initialization.
+
+Fixes the below:
+drivers/gpu/drm/amd/amdgpu/../amdkfd/kfd_process.c:1694 kfd_process_device_init_vm()
+warn: missing error code 'ret'
+
+drivers/gpu/drm/amd/amdgpu/../amdkfd/kfd_process.c
+ 1647 int kfd_process_device_init_vm(struct kfd_process_device *pdd,
+ 1648 struct file *drm_file)
+ 1649 {
+ ...
+ 1690
+ 1691 if (unlikely(!avm->pasid)) {
+ 1692 dev_warn(pdd->dev->adev->dev, "WARN: vm %p has no pasid associated",
+ 1693 avm);
+--> 1694 goto err_get_pasid;
+
+ret = -EINVAL?
+
+ 1695 }
+
+Fixes: 8544374c0f82 ("drm/amdkfd: Have kfd driver use same PASID values from graphic driver")
+Reported by: Dan Carpenter <dan.carpenter@linaro.org>
+Cc: Xiaogang Chen <xiaogang.chen@amd.com>
+Cc: Felix Kuehling <felix.kuehling@amd.com>
+Cc: Christian König <christian.koenig@amd.com>
+Cc: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+Reviewed-by: Felix Kuehling <felix.kuehling@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdkfd/kfd_process.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
+index a7e0a16dac47b..3f411922534b3 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
+@@ -1711,6 +1711,7 @@ int kfd_process_device_init_vm(struct kfd_process_device *pdd,
+ if (unlikely(!avm->pasid)) {
+ dev_warn(pdd->dev->adev->dev, "WARN: vm %p has no pasid associated",
+ avm);
++ ret = -EINVAL;
+ goto err_get_pasid;
+ }
+
+--
+2.39.5
+
--- /dev/null
+From 85b2e4de13582675fccc0d496b3ca13b41736f97 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jan 2025 15:48:26 -0500
+Subject: drm/amdkfd: fix missing L2 cache info in topology
+
+From: Eric Huang <jinhuieric.huang@amd.com>
+
+[ Upstream commit 5ffd56822a7159917306d99f18fd15dfd7288f20 ]
+
+In some ASICs L2 cache info may miss in kfd topology,
+because the first bitmap may be empty, that means
+the first cu may be inactive, so to find the first
+active cu will solve the issue.
+
+v2: Only find the first active cu in the first xcc
+
+Signed-off-by: Eric Huang <jinhuieric.huang@amd.com>
+Acked-by: Alex Deucher <alexander.deucher@amd.com>
+Acked-by: Lijo Lazar <lijo.lazar@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdkfd/kfd_topology.c | 19 +++++++++++++++++--
+ 1 file changed, 17 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
+index 334c576a75b14..98317eda2cdb4 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
+@@ -1683,17 +1683,32 @@ static int fill_in_l2_l3_pcache(struct kfd_cache_properties **props_ext,
+ int cache_type, unsigned int cu_processor_id,
+ struct kfd_node *knode)
+ {
+- unsigned int cu_sibling_map_mask;
++ unsigned int cu_sibling_map_mask = 0;
+ int first_active_cu;
+ int i, j, k, xcc, start, end;
+ int num_xcc = NUM_XCC(knode->xcc_mask);
+ struct kfd_cache_properties *pcache = NULL;
+ enum amdgpu_memory_partition mode;
+ struct amdgpu_device *adev = knode->adev;
++ bool found = false;
+
+ start = ffs(knode->xcc_mask) - 1;
+ end = start + num_xcc;
+- cu_sibling_map_mask = cu_info->bitmap[start][0][0];
++
++ /* To find the bitmap in the first active cu in the first
++ * xcc, it is based on the assumption that evrey xcc must
++ * have at least one active cu.
++ */
++ for (i = 0; i < gfx_info->max_shader_engines && !found; i++) {
++ for (j = 0; j < gfx_info->max_sh_per_se && !found; j++) {
++ if (cu_info->bitmap[start][i % 4][j % 4]) {
++ cu_sibling_map_mask =
++ cu_info->bitmap[start][i % 4][j % 4];
++ found = true;
++ }
++ }
++ }
++
+ cu_sibling_map_mask &=
+ ((1 << pcache_info[cache_type].num_cu_shared) - 1);
+ first_active_cu = ffs(cu_sibling_map_mask);
+--
+2.39.5
+
--- /dev/null
+From 6725b91424951af96d86284df9f875d2f73353d0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 12 Feb 2025 00:24:02 -0600
+Subject: drm/amdkfd: Fix pasid value leak
+
+From: Xiaogang Chen <xiaogang.chen@amd.com>
+
+[ Upstream commit 10e08943caedfb4b0b95933d248503a6f6b9fef6 ]
+
+Curret kfd does not allocate pasid values, instead uses pasid value for each
+vm from graphic driver. So should not prevent graphic driver from releasing
+pasid values since the values are allocated by graphic driver, not kfd driver
+anymore. This patch does not stop graphic driver release pasid values.
+
+Fixes: 8544374c0f82 ("drm/amdkfd: Have kfd driver use same PASID values from graphic driver")
+Signed-off-by: Xiaogang Chen <xiaogang.chen@amd.com>
+Reviewed-by: Felix Kuehling <felix.kuehling@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h | 2 --
+ .../gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c | 21 -------------------
+ drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 14 -------------
+ drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h | 1 -
+ drivers/gpu/drm/amd/amdkfd/kfd_process.c | 5 +----
+ 5 files changed, 1 insertion(+), 42 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
+index a160ffe80b3de..55d5399676951 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
+@@ -303,8 +303,6 @@ int amdgpu_amdkfd_gpuvm_acquire_process_vm(struct amdgpu_device *adev,
+ struct amdgpu_vm *avm,
+ void **process_info,
+ struct dma_fence **ef);
+-void amdgpu_amdkfd_gpuvm_release_process_vm(struct amdgpu_device *adev,
+- void *drm_priv);
+ uint64_t amdgpu_amdkfd_gpuvm_get_process_page_dir(void *drm_priv);
+ size_t amdgpu_amdkfd_get_available_memory(struct amdgpu_device *adev,
+ uint8_t xcp_id);
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
+index 0c8129f8d3635..b3c8eae460425 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
+@@ -1578,27 +1578,6 @@ void amdgpu_amdkfd_gpuvm_destroy_cb(struct amdgpu_device *adev,
+ }
+ }
+
+-void amdgpu_amdkfd_gpuvm_release_process_vm(struct amdgpu_device *adev,
+- void *drm_priv)
+-{
+- struct amdgpu_vm *avm;
+-
+- if (WARN_ON(!adev || !drm_priv))
+- return;
+-
+- avm = drm_priv_to_vm(drm_priv);
+-
+- pr_debug("Releasing process vm %p\n", avm);
+-
+- /* The original pasid of amdgpu vm has already been
+- * released during making a amdgpu vm to a compute vm
+- * The current pasid is managed by kfd and will be
+- * released on kfd process destroy. Set amdgpu pasid
+- * to 0 to avoid duplicate release.
+- */
+- amdgpu_vm_release_compute(adev, avm);
+-}
+-
+ uint64_t amdgpu_amdkfd_gpuvm_get_process_page_dir(void *drm_priv)
+ {
+ struct amdgpu_vm *avm = drm_priv_to_vm(drm_priv);
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+index f0d675c0fc69c..21be10d46cf9c 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+@@ -2687,20 +2687,6 @@ int amdgpu_vm_make_compute(struct amdgpu_device *adev, struct amdgpu_vm *vm)
+ return r;
+ }
+
+-/**
+- * amdgpu_vm_release_compute - release a compute vm
+- * @adev: amdgpu_device pointer
+- * @vm: a vm turned into compute vm by calling amdgpu_vm_make_compute
+- *
+- * This is a correspondant of amdgpu_vm_make_compute. It decouples compute
+- * pasid from vm. Compute should stop use of vm after this call.
+- */
+-void amdgpu_vm_release_compute(struct amdgpu_device *adev, struct amdgpu_vm *vm)
+-{
+- amdgpu_vm_set_pasid(adev, vm, 0);
+- vm->is_compute_context = false;
+-}
+-
+ static int amdgpu_vm_stats_is_zero(struct amdgpu_vm *vm)
+ {
+ for (int i = 0; i < __AMDGPU_PL_NUM; ++i) {
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
+index 5010a3107bf89..f3ad687125ad6 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
+@@ -489,7 +489,6 @@ int amdgpu_vm_set_pasid(struct amdgpu_device *adev, struct amdgpu_vm *vm,
+ long amdgpu_vm_wait_idle(struct amdgpu_vm *vm, long timeout);
+ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, int32_t xcp_id);
+ int amdgpu_vm_make_compute(struct amdgpu_device *adev, struct amdgpu_vm *vm);
+-void amdgpu_vm_release_compute(struct amdgpu_device *adev, struct amdgpu_vm *vm);
+ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm);
+ int amdgpu_vm_lock_pd(struct amdgpu_vm *vm, struct drm_exec *exec,
+ unsigned int num_fences);
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
+index 3f411922534b3..7c0c24732481e 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
+@@ -1059,11 +1059,8 @@ static void kfd_process_destroy_pdds(struct kfd_process *p)
+ kfd_process_device_destroy_cwsr_dgpu(pdd);
+ kfd_process_device_destroy_ib_mem(pdd);
+
+- if (pdd->drm_file) {
+- amdgpu_amdkfd_gpuvm_release_process_vm(
+- pdd->dev->adev, pdd->drm_priv);
++ if (pdd->drm_file)
+ fput(pdd->drm_file);
+- }
+
+ if (pdd->qpd.cwsr_kaddr && !pdd->qpd.cwsr_base)
+ free_pages((unsigned long)pdd->qpd.cwsr_kaddr,
+--
+2.39.5
+
--- /dev/null
+From dc7a556f00a36c1fe76aa174204c2b5bd3e1bd88 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Jan 2025 17:35:59 -0600
+Subject: drm/amdkfd: Have kfd driver use same PASID values from graphic driver
+
+From: Xiaogang Chen <xiaogang.chen@amd.com>
+
+[ Upstream commit 8544374c0f82edb285779f21b149826fe2c2977c ]
+
+Current kfd driver has its own PASID value for a kfd process and uses it to
+locate vm at interrupt handler or mapping between kfd process and vm. That
+design is not working when a physical gpu device has multiple spatial
+partitions, ex: adev in CPX mode. This patch has kfd driver use same pasid
+values that graphic driver generated which is per vm per pasid.
+
+These pasid values are passed to fw/hardware. We do not need change interrupt
+handler though more pasid values are used. Also, pasid values at log are
+replaced by user process pid; pasid values are not exposed to user. Users see
+their process pids that have meaning in user space.
+
+Signed-off-by: Xiaogang Chen <xiaogang.chen@amd.com>
+Reviewed-by: Felix Kuehling <felix.kuehling@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h | 3 +-
+ .../gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c | 21 ----
+ .../gpu/drm/amd/amdkfd/cik_event_interrupt.c | 18 ++-
+ drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 25 ++--
+ drivers/gpu/drm/amd/amdkfd/kfd_debug.c | 14 +--
+ drivers/gpu/drm/amd/amdkfd/kfd_device.c | 2 +-
+ .../drm/amd/amdkfd/kfd_device_queue_manager.c | 85 +++++++------
+ drivers/gpu/drm/amd/amdkfd/kfd_events.c | 43 ++++---
+ .../gpu/drm/amd/amdkfd/kfd_int_process_v11.c | 2 +-
+ .../gpu/drm/amd/amdkfd/kfd_int_process_v9.c | 2 +-
+ .../drm/amd/amdkfd/kfd_packet_manager_v9.c | 4 +-
+ .../drm/amd/amdkfd/kfd_packet_manager_vi.c | 3 +-
+ drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 11 +-
+ drivers/gpu/drm/amd/amdkfd/kfd_process.c | 115 ++++++++++--------
+ .../amd/amdkfd/kfd_process_queue_manager.c | 10 +-
+ drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 19 +--
+ 16 files changed, 196 insertions(+), 181 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
+index 2f48dc5747aa2..a160ffe80b3de 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
+@@ -47,6 +47,7 @@ enum TLB_FLUSH_TYPE {
+ };
+
+ struct amdgpu_device;
++struct kfd_process_device;
+ struct amdgpu_reset_context;
+
+ enum kfd_mem_attachment_type {
+@@ -298,8 +299,6 @@ bool amdgpu_amdkfd_compute_active(struct amdgpu_device *adev, uint32_t node_id);
+ (&((struct amdgpu_fpriv *) \
+ ((struct drm_file *)(drm_priv))->driver_priv)->vm)
+
+-int amdgpu_amdkfd_gpuvm_set_vm_pasid(struct amdgpu_device *adev,
+- struct amdgpu_vm *avm, u32 pasid);
+ int amdgpu_amdkfd_gpuvm_acquire_process_vm(struct amdgpu_device *adev,
+ struct amdgpu_vm *avm,
+ void **process_info,
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
+index c0aaa72b6c210..0c8129f8d3635 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
+@@ -1521,27 +1521,6 @@ static void amdgpu_amdkfd_gpuvm_unpin_bo(struct amdgpu_bo *bo)
+ amdgpu_bo_unreserve(bo);
+ }
+
+-int amdgpu_amdkfd_gpuvm_set_vm_pasid(struct amdgpu_device *adev,
+- struct amdgpu_vm *avm, u32 pasid)
+-
+-{
+- int ret;
+-
+- /* Free the original amdgpu allocated pasid,
+- * will be replaced with kfd allocated pasid.
+- */
+- if (avm->pasid) {
+- amdgpu_pasid_free(avm->pasid);
+- amdgpu_vm_set_pasid(adev, avm, 0);
+- }
+-
+- ret = amdgpu_vm_set_pasid(adev, avm, pasid);
+- if (ret)
+- return ret;
+-
+- return 0;
+-}
+-
+ int amdgpu_amdkfd_gpuvm_acquire_process_vm(struct amdgpu_device *adev,
+ struct amdgpu_vm *avm,
+ void **process_info,
+diff --git a/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c b/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c
+index 795382b55e0a9..981d9adcc5e1d 100644
+--- a/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c
++++ b/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c
+@@ -107,20 +107,30 @@ static void cik_event_interrupt_wq(struct kfd_node *dev,
+ kfd_signal_hw_exception_event(pasid);
+ else if (ihre->source_id == CIK_INTSRC_GFX_PAGE_INV_FAULT ||
+ ihre->source_id == CIK_INTSRC_GFX_MEM_PROT_FAULT) {
++ struct kfd_process_device *pdd = NULL;
+ struct kfd_vm_fault_info info;
++ struct kfd_process *p;
+
+ kfd_smi_event_update_vmfault(dev, pasid);
+- kfd_dqm_evict_pasid(dev->dqm, pasid);
++ p = kfd_lookup_process_by_pasid(pasid, &pdd);
++ if (!pdd)
++ return;
++
++ kfd_evict_process_device(pdd);
+
+ memset(&info, 0, sizeof(info));
+ amdgpu_amdkfd_gpuvm_get_vm_fault_info(dev->adev, &info);
+- if (!info.page_addr && !info.status)
++ if (!info.page_addr && !info.status) {
++ kfd_unref_process(p);
+ return;
++ }
+
+ if (info.vmid == vmid)
+- kfd_signal_vm_fault_event(dev, pasid, &info, NULL);
++ kfd_signal_vm_fault_event(pdd, &info, NULL);
+ else
+- kfd_signal_vm_fault_event(dev, pasid, NULL, NULL);
++ kfd_signal_vm_fault_event(pdd, &info, NULL);
++
++ kfd_unref_process(p);
+ }
+ }
+
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
+index 33df35cab4679..8c2e92378b491 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
+@@ -155,8 +155,8 @@ static int kfd_open(struct inode *inode, struct file *filep)
+ /* filep now owns the reference returned by kfd_create_process */
+ filep->private_data = process;
+
+- dev_dbg(kfd_device, "process %d opened, compat mode (32 bit) - %d\n",
+- process->pasid, process->is_32bit_user_mode);
++ dev_dbg(kfd_device, "process pid %d opened kfd node, compat mode (32 bit) - %d\n",
++ process->lead_thread->pid, process->is_32bit_user_mode);
+
+ return 0;
+ }
+@@ -366,8 +366,8 @@ static int kfd_ioctl_create_queue(struct file *filep, struct kfd_process *p,
+ goto err_acquire_queue_buf;
+ }
+
+- pr_debug("Creating queue for PASID 0x%x on gpu 0x%x\n",
+- p->pasid,
++ pr_debug("Creating queue for process pid %d on gpu 0x%x\n",
++ p->lead_thread->pid,
+ dev->id);
+
+ err = pqm_create_queue(&p->pqm, dev, &q_properties, &queue_id,
+@@ -420,9 +420,9 @@ static int kfd_ioctl_destroy_queue(struct file *filp, struct kfd_process *p,
+ int retval;
+ struct kfd_ioctl_destroy_queue_args *args = data;
+
+- pr_debug("Destroying queue id %d for pasid 0x%x\n",
++ pr_debug("Destroying queue id %d for process pid %d\n",
+ args->queue_id,
+- p->pasid);
++ p->lead_thread->pid);
+
+ mutex_lock(&p->mutex);
+
+@@ -478,8 +478,8 @@ static int kfd_ioctl_update_queue(struct file *filp, struct kfd_process *p,
+ properties.pm4_target_xcc = (args->queue_percentage >> 8) & 0xFF;
+ properties.priority = args->queue_priority;
+
+- pr_debug("Updating queue id %d for pasid 0x%x\n",
+- args->queue_id, p->pasid);
++ pr_debug("Updating queue id %d for process pid %d\n",
++ args->queue_id, p->lead_thread->pid);
+
+ mutex_lock(&p->mutex);
+
+@@ -705,7 +705,7 @@ static int kfd_ioctl_get_process_apertures(struct file *filp,
+ struct kfd_process_device_apertures *pAperture;
+ int i;
+
+- dev_dbg(kfd_device, "get apertures for PASID 0x%x", p->pasid);
++ dev_dbg(kfd_device, "get apertures for process pid %d", p->lead_thread->pid);
+
+ args->num_of_nodes = 0;
+
+@@ -757,7 +757,8 @@ static int kfd_ioctl_get_process_apertures_new(struct file *filp,
+ int ret;
+ int i;
+
+- dev_dbg(kfd_device, "get apertures for PASID 0x%x", p->pasid);
++ dev_dbg(kfd_device, "get apertures for process pid %d",
++ p->lead_thread->pid);
+
+ if (args->num_of_nodes == 0) {
+ /* Return number of nodes, so that user space can alloacate
+@@ -3375,12 +3376,12 @@ static int kfd_mmio_mmap(struct kfd_node *dev, struct kfd_process *process,
+
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+- pr_debug("pasid 0x%x mapping mmio page\n"
++ pr_debug("process pid %d mapping mmio page\n"
+ " target user address == 0x%08llX\n"
+ " physical address == 0x%08llX\n"
+ " vm_flags == 0x%04lX\n"
+ " size == 0x%04lX\n",
+- process->pasid, (unsigned long long) vma->vm_start,
++ process->lead_thread->pid, (unsigned long long) vma->vm_start,
+ address, vma->vm_flags, PAGE_SIZE);
+
+ return io_remap_pfn_range(vma,
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_debug.c b/drivers/gpu/drm/amd/amdkfd/kfd_debug.c
+index a8abc30918013..12456c61ffa54 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_debug.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_debug.c
+@@ -204,11 +204,12 @@ bool kfd_set_dbg_ev_from_interrupt(struct kfd_node *dev,
+ size_t exception_data_size)
+ {
+ struct kfd_process *p;
++ struct kfd_process_device *pdd = NULL;
+ bool signaled_to_debugger_or_runtime = false;
+
+- p = kfd_lookup_process_by_pasid(pasid);
++ p = kfd_lookup_process_by_pasid(pasid, &pdd);
+
+- if (!p)
++ if (!pdd)
+ return false;
+
+ if (!kfd_dbg_ev_raise(trap_mask, p, dev, doorbell_id, true,
+@@ -238,9 +239,8 @@ bool kfd_set_dbg_ev_from_interrupt(struct kfd_node *dev,
+
+ mutex_unlock(&p->mutex);
+ } else if (trap_mask & KFD_EC_MASK(EC_DEVICE_MEMORY_VIOLATION)) {
+- kfd_dqm_evict_pasid(dev->dqm, p->pasid);
+- kfd_signal_vm_fault_event(dev, p->pasid, NULL,
+- exception_data);
++ kfd_evict_process_device(pdd);
++ kfd_signal_vm_fault_event(pdd, NULL, exception_data);
+
+ signaled_to_debugger_or_runtime = true;
+ }
+@@ -276,8 +276,8 @@ int kfd_dbg_send_exception_to_runtime(struct kfd_process *p,
+ data = (struct kfd_hsa_memory_exception_data *)
+ pdd->vm_fault_exc_data;
+
+- kfd_dqm_evict_pasid(pdd->dev->dqm, p->pasid);
+- kfd_signal_vm_fault_event(pdd->dev, p->pasid, NULL, data);
++ kfd_evict_process_device(pdd);
++ kfd_signal_vm_fault_event(pdd, NULL, data);
+ error_reason &= ~KFD_EC_MASK(EC_DEVICE_MEMORY_VIOLATION);
+ }
+
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
+index 6cefd338f23de..bf978b368f6a5 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
+@@ -1558,7 +1558,7 @@ bool kgd2kfd_vmfault_fast_path(struct amdgpu_device *adev, struct amdgpu_iv_entr
+ u32 cam_index;
+
+ if (entry->ih == &adev->irq.ih_soft || entry->ih == &adev->irq.ih1) {
+- p = kfd_lookup_process_by_pasid(entry->pasid);
++ p = kfd_lookup_process_by_pasid(entry->pasid, NULL);
+ if (!p)
+ return true;
+
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
+index 7f8ec2a152ac6..35ae3c55a97fa 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
+@@ -208,7 +208,7 @@ static int add_queue_mes(struct device_queue_manager *dqm, struct queue *q,
+ return -EIO;
+
+ memset(&queue_input, 0x0, sizeof(struct mes_add_queue_input));
+- queue_input.process_id = qpd->pqm->process->pasid;
++ queue_input.process_id = pdd->pasid;
+ queue_input.page_table_base_addr = qpd->page_table_base;
+ queue_input.process_va_start = 0;
+ queue_input.process_va_end = adev->vm_manager.max_pfn - 1;
+@@ -527,6 +527,7 @@ static int allocate_vmid(struct device_queue_manager *dqm,
+ struct qcm_process_device *qpd,
+ struct queue *q)
+ {
++ struct kfd_process_device *pdd = qpd_to_pdd(qpd);
+ struct device *dev = dqm->dev->adev->dev;
+ int allocated_vmid = -1, i;
+
+@@ -545,9 +546,9 @@ static int allocate_vmid(struct device_queue_manager *dqm,
+
+ pr_debug("vmid allocated: %d\n", allocated_vmid);
+
+- dqm->vmid_pasid[allocated_vmid] = q->process->pasid;
++ dqm->vmid_pasid[allocated_vmid] = pdd->pasid;
+
+- set_pasid_vmid_mapping(dqm, q->process->pasid, allocated_vmid);
++ set_pasid_vmid_mapping(dqm, pdd->pasid, allocated_vmid);
+
+ qpd->vmid = allocated_vmid;
+ q->properties.vmid = allocated_vmid;
+@@ -799,6 +800,11 @@ static int dbgdev_wave_reset_wavefronts(struct kfd_node *dev, struct kfd_process
+ return -EOPNOTSUPP;
+ }
+
++ /* taking the VMID for that process on the safe way using PDD */
++ pdd = kfd_get_process_device_data(dev, p);
++ if (!pdd)
++ return -EFAULT;
++
+ /* Scan all registers in the range ATC_VMID8_PASID_MAPPING ..
+ * ATC_VMID15_PASID_MAPPING
+ * to check which VMID the current process is mapped to.
+@@ -808,23 +814,19 @@ static int dbgdev_wave_reset_wavefronts(struct kfd_node *dev, struct kfd_process
+ status = dev->kfd2kgd->get_atc_vmid_pasid_mapping_info
+ (dev->adev, vmid, &queried_pasid);
+
+- if (status && queried_pasid == p->pasid) {
+- pr_debug("Killing wave fronts of vmid %d and pasid 0x%x\n",
+- vmid, p->pasid);
++ if (status && queried_pasid == pdd->pasid) {
++ pr_debug("Killing wave fronts of vmid %d and process pid %d\n",
++ vmid, p->lead_thread->pid);
+ break;
+ }
+ }
+
+ if (vmid > last_vmid_to_scan) {
+- dev_err(dev->adev->dev, "Didn't find vmid for pasid 0x%x\n", p->pasid);
++ dev_err(dev->adev->dev, "Didn't find vmid for process pid %d\n",
++ p->lead_thread->pid);
+ return -EFAULT;
+ }
+
+- /* taking the VMID for that process on the safe way using PDD */
+- pdd = kfd_get_process_device_data(dev, p);
+- if (!pdd)
+- return -EFAULT;
+-
+ reg_gfx_index.bits.sh_broadcast_writes = 1;
+ reg_gfx_index.bits.se_broadcast_writes = 1;
+ reg_gfx_index.bits.instance_broadcast_writes = 1;
+@@ -1060,8 +1062,8 @@ static int suspend_single_queue(struct device_queue_manager *dqm,
+ if (q->properties.is_suspended)
+ return 0;
+
+- pr_debug("Suspending PASID %u queue [%i]\n",
+- pdd->process->pasid,
++ pr_debug("Suspending process pid %d queue [%i]\n",
++ pdd->process->lead_thread->pid,
+ q->properties.queue_id);
+
+ is_new = q->properties.exception_status & KFD_EC_MASK(EC_QUEUE_NEW);
+@@ -1108,8 +1110,8 @@ static int resume_single_queue(struct device_queue_manager *dqm,
+
+ pdd = qpd_to_pdd(qpd);
+
+- pr_debug("Restoring from suspend PASID %u queue [%i]\n",
+- pdd->process->pasid,
++ pr_debug("Restoring from suspend process pid %d queue [%i]\n",
++ pdd->process->lead_thread->pid,
+ q->properties.queue_id);
+
+ q->properties.is_suspended = false;
+@@ -1142,8 +1144,8 @@ static int evict_process_queues_nocpsch(struct device_queue_manager *dqm,
+ goto out;
+
+ pdd = qpd_to_pdd(qpd);
+- pr_debug_ratelimited("Evicting PASID 0x%x queues\n",
+- pdd->process->pasid);
++ pr_debug_ratelimited("Evicting process pid %d queues\n",
++ pdd->process->lead_thread->pid);
+
+ pdd->last_evict_timestamp = get_jiffies_64();
+ /* Mark all queues as evicted. Deactivate all active queues on
+@@ -1200,8 +1202,8 @@ static int evict_process_queues_cpsch(struct device_queue_manager *dqm,
+ if (!pdd->drm_priv)
+ goto out;
+
+- pr_debug_ratelimited("Evicting PASID 0x%x queues\n",
+- pdd->process->pasid);
++ pr_debug_ratelimited("Evicting process pid %d queues\n",
++ pdd->process->lead_thread->pid);
+
+ /* Mark all queues as evicted. Deactivate all active queues on
+ * the qpd.
+@@ -1261,8 +1263,8 @@ static int restore_process_queues_nocpsch(struct device_queue_manager *dqm,
+ goto out;
+ }
+
+- pr_debug_ratelimited("Restoring PASID 0x%x queues\n",
+- pdd->process->pasid);
++ pr_debug_ratelimited("Restoring process pid %d queues\n",
++ pdd->process->lead_thread->pid);
+
+ /* Update PD Base in QPD */
+ qpd->page_table_base = pd_base;
+@@ -1345,8 +1347,8 @@ static int restore_process_queues_cpsch(struct device_queue_manager *dqm,
+ if (!pdd->drm_priv)
+ goto vm_not_acquired;
+
+- pr_debug_ratelimited("Restoring PASID 0x%x queues\n",
+- pdd->process->pasid);
++ pr_debug_ratelimited("Restoring process pid %d queues\n",
++ pdd->process->lead_thread->pid);
+
+ /* Update PD Base in QPD */
+ qpd->page_table_base = amdgpu_amdkfd_gpuvm_get_process_page_dir(pdd->drm_priv);
+@@ -2137,8 +2139,8 @@ static void set_queue_as_reset(struct device_queue_manager *dqm, struct queue *q
+ {
+ struct kfd_process_device *pdd = qpd_to_pdd(qpd);
+
+- dev_err(dqm->dev->adev->dev, "queue id 0x%0x at pasid 0x%0x is reset\n",
+- q->properties.queue_id, q->process->pasid);
++ dev_err(dqm->dev->adev->dev, "queue id 0x%0x at pasid %d is reset\n",
++ q->properties.queue_id, pdd->process->lead_thread->pid);
+
+ pdd->has_reset_queue = true;
+ if (q->properties.is_active) {
+@@ -2941,20 +2943,19 @@ void device_queue_manager_uninit(struct device_queue_manager *dqm)
+
+ int kfd_dqm_suspend_bad_queue_mes(struct kfd_node *knode, u32 pasid, u32 doorbell_id)
+ {
+- struct kfd_process_device *pdd;
+- struct kfd_process *p = kfd_lookup_process_by_pasid(pasid);
++ struct kfd_process_device *pdd = NULL;
++ struct kfd_process *p = kfd_lookup_process_by_pasid(pasid, &pdd);
+ struct device_queue_manager *dqm = knode->dqm;
+ struct device *dev = dqm->dev->adev->dev;
+ struct qcm_process_device *qpd;
+ struct queue *q = NULL;
+ int ret = 0;
+
+- if (!p)
++ if (!pdd)
+ return -EINVAL;
+
+ dqm_lock(dqm);
+
+- pdd = kfd_get_process_device_data(dqm->dev, p);
+ if (pdd) {
+ qpd = &pdd->qpd;
+
+@@ -2987,6 +2988,7 @@ int kfd_dqm_suspend_bad_queue_mes(struct kfd_node *knode, u32 pasid, u32 doorbel
+
+ out:
+ dqm_unlock(dqm);
++ kfd_unref_process(p);
+ return ret;
+ }
+
+@@ -3028,24 +3030,21 @@ static int kfd_dqm_evict_pasid_mes(struct device_queue_manager *dqm,
+ return ret;
+ }
+
+-int kfd_dqm_evict_pasid(struct device_queue_manager *dqm, u32 pasid)
++int kfd_evict_process_device(struct kfd_process_device *pdd)
+ {
+- struct kfd_process_device *pdd;
+- struct kfd_process *p = kfd_lookup_process_by_pasid(pasid);
++ struct device_queue_manager *dqm;
++ struct kfd_process *p;
+ int ret = 0;
+
+- if (!p)
+- return -EINVAL;
++ p = pdd->process;
++ dqm = pdd->dev->dqm;
++
+ WARN(debug_evictions, "Evicting pid %d", p->lead_thread->pid);
+- pdd = kfd_get_process_device_data(dqm->dev, p);
+- if (pdd) {
+- if (dqm->dev->kfd->shared_resources.enable_mes)
+- ret = kfd_dqm_evict_pasid_mes(dqm, &pdd->qpd);
+- else
+- ret = dqm->ops.evict_process_queues(dqm, &pdd->qpd);
+- }
+
+- kfd_unref_process(p);
++ if (dqm->dev->kfd->shared_resources.enable_mes)
++ ret = kfd_dqm_evict_pasid_mes(dqm, &pdd->qpd);
++ else
++ ret = dqm->ops.evict_process_queues(dqm, &pdd->qpd);
+
+ return ret;
+ }
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_events.c
+index d075f24e5f9f3..fecdb67940750 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_events.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_events.c
+@@ -727,7 +727,7 @@ void kfd_signal_event_interrupt(u32 pasid, uint32_t partial_id,
+ * to process context, kfd_process could attempt to exit while we are
+ * running so the lookup function increments the process ref count.
+ */
+- struct kfd_process *p = kfd_lookup_process_by_pasid(pasid);
++ struct kfd_process *p = kfd_lookup_process_by_pasid(pasid, NULL);
+
+ if (!p)
+ return; /* Presumably process exited. */
+@@ -1139,8 +1139,8 @@ static void lookup_events_by_type_and_signal(struct kfd_process *p,
+
+ if (type == KFD_EVENT_TYPE_MEMORY) {
+ dev_warn(kfd_device,
+- "Sending SIGSEGV to process %d (pasid 0x%x)",
+- p->lead_thread->pid, p->pasid);
++ "Sending SIGSEGV to process pid %d",
++ p->lead_thread->pid);
+ send_sig(SIGSEGV, p->lead_thread, 0);
+ }
+
+@@ -1148,13 +1148,13 @@ static void lookup_events_by_type_and_signal(struct kfd_process *p,
+ if (send_signal) {
+ if (send_sigterm) {
+ dev_warn(kfd_device,
+- "Sending SIGTERM to process %d (pasid 0x%x)",
+- p->lead_thread->pid, p->pasid);
++ "Sending SIGTERM to process pid %d",
++ p->lead_thread->pid);
+ send_sig(SIGTERM, p->lead_thread, 0);
+ } else {
+ dev_err(kfd_device,
+- "Process %d (pasid 0x%x) got unhandled exception",
+- p->lead_thread->pid, p->pasid);
++ "Process pid %d got unhandled exception",
++ p->lead_thread->pid);
+ }
+ }
+
+@@ -1168,7 +1168,7 @@ void kfd_signal_hw_exception_event(u32 pasid)
+ * to process context, kfd_process could attempt to exit while we are
+ * running so the lookup function increments the process ref count.
+ */
+- struct kfd_process *p = kfd_lookup_process_by_pasid(pasid);
++ struct kfd_process *p = kfd_lookup_process_by_pasid(pasid, NULL);
+
+ if (!p)
+ return; /* Presumably process exited. */
+@@ -1177,22 +1177,20 @@ void kfd_signal_hw_exception_event(u32 pasid)
+ kfd_unref_process(p);
+ }
+
+-void kfd_signal_vm_fault_event(struct kfd_node *dev, u32 pasid,
++void kfd_signal_vm_fault_event(struct kfd_process_device *pdd,
+ struct kfd_vm_fault_info *info,
+ struct kfd_hsa_memory_exception_data *data)
+ {
+ struct kfd_event *ev;
+ uint32_t id;
+- struct kfd_process *p = kfd_lookup_process_by_pasid(pasid);
++ struct kfd_process *p = pdd->process;
+ struct kfd_hsa_memory_exception_data memory_exception_data;
+ int user_gpu_id;
+
+- if (!p)
+- return; /* Presumably process exited. */
+-
+- user_gpu_id = kfd_process_get_user_gpu_id(p, dev->id);
++ user_gpu_id = kfd_process_get_user_gpu_id(p, pdd->dev->id);
+ if (unlikely(user_gpu_id == -EINVAL)) {
+- WARN_ONCE(1, "Could not get user_gpu_id from dev->id:%x\n", dev->id);
++ WARN_ONCE(1, "Could not get user_gpu_id from dev->id:%x\n",
++ pdd->dev->id);
+ return;
+ }
+
+@@ -1229,7 +1227,6 @@ void kfd_signal_vm_fault_event(struct kfd_node *dev, u32 pasid,
+ }
+
+ rcu_read_unlock();
+- kfd_unref_process(p);
+ }
+
+ void kfd_signal_reset_event(struct kfd_node *dev)
+@@ -1264,7 +1261,8 @@ void kfd_signal_reset_event(struct kfd_node *dev)
+ }
+
+ if (unlikely(!pdd)) {
+- WARN_ONCE(1, "Could not get device data from pasid:0x%x\n", p->pasid);
++ WARN_ONCE(1, "Could not get device data from process pid:%d\n",
++ p->lead_thread->pid);
+ continue;
+ }
+
+@@ -1273,8 +1271,15 @@ void kfd_signal_reset_event(struct kfd_node *dev)
+
+ if (dev->dqm->detect_hang_count) {
+ struct amdgpu_task_info *ti;
++ struct amdgpu_fpriv *drv_priv;
++
++ if (unlikely(amdgpu_file_to_fpriv(pdd->drm_file, &drv_priv))) {
++ WARN_ONCE(1, "Could not get vm for device %x from pid:%d\n",
++ dev->id, p->lead_thread->pid);
++ continue;
++ }
+
+- ti = amdgpu_vm_get_task_info_pasid(dev->adev, p->pasid);
++ ti = amdgpu_vm_get_task_info_vm(&drv_priv->vm);
+ if (ti) {
+ dev_err(dev->adev->dev,
+ "Queues reset on process %s tid %d thread %s pid %d\n",
+@@ -1311,7 +1316,7 @@ void kfd_signal_reset_event(struct kfd_node *dev)
+
+ void kfd_signal_poison_consumed_event(struct kfd_node *dev, u32 pasid)
+ {
+- struct kfd_process *p = kfd_lookup_process_by_pasid(pasid);
++ struct kfd_process *p = kfd_lookup_process_by_pasid(pasid, NULL);
+ struct kfd_hsa_memory_exception_data memory_exception_data;
+ struct kfd_hsa_hw_exception_data hw_exception_data;
+ struct kfd_event *ev;
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v11.c b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v11.c
+index b3f988b275a88..c5f97e6e36ff5 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v11.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v11.c
+@@ -194,7 +194,7 @@ static void event_interrupt_poison_consumption_v11(struct kfd_node *dev,
+ enum amdgpu_ras_block block = 0;
+ int ret = -EINVAL;
+ uint32_t reset = 0;
+- struct kfd_process *p = kfd_lookup_process_by_pasid(pasid);
++ struct kfd_process *p = kfd_lookup_process_by_pasid(pasid, NULL);
+
+ if (!p)
+ return;
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c
+index 0cb5c582ce7dc..b8a91bf4ef307 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c
+@@ -146,7 +146,7 @@ static void event_interrupt_poison_consumption_v9(struct kfd_node *dev,
+ {
+ enum amdgpu_ras_block block = 0;
+ uint32_t reset = 0;
+- struct kfd_process *p = kfd_lookup_process_by_pasid(pasid);
++ struct kfd_process *p = kfd_lookup_process_by_pasid(pasid, NULL);
+ enum ras_event_type type = RAS_EVENT_TYPE_POISON_CONSUMPTION;
+ u64 event_id;
+ int old_poison, ret;
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager_v9.c
+index 1f9f5bfeaf868..d56525201155a 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager_v9.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager_v9.c
+@@ -47,7 +47,7 @@ static int pm_map_process_v9(struct packet_manager *pm,
+ packet->bitfields2.exec_cleaner_shader = 1;
+ packet->bitfields2.diq_enable = (qpd->is_debug) ? 1 : 0;
+ packet->bitfields2.process_quantum = 10;
+- packet->bitfields2.pasid = qpd->pqm->process->pasid;
++ packet->bitfields2.pasid = pdd->pasid;
+ packet->bitfields14.gds_size = qpd->gds_size & 0x3F;
+ packet->bitfields14.gds_size_hi = (qpd->gds_size >> 6) & 0xF;
+ packet->bitfields14.num_gws = (qpd->mapped_gws_queue) ? qpd->num_gws : 0;
+@@ -106,7 +106,7 @@ static int pm_map_process_aldebaran(struct packet_manager *pm,
+ packet->bitfields2.exec_cleaner_shader = 1;
+ packet->bitfields2.diq_enable = (qpd->is_debug) ? 1 : 0;
+ packet->bitfields2.process_quantum = 10;
+- packet->bitfields2.pasid = qpd->pqm->process->pasid;
++ packet->bitfields2.pasid = pdd->pasid;
+ packet->bitfields14.gds_size = qpd->gds_size & 0x3F;
+ packet->bitfields14.gds_size_hi = (qpd->gds_size >> 6) & 0xF;
+ packet->bitfields14.num_gws = (qpd->mapped_gws_queue) ? qpd->num_gws : 0;
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager_vi.c
+index c1199d06d131b..347c86e1c378f 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager_vi.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager_vi.c
+@@ -42,6 +42,7 @@ unsigned int pm_build_pm4_header(unsigned int opcode, size_t packet_size)
+ static int pm_map_process_vi(struct packet_manager *pm, uint32_t *buffer,
+ struct qcm_process_device *qpd)
+ {
++ struct kfd_process_device *pdd = qpd_to_pdd(qpd);
+ struct pm4_mes_map_process *packet;
+
+ packet = (struct pm4_mes_map_process *)buffer;
+@@ -52,7 +53,7 @@ static int pm_map_process_vi(struct packet_manager *pm, uint32_t *buffer,
+ sizeof(struct pm4_mes_map_process));
+ packet->bitfields2.diq_enable = (qpd->is_debug) ? 1 : 0;
+ packet->bitfields2.process_quantum = 10;
+- packet->bitfields2.pasid = qpd->pqm->process->pasid;
++ packet->bitfields2.pasid = pdd->pasid;
+ packet->bitfields3.page_table_base = qpd->page_table_base;
+ packet->bitfields10.gds_size = qpd->gds_size;
+ packet->bitfields10.num_gws = qpd->num_gws;
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
+index d8cd913aa772b..0a99c5c9cadc0 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
+@@ -851,6 +851,8 @@ struct kfd_process_device {
+
+ /* Tracks queue reset status */
+ bool has_reset_queue;
++
++ u32 pasid;
+ };
+
+ #define qpd_to_pdd(x) container_of(x, struct kfd_process_device, qpd)
+@@ -910,8 +912,6 @@ struct kfd_process {
+ /* We want to receive a notification when the mm_struct is destroyed */
+ struct mmu_notifier mmu_notifier;
+
+- u32 pasid;
+-
+ /*
+ * Array of kfd_process_device pointers,
+ * one for each device the process is using.
+@@ -1039,7 +1039,8 @@ void kfd_process_destroy_wq(void);
+ void kfd_cleanup_processes(void);
+ struct kfd_process *kfd_create_process(struct task_struct *thread);
+ struct kfd_process *kfd_get_process(const struct task_struct *task);
+-struct kfd_process *kfd_lookup_process_by_pasid(u32 pasid);
++struct kfd_process *kfd_lookup_process_by_pasid(u32 pasid,
++ struct kfd_process_device **pdd);
+ struct kfd_process *kfd_lookup_process_by_mm(const struct mm_struct *mm);
+
+ int kfd_process_gpuidx_from_gpuid(struct kfd_process *p, uint32_t gpu_id);
+@@ -1337,7 +1338,7 @@ void device_queue_manager_uninit(struct device_queue_manager *dqm);
+ struct kernel_queue *kernel_queue_init(struct kfd_node *dev,
+ enum kfd_queue_type type);
+ void kernel_queue_uninit(struct kernel_queue *kq);
+-int kfd_dqm_evict_pasid(struct device_queue_manager *dqm, u32 pasid);
++int kfd_evict_process_device(struct kfd_process_device *pdd);
+ int kfd_dqm_suspend_bad_queue_mes(struct kfd_node *knode, u32 pasid, u32 doorbell_id);
+
+ /* Process Queue Manager */
+@@ -1492,7 +1493,7 @@ int kfd_event_create(struct file *devkfd, struct kfd_process *p,
+ int kfd_get_num_events(struct kfd_process *p);
+ int kfd_event_destroy(struct kfd_process *p, uint32_t event_id);
+
+-void kfd_signal_vm_fault_event(struct kfd_node *dev, u32 pasid,
++void kfd_signal_vm_fault_event(struct kfd_process_device *pdd,
+ struct kfd_vm_fault_info *info,
+ struct kfd_hsa_memory_exception_data *data);
+
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
+index c9cbc0ecd9cb2..a7e0a16dac47b 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
+@@ -283,8 +283,8 @@ static int kfd_get_cu_occupancy(struct attribute *attr, char *buffer)
+ cu_cnt = 0;
+ proc = pdd->process;
+ if (pdd->qpd.queue_count == 0) {
+- pr_debug("Gpu-Id: %d has no active queues for process %d\n",
+- dev->id, proc->pasid);
++ pr_debug("Gpu-Id: %d has no active queues for process pid %d\n",
++ dev->id, (int)proc->lead_thread->pid);
+ return snprintf(buffer, PAGE_SIZE, "%d\n", cu_cnt);
+ }
+
+@@ -328,12 +328,9 @@ static int kfd_get_cu_occupancy(struct attribute *attr, char *buffer)
+ static ssize_t kfd_procfs_show(struct kobject *kobj, struct attribute *attr,
+ char *buffer)
+ {
+- if (strcmp(attr->name, "pasid") == 0) {
+- struct kfd_process *p = container_of(attr, struct kfd_process,
+- attr_pasid);
+-
+- return snprintf(buffer, PAGE_SIZE, "%d\n", p->pasid);
+- } else if (strncmp(attr->name, "vram_", 5) == 0) {
++ if (strcmp(attr->name, "pasid") == 0)
++ return snprintf(buffer, PAGE_SIZE, "%d\n", 0);
++ else if (strncmp(attr->name, "vram_", 5) == 0) {
+ struct kfd_process_device *pdd = container_of(attr, struct kfd_process_device,
+ attr_vram);
+ return snprintf(buffer, PAGE_SIZE, "%llu\n", atomic64_read(&pdd->vram_usage));
+@@ -1057,9 +1054,8 @@ static void kfd_process_destroy_pdds(struct kfd_process *p)
+ for (i = 0; i < p->n_pdds; i++) {
+ struct kfd_process_device *pdd = p->pdds[i];
+
+- pr_debug("Releasing pdd (topology id %d) for process (pasid 0x%x)\n",
+- pdd->dev->id, p->pasid);
+-
++ pr_debug("Releasing pdd (topology id %d, for pid %d)\n",
++ pdd->dev->id, p->lead_thread->pid);
+ kfd_process_device_destroy_cwsr_dgpu(pdd);
+ kfd_process_device_destroy_ib_mem(pdd);
+
+@@ -1191,7 +1187,6 @@ static void kfd_process_wq_release(struct work_struct *work)
+
+ kfd_event_free_process(p);
+
+- kfd_pasid_free(p->pasid);
+ mutex_destroy(&p->mutex);
+
+ put_task_struct(p->lead_thread);
+@@ -1542,12 +1537,6 @@ static struct kfd_process *create_process(const struct task_struct *thread)
+ atomic_set(&process->debugged_process_count, 0);
+ sema_init(&process->runtime_enable_sema, 0);
+
+- process->pasid = kfd_pasid_alloc();
+- if (process->pasid == 0) {
+- err = -ENOSPC;
+- goto err_alloc_pasid;
+- }
+-
+ err = pqm_init(&process->pqm, process);
+ if (err != 0)
+ goto err_process_pqm_init;
+@@ -1601,8 +1590,6 @@ static struct kfd_process *create_process(const struct task_struct *thread)
+ err_init_apertures:
+ pqm_uninit(&process->pqm);
+ err_process_pqm_init:
+- kfd_pasid_free(process->pasid);
+-err_alloc_pasid:
+ kfd_event_free_process(process);
+ err_event_init:
+ mutex_destroy(&process->mutex);
+@@ -1721,15 +1708,18 @@ int kfd_process_device_init_vm(struct kfd_process_device *pdd,
+ if (ret)
+ goto err_init_cwsr;
+
+- ret = amdgpu_amdkfd_gpuvm_set_vm_pasid(dev->adev, avm, p->pasid);
+- if (ret)
+- goto err_set_pasid;
++ if (unlikely(!avm->pasid)) {
++ dev_warn(pdd->dev->adev->dev, "WARN: vm %p has no pasid associated",
++ avm);
++ goto err_get_pasid;
++ }
+
++ pdd->pasid = avm->pasid;
+ pdd->drm_file = drm_file;
+
+ return 0;
+
+-err_set_pasid:
++err_get_pasid:
+ kfd_process_device_destroy_cwsr_dgpu(pdd);
+ err_init_cwsr:
+ kfd_process_device_destroy_ib_mem(pdd);
+@@ -1815,25 +1805,50 @@ void kfd_process_device_remove_obj_handle(struct kfd_process_device *pdd,
+ idr_remove(&pdd->alloc_idr, handle);
+ }
+
+-/* This increments the process->ref counter. */
+-struct kfd_process *kfd_lookup_process_by_pasid(u32 pasid)
++static struct kfd_process_device *kfd_lookup_process_device_by_pasid(u32 pasid)
+ {
+- struct kfd_process *p, *ret_p = NULL;
++ struct kfd_process_device *ret_p = NULL;
++ struct kfd_process *p;
+ unsigned int temp;
+-
+- int idx = srcu_read_lock(&kfd_processes_srcu);
++ int i;
+
+ hash_for_each_rcu(kfd_processes_table, temp, p, kfd_processes) {
+- if (p->pasid == pasid) {
+- kref_get(&p->ref);
+- ret_p = p;
+- break;
++ for (i = 0; i < p->n_pdds; i++) {
++ if (p->pdds[i]->pasid == pasid) {
++ ret_p = p->pdds[i];
++ break;
++ }
+ }
++ if (ret_p)
++ break;
++ }
++ return ret_p;
++}
++
++/* This increments the process->ref counter. */
++struct kfd_process *kfd_lookup_process_by_pasid(u32 pasid,
++ struct kfd_process_device **pdd)
++{
++ struct kfd_process_device *ret_p;
++
++ int idx = srcu_read_lock(&kfd_processes_srcu);
++
++ ret_p = kfd_lookup_process_device_by_pasid(pasid);
++ if (ret_p) {
++ if (pdd)
++ *pdd = ret_p;
++ kref_get(&ret_p->process->ref);
++
++ srcu_read_unlock(&kfd_processes_srcu, idx);
++ return ret_p->process;
+ }
+
+ srcu_read_unlock(&kfd_processes_srcu, idx);
+
+- return ret_p;
++ if (pdd)
++ *pdd = NULL;
++
++ return NULL;
+ }
+
+ /* This increments the process->ref counter. */
+@@ -1989,7 +2004,7 @@ static void evict_process_worker(struct work_struct *work)
+ */
+ p = container_of(dwork, struct kfd_process, eviction_work);
+
+- pr_debug("Started evicting pasid 0x%x\n", p->pasid);
++ pr_debug("Started evicting process pid %d\n", p->lead_thread->pid);
+ ret = kfd_process_evict_queues(p, KFD_QUEUE_EVICTION_TRIGGER_TTM);
+ if (!ret) {
+ /* If another thread already signaled the eviction fence,
+@@ -2001,9 +2016,9 @@ static void evict_process_worker(struct work_struct *work)
+ msecs_to_jiffies(PROCESS_RESTORE_TIME_MS)))
+ kfd_process_restore_queues(p);
+
+- pr_debug("Finished evicting pasid 0x%x\n", p->pasid);
++ pr_debug("Finished evicting process pid %d\n", p->lead_thread->pid);
+ } else
+- pr_err("Failed to evict queues of pasid 0x%x\n", p->pasid);
++ pr_err("Failed to evict queues of process pid %d\n", p->lead_thread->pid);
+ }
+
+ static int restore_process_helper(struct kfd_process *p)
+@@ -2020,9 +2035,11 @@ static int restore_process_helper(struct kfd_process *p)
+
+ ret = kfd_process_restore_queues(p);
+ if (!ret)
+- pr_debug("Finished restoring pasid 0x%x\n", p->pasid);
++ pr_debug("Finished restoring process pid %d\n",
++ p->lead_thread->pid);
+ else
+- pr_err("Failed to restore queues of pasid 0x%x\n", p->pasid);
++ pr_err("Failed to restore queues of process pid %d\n",
++ p->lead_thread->pid);
+
+ return ret;
+ }
+@@ -2039,7 +2056,7 @@ static void restore_process_worker(struct work_struct *work)
+ * lifetime of this thread, kfd_process p will be valid
+ */
+ p = container_of(dwork, struct kfd_process, restore_work);
+- pr_debug("Started restoring pasid 0x%x\n", p->pasid);
++ pr_debug("Started restoring process pasid %d\n", (int)p->lead_thread->pid);
+
+ /* Setting last_restore_timestamp before successful restoration.
+ * Otherwise this would have to be set by KGD (restore_process_bos)
+@@ -2055,8 +2072,8 @@ static void restore_process_worker(struct work_struct *work)
+
+ ret = restore_process_helper(p);
+ if (ret) {
+- pr_debug("Failed to restore BOs of pasid 0x%x, retry after %d ms\n",
+- p->pasid, PROCESS_BACK_OFF_TIME_MS);
++ pr_debug("Failed to restore BOs of process pid %d, retry after %d ms\n",
++ p->lead_thread->pid, PROCESS_BACK_OFF_TIME_MS);
+ if (mod_delayed_work(kfd_restore_wq, &p->restore_work,
+ msecs_to_jiffies(PROCESS_RESTORE_TIME_MS)))
+ kfd_process_restore_queues(p);
+@@ -2072,7 +2089,7 @@ void kfd_suspend_all_processes(void)
+ WARN(debug_evictions, "Evicting all processes");
+ hash_for_each_rcu(kfd_processes_table, temp, p, kfd_processes) {
+ if (kfd_process_evict_queues(p, KFD_QUEUE_EVICTION_TRIGGER_SUSPEND))
+- pr_err("Failed to suspend process 0x%x\n", p->pasid);
++ pr_err("Failed to suspend process pid %d\n", p->lead_thread->pid);
+ signal_eviction_fence(p);
+ }
+ srcu_read_unlock(&kfd_processes_srcu, idx);
+@@ -2086,8 +2103,8 @@ int kfd_resume_all_processes(void)
+
+ hash_for_each_rcu(kfd_processes_table, temp, p, kfd_processes) {
+ if (restore_process_helper(p)) {
+- pr_err("Restore process %d failed during resume\n",
+- p->pasid);
++ pr_err("Restore process pid %d failed during resume\n",
++ p->lead_thread->pid);
+ ret = -EFAULT;
+ }
+ }
+@@ -2142,7 +2159,7 @@ int kfd_process_drain_interrupts(struct kfd_process_device *pdd)
+ memset(irq_drain_fence, 0, sizeof(irq_drain_fence));
+ irq_drain_fence[0] = (KFD_IRQ_FENCE_SOURCEID << 8) |
+ KFD_IRQ_FENCE_CLIENTID;
+- irq_drain_fence[3] = pdd->process->pasid;
++ irq_drain_fence[3] = pdd->pasid;
+
+ /*
+ * For GFX 9.4.3/9.5.0, send the NodeId also in IH cookie DW[3]
+@@ -2173,7 +2190,7 @@ void kfd_process_close_interrupt_drain(unsigned int pasid)
+ {
+ struct kfd_process *p;
+
+- p = kfd_lookup_process_by_pasid(pasid);
++ p = kfd_lookup_process_by_pasid(pasid, NULL);
+
+ if (!p)
+ return;
+@@ -2294,8 +2311,8 @@ int kfd_debugfs_mqds_by_process(struct seq_file *m, void *data)
+ int idx = srcu_read_lock(&kfd_processes_srcu);
+
+ hash_for_each_rcu(kfd_processes_table, temp, p, kfd_processes) {
+- seq_printf(m, "Process %d PASID 0x%x:\n",
+- p->lead_thread->tgid, p->pasid);
++ seq_printf(m, "Process %d PASID %d:\n",
++ p->lead_thread->tgid, p->lead_thread->pid);
+
+ mutex_lock(&p->mutex);
+ r = pqm_debugfs_mqds(m, &p->pqm);
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
+index d79caa1a68676..662c595ce7838 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
+@@ -69,8 +69,8 @@ static int find_available_queue_slot(struct process_queue_manager *pqm,
+ pr_debug("The new slot id %lu\n", found);
+
+ if (found >= KFD_MAX_NUM_OF_QUEUES_PER_PROCESS) {
+- pr_info("Cannot open more queues for process with pasid 0x%x\n",
+- pqm->process->pasid);
++ pr_info("Cannot open more queues for process with pid %d\n",
++ pqm->process->lead_thread->pid);
+ return -ENOMEM;
+ }
+
+@@ -451,8 +451,8 @@ int pqm_create_queue(struct process_queue_manager *pqm,
+ }
+
+ if (retval != 0) {
+- pr_err("Pasid 0x%x DQM create queue type %d failed. ret %d\n",
+- pqm->process->pasid, type, retval);
++ pr_err("process pid %d DQM create queue type %d failed. ret %d\n",
++ pqm->process->lead_thread->pid, type, retval);
+ goto err_create_queue;
+ }
+
+@@ -546,7 +546,7 @@ int pqm_destroy_queue(struct process_queue_manager *pqm, unsigned int qid)
+ retval = dqm->ops.destroy_queue(dqm, &pdd->qpd, pqn->q);
+ if (retval) {
+ pr_err("Pasid 0x%x destroy queue %d failed, ret %d\n",
+- pqm->process->pasid,
++ pdd->pasid,
+ pqn->q->properties.queue_id, retval);
+ if (retval != -ETIME && retval != -EIO)
+ goto err_destroy_queue;
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
+index 47189453b20c3..116116a9f5781 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
+@@ -563,7 +563,8 @@ svm_range_vram_node_new(struct kfd_node *node, struct svm_range *prange,
+ int r;
+
+ p = container_of(prange->svms, struct kfd_process, svms);
+- pr_debug("pasid: %x svms 0x%p [0x%lx 0x%lx]\n", p->pasid, prange->svms,
++ pr_debug("process pid: %d svms 0x%p [0x%lx 0x%lx]\n",
++ p->lead_thread->pid, prange->svms,
+ prange->start, prange->last);
+
+ if (svm_range_validate_svm_bo(node, prange))
+@@ -2973,7 +2974,7 @@ svm_range_restore_pages(struct amdgpu_device *adev, unsigned int pasid,
+ return -EFAULT;
+ }
+
+- p = kfd_lookup_process_by_pasid(pasid);
++ p = kfd_lookup_process_by_pasid(pasid, NULL);
+ if (!p) {
+ pr_debug("kfd process not founded pasid 0x%x\n", pasid);
+ return 0;
+@@ -3239,7 +3240,8 @@ void svm_range_list_fini(struct kfd_process *p)
+ struct svm_range *prange;
+ struct svm_range *next;
+
+- pr_debug("pasid 0x%x svms 0x%p\n", p->pasid, &p->svms);
++ pr_debug("process pid %d svms 0x%p\n", p->lead_thread->pid,
++ &p->svms);
+
+ cancel_delayed_work_sync(&p->svms.restore_work);
+
+@@ -3262,7 +3264,8 @@ void svm_range_list_fini(struct kfd_process *p)
+
+ mutex_destroy(&p->svms.lock);
+
+- pr_debug("pasid 0x%x svms 0x%p done\n", p->pasid, &p->svms);
++ pr_debug("process pid %d svms 0x%p done\n",
++ p->lead_thread->pid, &p->svms);
+ }
+
+ int svm_range_list_init(struct kfd_process *p)
+@@ -3625,8 +3628,8 @@ svm_range_set_attr(struct kfd_process *p, struct mm_struct *mm,
+ bool flush_tlb;
+ int r, ret = 0;
+
+- pr_debug("pasid 0x%x svms 0x%p [0x%llx 0x%llx] pages 0x%llx\n",
+- p->pasid, &p->svms, start, start + size - 1, size);
++ pr_debug("process pid %d svms 0x%p [0x%llx 0x%llx] pages 0x%llx\n",
++ p->lead_thread->pid, &p->svms, start, start + size - 1, size);
+
+ r = svm_range_check_attr(p, nattr, attrs);
+ if (r)
+@@ -3734,8 +3737,8 @@ svm_range_set_attr(struct kfd_process *p, struct mm_struct *mm,
+ out:
+ mutex_unlock(&process_info->lock);
+
+- pr_debug("pasid 0x%x svms 0x%p [0x%llx 0x%llx] done, r=%d\n", p->pasid,
+- &p->svms, start, start + size - 1, r);
++ pr_debug("process pid %d svms 0x%p [0x%llx 0x%llx] done, r=%d\n",
++ p->lead_thread->pid, &p->svms, start, start + size - 1, r);
+
+ return ret ? ret : r;
+ }
+--
+2.39.5
+
--- /dev/null
+From 6885273d67c22bddb4e6e30f3b4ba04a458023c7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 17 Feb 2025 20:08:29 -0500
+Subject: drm/amdkfd: KFD release_work possible circular locking
+
+From: Philip Yang <Philip.Yang@amd.com>
+
+[ Upstream commit 1b9366c601039d60546794c63fbb83ce8e53b978 ]
+
+If waiting for gpu reset done in KFD release_work, thers is WARNING:
+possible circular locking dependency detected
+
+ #2 kfd_create_process
+ kfd_process_mutex
+ flush kfd release work
+
+ #1 kfd release work
+ wait for amdgpu reset work
+
+ #0 amdgpu_device_gpu_reset
+ kgd2kfd_pre_reset
+ kfd_process_mutex
+
+ Possible unsafe locking scenario:
+
+ CPU0 CPU1
+ ---- ----
+ lock((work_completion)(&p->release_work));
+ lock((wq_completion)kfd_process_wq);
+ lock((work_completion)(&p->release_work));
+ lock((wq_completion)amdgpu-reset-dev);
+
+To fix this, KFD create process move flush release work outside
+kfd_process_mutex.
+
+Signed-off-by: Philip Yang <Philip.Yang@amd.com>
+Reviewed-by: Felix Kuehling <felix.kuehling@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdkfd/kfd_process.c | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
+index c3f2c0428e013..c9cbc0ecd9cb2 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
+@@ -842,6 +842,14 @@ struct kfd_process *kfd_create_process(struct task_struct *thread)
+ return ERR_PTR(-EINVAL);
+ }
+
++ /* If the process just called exec(3), it is possible that the
++ * cleanup of the kfd_process (following the release of the mm
++ * of the old process image) is still in the cleanup work queue.
++ * Make sure to drain any job before trying to recreate any
++ * resource for this process.
++ */
++ flush_workqueue(kfd_process_wq);
++
+ /*
+ * take kfd processes mutex before starting of process creation
+ * so there won't be a case where two threads of the same process
+@@ -862,14 +870,6 @@ struct kfd_process *kfd_create_process(struct task_struct *thread)
+ if (process) {
+ pr_debug("Process already found\n");
+ } else {
+- /* If the process just called exec(3), it is possible that the
+- * cleanup of the kfd_process (following the release of the mm
+- * of the old process image) is still in the cleanup work queue.
+- * Make sure to drain any job before trying to recreate any
+- * resource for this process.
+- */
+- flush_workqueue(kfd_process_wq);
+-
+ process = create_process(thread);
+ if (IS_ERR(process))
+ goto out;
+--
+2.39.5
+
--- /dev/null
+From c1e74e5dd6097dade4ca575cd47120dbe43c6cfe Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 14 Jan 2025 14:07:24 -0500
+Subject: drm/amdkfd: Set per-process flags only once cik/vi
+
+From: Harish Kasiviswanathan <Harish.Kasiviswanathan@amd.com>
+
+[ Upstream commit 289e68503a4533b014f8447e2af28ad44c92c221 ]
+
+Set per-process static sh_mem config only once during process
+initialization. Move all static changes from update_qpd() which is
+called each time a queue is created to set_cache_memory_policy() which
+is called once during process initialization.
+
+set_cache_memory_policy() is currently defined only for cik and vi
+family. So this commit only focuses on these two. A separate commit will
+address other asics.
+
+Signed-off-by: Harish Kasiviswanathan <Harish.Kasiviswanathan@amd.com>
+Reviewed-by: Amber Lin <Amber.Lin@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../drm/amd/amdkfd/kfd_device_queue_manager.c | 39 +---------
+ .../amd/amdkfd/kfd_device_queue_manager_cik.c | 69 ++++++++++++------
+ .../amd/amdkfd/kfd_device_queue_manager_vi.c | 71 ++++++++++++-------
+ 3 files changed, 94 insertions(+), 85 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
+index ad9cb50a9fa38..7f8ec2a152ac6 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
+@@ -2491,14 +2491,6 @@ static int destroy_queue_cpsch(struct device_queue_manager *dqm,
+ return retval;
+ }
+
+-/*
+- * Low bits must be 0000/FFFF as required by HW, high bits must be 0 to
+- * stay in user mode.
+- */
+-#define APE1_FIXED_BITS_MASK 0xFFFF80000000FFFFULL
+-/* APE1 limit is inclusive and 64K aligned. */
+-#define APE1_LIMIT_ALIGNMENT 0xFFFF
+-
+ static bool set_cache_memory_policy(struct device_queue_manager *dqm,
+ struct qcm_process_device *qpd,
+ enum cache_policy default_policy,
+@@ -2513,34 +2505,6 @@ static bool set_cache_memory_policy(struct device_queue_manager *dqm,
+
+ dqm_lock(dqm);
+
+- if (alternate_aperture_size == 0) {
+- /* base > limit disables APE1 */
+- qpd->sh_mem_ape1_base = 1;
+- qpd->sh_mem_ape1_limit = 0;
+- } else {
+- /*
+- * In FSA64, APE1_Base[63:0] = { 16{SH_MEM_APE1_BASE[31]},
+- * SH_MEM_APE1_BASE[31:0], 0x0000 }
+- * APE1_Limit[63:0] = { 16{SH_MEM_APE1_LIMIT[31]},
+- * SH_MEM_APE1_LIMIT[31:0], 0xFFFF }
+- * Verify that the base and size parameters can be
+- * represented in this format and convert them.
+- * Additionally restrict APE1 to user-mode addresses.
+- */
+-
+- uint64_t base = (uintptr_t)alternate_aperture_base;
+- uint64_t limit = base + alternate_aperture_size - 1;
+-
+- if (limit <= base || (base & APE1_FIXED_BITS_MASK) != 0 ||
+- (limit & APE1_FIXED_BITS_MASK) != APE1_LIMIT_ALIGNMENT) {
+- retval = false;
+- goto out;
+- }
+-
+- qpd->sh_mem_ape1_base = base >> 16;
+- qpd->sh_mem_ape1_limit = limit >> 16;
+- }
+-
+ retval = dqm->asic_ops.set_cache_memory_policy(
+ dqm,
+ qpd,
+@@ -2549,6 +2513,9 @@ static bool set_cache_memory_policy(struct device_queue_manager *dqm,
+ alternate_aperture_base,
+ alternate_aperture_size);
+
++ if (retval)
++ goto out;
++
+ if ((dqm->sched_policy == KFD_SCHED_POLICY_NO_HWS) && (qpd->vmid != 0))
+ program_sh_mem_settings(dqm, qpd);
+
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c
+index d4d95c7f2e5d4..32bedef912b3b 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c
+@@ -27,6 +27,14 @@
+ #include "oss/oss_2_4_sh_mask.h"
+ #include "gca/gfx_7_2_sh_mask.h"
+
++/*
++ * Low bits must be 0000/FFFF as required by HW, high bits must be 0 to
++ * stay in user mode.
++ */
++#define APE1_FIXED_BITS_MASK 0xFFFF80000000FFFFULL
++/* APE1 limit is inclusive and 64K aligned. */
++#define APE1_LIMIT_ALIGNMENT 0xFFFF
++
+ static bool set_cache_memory_policy_cik(struct device_queue_manager *dqm,
+ struct qcm_process_device *qpd,
+ enum cache_policy default_policy,
+@@ -84,6 +92,36 @@ static bool set_cache_memory_policy_cik(struct device_queue_manager *dqm,
+ {
+ uint32_t default_mtype;
+ uint32_t ape1_mtype;
++ unsigned int temp;
++ bool retval = true;
++
++ if (alternate_aperture_size == 0) {
++ /* base > limit disables APE1 */
++ qpd->sh_mem_ape1_base = 1;
++ qpd->sh_mem_ape1_limit = 0;
++ } else {
++ /*
++ * In FSA64, APE1_Base[63:0] = { 16{SH_MEM_APE1_BASE[31]},
++ * SH_MEM_APE1_BASE[31:0], 0x0000 }
++ * APE1_Limit[63:0] = { 16{SH_MEM_APE1_LIMIT[31]},
++ * SH_MEM_APE1_LIMIT[31:0], 0xFFFF }
++ * Verify that the base and size parameters can be
++ * represented in this format and convert them.
++ * Additionally restrict APE1 to user-mode addresses.
++ */
++
++ uint64_t base = (uintptr_t)alternate_aperture_base;
++ uint64_t limit = base + alternate_aperture_size - 1;
++
++ if (limit <= base || (base & APE1_FIXED_BITS_MASK) != 0 ||
++ (limit & APE1_FIXED_BITS_MASK) != APE1_LIMIT_ALIGNMENT) {
++ retval = false;
++ goto out;
++ }
++
++ qpd->sh_mem_ape1_base = base >> 16;
++ qpd->sh_mem_ape1_limit = limit >> 16;
++ }
+
+ default_mtype = (default_policy == cache_policy_coherent) ?
+ MTYPE_NONCACHED :
+@@ -97,37 +135,22 @@ static bool set_cache_memory_policy_cik(struct device_queue_manager *dqm,
+ | ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED)
+ | DEFAULT_MTYPE(default_mtype)
+ | APE1_MTYPE(ape1_mtype);
+-
+- return true;
+-}
+-
+-static int update_qpd_cik(struct device_queue_manager *dqm,
+- struct qcm_process_device *qpd)
+-{
+- struct kfd_process_device *pdd;
+- unsigned int temp;
+-
+- pdd = qpd_to_pdd(qpd);
+-
+- /* check if sh_mem_config register already configured */
+- if (qpd->sh_mem_config == 0) {
+- qpd->sh_mem_config =
+- ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED) |
+- DEFAULT_MTYPE(MTYPE_NONCACHED) |
+- APE1_MTYPE(MTYPE_NONCACHED);
+- qpd->sh_mem_ape1_limit = 0;
+- qpd->sh_mem_ape1_base = 0;
+- }
+-
+ /* On dGPU we're always in GPUVM64 addressing mode with 64-bit
+ * aperture addresses.
+ */
+- temp = get_sh_mem_bases_nybble_64(pdd);
++ temp = get_sh_mem_bases_nybble_64(qpd_to_pdd(qpd));
+ qpd->sh_mem_bases = compute_sh_mem_bases_64bit(temp);
+
+ pr_debug("is32bit process: %d sh_mem_bases nybble: 0x%X and register 0x%X\n",
+ qpd->pqm->process->is_32bit_user_mode, temp, qpd->sh_mem_bases);
+
++out:
++ return retval;
++}
++
++static int update_qpd_cik(struct device_queue_manager *dqm,
++ struct qcm_process_device *qpd)
++{
+ return 0;
+ }
+
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c
+index b291ee0fab943..320518f418903 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c
+@@ -27,6 +27,14 @@
+ #include "gca/gfx_8_0_sh_mask.h"
+ #include "oss/oss_3_0_sh_mask.h"
+
++/*
++ * Low bits must be 0000/FFFF as required by HW, high bits must be 0 to
++ * stay in user mode.
++ */
++#define APE1_FIXED_BITS_MASK 0xFFFF80000000FFFFULL
++/* APE1 limit is inclusive and 64K aligned. */
++#define APE1_LIMIT_ALIGNMENT 0xFFFF
++
+ static bool set_cache_memory_policy_vi(struct device_queue_manager *dqm,
+ struct qcm_process_device *qpd,
+ enum cache_policy default_policy,
+@@ -85,6 +93,36 @@ static bool set_cache_memory_policy_vi(struct device_queue_manager *dqm,
+ {
+ uint32_t default_mtype;
+ uint32_t ape1_mtype;
++ unsigned int temp;
++ bool retval = true;
++
++ if (alternate_aperture_size == 0) {
++ /* base > limit disables APE1 */
++ qpd->sh_mem_ape1_base = 1;
++ qpd->sh_mem_ape1_limit = 0;
++ } else {
++ /*
++ * In FSA64, APE1_Base[63:0] = { 16{SH_MEM_APE1_BASE[31]},
++ * SH_MEM_APE1_BASE[31:0], 0x0000 }
++ * APE1_Limit[63:0] = { 16{SH_MEM_APE1_LIMIT[31]},
++ * SH_MEM_APE1_LIMIT[31:0], 0xFFFF }
++ * Verify that the base and size parameters can be
++ * represented in this format and convert them.
++ * Additionally restrict APE1 to user-mode addresses.
++ */
++
++ uint64_t base = (uintptr_t)alternate_aperture_base;
++ uint64_t limit = base + alternate_aperture_size - 1;
++
++ if (limit <= base || (base & APE1_FIXED_BITS_MASK) != 0 ||
++ (limit & APE1_FIXED_BITS_MASK) != APE1_LIMIT_ALIGNMENT) {
++ retval = false;
++ goto out;
++ }
++
++ qpd->sh_mem_ape1_base = base >> 16;
++ qpd->sh_mem_ape1_limit = limit >> 16;
++ }
+
+ default_mtype = (default_policy == cache_policy_coherent) ?
+ MTYPE_UC :
+@@ -100,40 +138,21 @@ static bool set_cache_memory_policy_vi(struct device_queue_manager *dqm,
+ default_mtype << SH_MEM_CONFIG__DEFAULT_MTYPE__SHIFT |
+ ape1_mtype << SH_MEM_CONFIG__APE1_MTYPE__SHIFT;
+
+- return true;
+-}
+-
+-static int update_qpd_vi(struct device_queue_manager *dqm,
+- struct qcm_process_device *qpd)
+-{
+- struct kfd_process_device *pdd;
+- unsigned int temp;
+-
+- pdd = qpd_to_pdd(qpd);
+-
+- /* check if sh_mem_config register already configured */
+- if (qpd->sh_mem_config == 0) {
+- qpd->sh_mem_config =
+- SH_MEM_ALIGNMENT_MODE_UNALIGNED <<
+- SH_MEM_CONFIG__ALIGNMENT_MODE__SHIFT |
+- MTYPE_UC <<
+- SH_MEM_CONFIG__DEFAULT_MTYPE__SHIFT |
+- MTYPE_UC <<
+- SH_MEM_CONFIG__APE1_MTYPE__SHIFT;
+-
+- qpd->sh_mem_ape1_limit = 0;
+- qpd->sh_mem_ape1_base = 0;
+- }
+-
+ /* On dGPU we're always in GPUVM64 addressing mode with 64-bit
+ * aperture addresses.
+ */
+- temp = get_sh_mem_bases_nybble_64(pdd);
++ temp = get_sh_mem_bases_nybble_64(qpd_to_pdd(qpd));
+ qpd->sh_mem_bases = compute_sh_mem_bases_64bit(temp);
+
+ pr_debug("sh_mem_bases nybble: 0x%X and register 0x%X\n",
+ temp, qpd->sh_mem_bases);
++out:
++ return retval;
++}
+
++static int update_qpd_vi(struct device_queue_manager *dqm,
++ struct qcm_process_device *qpd)
++{
+ return 0;
+ }
+
+--
+2.39.5
+
--- /dev/null
+From 2ff1b7d41b89eda2c25989a2ab219bb1bc2442c5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 14 Jan 2025 14:13:35 -0500
+Subject: drm/amdkfd: Set per-process flags only once for gfx9/10/11/12
+
+From: Harish Kasiviswanathan <Harish.Kasiviswanathan@amd.com>
+
+[ Upstream commit 61972cd93af70738a6ad7f93e17cc7f68a01e182 ]
+
+Define set_cache_memory_policy() for these asics and move all static
+changes from update_qpd() which is called each time a queue is created
+to set_cache_memory_policy() which is called once during process
+initialization
+
+Signed-off-by: Harish Kasiviswanathan <Harish.Kasiviswanathan@amd.com>
+Reviewed-by: Amber Lin <Amber.Lin@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../amd/amdkfd/kfd_device_queue_manager_v10.c | 41 +++++++++++--------
+ .../amd/amdkfd/kfd_device_queue_manager_v11.c | 41 +++++++++++--------
+ .../amd/amdkfd/kfd_device_queue_manager_v12.c | 41 +++++++++++--------
+ .../amd/amdkfd/kfd_device_queue_manager_v9.c | 36 +++++++++++++++-
+ 4 files changed, 107 insertions(+), 52 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v10.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v10.c
+index 245a90dfc2f6b..b5f5f141353b5 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v10.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v10.c
+@@ -31,10 +31,17 @@ static int update_qpd_v10(struct device_queue_manager *dqm,
+ struct qcm_process_device *qpd);
+ static void init_sdma_vm_v10(struct device_queue_manager *dqm, struct queue *q,
+ struct qcm_process_device *qpd);
++static bool set_cache_memory_policy_v10(struct device_queue_manager *dqm,
++ struct qcm_process_device *qpd,
++ enum cache_policy default_policy,
++ enum cache_policy alternate_policy,
++ void __user *alternate_aperture_base,
++ uint64_t alternate_aperture_size);
+
+ void device_queue_manager_init_v10(
+ struct device_queue_manager_asic_ops *asic_ops)
+ {
++ asic_ops->set_cache_memory_policy = set_cache_memory_policy_v10;
+ asic_ops->update_qpd = update_qpd_v10;
+ asic_ops->init_sdma_vm = init_sdma_vm_v10;
+ asic_ops->mqd_manager_init = mqd_manager_init_v10;
+@@ -49,27 +56,27 @@ static uint32_t compute_sh_mem_bases_64bit(struct kfd_process_device *pdd)
+ private_base;
+ }
+
+-static int update_qpd_v10(struct device_queue_manager *dqm,
+- struct qcm_process_device *qpd)
++static bool set_cache_memory_policy_v10(struct device_queue_manager *dqm,
++ struct qcm_process_device *qpd,
++ enum cache_policy default_policy,
++ enum cache_policy alternate_policy,
++ void __user *alternate_aperture_base,
++ uint64_t alternate_aperture_size)
+ {
+- struct kfd_process_device *pdd;
+-
+- pdd = qpd_to_pdd(qpd);
+-
+- /* check if sh_mem_config register already configured */
+- if (qpd->sh_mem_config == 0) {
+- qpd->sh_mem_config =
+- (SH_MEM_ALIGNMENT_MODE_UNALIGNED <<
+- SH_MEM_CONFIG__ALIGNMENT_MODE__SHIFT) |
+- (3 << SH_MEM_CONFIG__INITIAL_INST_PREFETCH__SHIFT);
+- qpd->sh_mem_ape1_limit = 0;
+- qpd->sh_mem_ape1_base = 0;
+- }
+-
+- qpd->sh_mem_bases = compute_sh_mem_bases_64bit(pdd);
++ qpd->sh_mem_config = (SH_MEM_ALIGNMENT_MODE_UNALIGNED <<
++ SH_MEM_CONFIG__ALIGNMENT_MODE__SHIFT) |
++ (3 << SH_MEM_CONFIG__INITIAL_INST_PREFETCH__SHIFT);
++ qpd->sh_mem_ape1_limit = 0;
++ qpd->sh_mem_ape1_base = 0;
++ qpd->sh_mem_bases = compute_sh_mem_bases_64bit(qpd_to_pdd(qpd));
+
+ pr_debug("sh_mem_bases 0x%X\n", qpd->sh_mem_bases);
++ return true;
++}
+
++static int update_qpd_v10(struct device_queue_manager *dqm,
++ struct qcm_process_device *qpd)
++{
+ return 0;
+ }
+
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v11.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v11.c
+index 2e129da7acb43..f436878d0d621 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v11.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v11.c
+@@ -30,10 +30,17 @@ static int update_qpd_v11(struct device_queue_manager *dqm,
+ struct qcm_process_device *qpd);
+ static void init_sdma_vm_v11(struct device_queue_manager *dqm, struct queue *q,
+ struct qcm_process_device *qpd);
++static bool set_cache_memory_policy_v11(struct device_queue_manager *dqm,
++ struct qcm_process_device *qpd,
++ enum cache_policy default_policy,
++ enum cache_policy alternate_policy,
++ void __user *alternate_aperture_base,
++ uint64_t alternate_aperture_size);
+
+ void device_queue_manager_init_v11(
+ struct device_queue_manager_asic_ops *asic_ops)
+ {
++ asic_ops->set_cache_memory_policy = set_cache_memory_policy_v11;
+ asic_ops->update_qpd = update_qpd_v11;
+ asic_ops->init_sdma_vm = init_sdma_vm_v11;
+ asic_ops->mqd_manager_init = mqd_manager_init_v11;
+@@ -48,28 +55,28 @@ static uint32_t compute_sh_mem_bases_64bit(struct kfd_process_device *pdd)
+ private_base;
+ }
+
+-static int update_qpd_v11(struct device_queue_manager *dqm,
+- struct qcm_process_device *qpd)
++static bool set_cache_memory_policy_v11(struct device_queue_manager *dqm,
++ struct qcm_process_device *qpd,
++ enum cache_policy default_policy,
++ enum cache_policy alternate_policy,
++ void __user *alternate_aperture_base,
++ uint64_t alternate_aperture_size)
+ {
+- struct kfd_process_device *pdd;
+-
+- pdd = qpd_to_pdd(qpd);
+-
+- /* check if sh_mem_config register already configured */
+- if (qpd->sh_mem_config == 0) {
+- qpd->sh_mem_config =
+- (SH_MEM_ALIGNMENT_MODE_UNALIGNED <<
+- SH_MEM_CONFIG__ALIGNMENT_MODE__SHIFT) |
+- (3 << SH_MEM_CONFIG__INITIAL_INST_PREFETCH__SHIFT);
+-
+- qpd->sh_mem_ape1_limit = 0;
+- qpd->sh_mem_ape1_base = 0;
+- }
++ qpd->sh_mem_config = (SH_MEM_ALIGNMENT_MODE_UNALIGNED <<
++ SH_MEM_CONFIG__ALIGNMENT_MODE__SHIFT) |
++ (3 << SH_MEM_CONFIG__INITIAL_INST_PREFETCH__SHIFT);
+
+- qpd->sh_mem_bases = compute_sh_mem_bases_64bit(pdd);
++ qpd->sh_mem_ape1_limit = 0;
++ qpd->sh_mem_ape1_base = 0;
++ qpd->sh_mem_bases = compute_sh_mem_bases_64bit(qpd_to_pdd(qpd));
+
+ pr_debug("sh_mem_bases 0x%X\n", qpd->sh_mem_bases);
++ return true;
++}
+
++static int update_qpd_v11(struct device_queue_manager *dqm,
++ struct qcm_process_device *qpd)
++{
+ return 0;
+ }
+
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v12.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v12.c
+index 4f3295b29dfb1..62ca1c8fcbaf9 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v12.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v12.c
+@@ -30,10 +30,17 @@ static int update_qpd_v12(struct device_queue_manager *dqm,
+ struct qcm_process_device *qpd);
+ static void init_sdma_vm_v12(struct device_queue_manager *dqm, struct queue *q,
+ struct qcm_process_device *qpd);
++static bool set_cache_memory_policy_v12(struct device_queue_manager *dqm,
++ struct qcm_process_device *qpd,
++ enum cache_policy default_policy,
++ enum cache_policy alternate_policy,
++ void __user *alternate_aperture_base,
++ uint64_t alternate_aperture_size);
+
+ void device_queue_manager_init_v12(
+ struct device_queue_manager_asic_ops *asic_ops)
+ {
++ asic_ops->set_cache_memory_policy = set_cache_memory_policy_v12;
+ asic_ops->update_qpd = update_qpd_v12;
+ asic_ops->init_sdma_vm = init_sdma_vm_v12;
+ asic_ops->mqd_manager_init = mqd_manager_init_v12;
+@@ -48,28 +55,28 @@ static uint32_t compute_sh_mem_bases_64bit(struct kfd_process_device *pdd)
+ private_base;
+ }
+
+-static int update_qpd_v12(struct device_queue_manager *dqm,
+- struct qcm_process_device *qpd)
++static bool set_cache_memory_policy_v12(struct device_queue_manager *dqm,
++ struct qcm_process_device *qpd,
++ enum cache_policy default_policy,
++ enum cache_policy alternate_policy,
++ void __user *alternate_aperture_base,
++ uint64_t alternate_aperture_size)
+ {
+- struct kfd_process_device *pdd;
+-
+- pdd = qpd_to_pdd(qpd);
+-
+- /* check if sh_mem_config register already configured */
+- if (qpd->sh_mem_config == 0) {
+- qpd->sh_mem_config =
+- (SH_MEM_ALIGNMENT_MODE_UNALIGNED <<
+- SH_MEM_CONFIG__ALIGNMENT_MODE__SHIFT) |
+- (3 << SH_MEM_CONFIG__INITIAL_INST_PREFETCH__SHIFT);
+-
+- qpd->sh_mem_ape1_limit = 0;
+- qpd->sh_mem_ape1_base = 0;
+- }
++ qpd->sh_mem_config = (SH_MEM_ALIGNMENT_MODE_UNALIGNED <<
++ SH_MEM_CONFIG__ALIGNMENT_MODE__SHIFT) |
++ (3 << SH_MEM_CONFIG__INITIAL_INST_PREFETCH__SHIFT);
+
+- qpd->sh_mem_bases = compute_sh_mem_bases_64bit(pdd);
++ qpd->sh_mem_ape1_limit = 0;
++ qpd->sh_mem_ape1_base = 0;
++ qpd->sh_mem_bases = compute_sh_mem_bases_64bit(qpd_to_pdd(qpd));
+
+ pr_debug("sh_mem_bases 0x%X\n", qpd->sh_mem_bases);
++ return true;
++}
+
++static int update_qpd_v12(struct device_queue_manager *dqm,
++ struct qcm_process_device *qpd)
++{
+ return 0;
+ }
+
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v9.c
+index 67137e674f1d0..c734eb9b505f8 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v9.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v9.c
+@@ -30,10 +30,17 @@ static int update_qpd_v9(struct device_queue_manager *dqm,
+ struct qcm_process_device *qpd);
+ static void init_sdma_vm_v9(struct device_queue_manager *dqm, struct queue *q,
+ struct qcm_process_device *qpd);
++static bool set_cache_memory_policy_v9(struct device_queue_manager *dqm,
++ struct qcm_process_device *qpd,
++ enum cache_policy default_policy,
++ enum cache_policy alternate_policy,
++ void __user *alternate_aperture_base,
++ uint64_t alternate_aperture_size);
+
+ void device_queue_manager_init_v9(
+ struct device_queue_manager_asic_ops *asic_ops)
+ {
++ asic_ops->set_cache_memory_policy = set_cache_memory_policy_v9;
+ asic_ops->update_qpd = update_qpd_v9;
+ asic_ops->init_sdma_vm = init_sdma_vm_v9;
+ asic_ops->mqd_manager_init = mqd_manager_init_v9;
+@@ -48,10 +55,37 @@ static uint32_t compute_sh_mem_bases_64bit(struct kfd_process_device *pdd)
+ private_base;
+ }
+
++static bool set_cache_memory_policy_v9(struct device_queue_manager *dqm,
++ struct qcm_process_device *qpd,
++ enum cache_policy default_policy,
++ enum cache_policy alternate_policy,
++ void __user *alternate_aperture_base,
++ uint64_t alternate_aperture_size)
++{
++ qpd->sh_mem_config = SH_MEM_ALIGNMENT_MODE_UNALIGNED <<
++ SH_MEM_CONFIG__ALIGNMENT_MODE__SHIFT;
++
++ if (dqm->dev->kfd->noretry)
++ qpd->sh_mem_config |= 1 << SH_MEM_CONFIG__RETRY_DISABLE__SHIFT;
++
++ if (KFD_GC_VERSION(dqm->dev->kfd) == IP_VERSION(9, 4, 3) ||
++ KFD_GC_VERSION(dqm->dev->kfd) == IP_VERSION(9, 4, 4) ||
++ KFD_GC_VERSION(dqm->dev->kfd) == IP_VERSION(9, 5, 0))
++ qpd->sh_mem_config |= (1 << SH_MEM_CONFIG__F8_MODE__SHIFT);
++
++ qpd->sh_mem_ape1_limit = 0;
++ qpd->sh_mem_ape1_base = 0;
++ qpd->sh_mem_bases = compute_sh_mem_bases_64bit(qpd_to_pdd(qpd));
++
++ pr_debug("sh_mem_bases 0x%X sh_mem_config 0x%X\n", qpd->sh_mem_bases,
++ qpd->sh_mem_config);
++ return true;
++}
++
+ static int update_qpd_v9(struct device_queue_manager *dqm,
+ struct qcm_process_device *qpd)
+ {
+- struct kfd_process_device *pdd;
++ struct kfd_process_device *pdd = qpd_to_pdd(qpd);
+
+ pdd = qpd_to_pdd(qpd);
+
+--
+2.39.5
+
--- /dev/null
+From 5f19b373457860f7e5e81622b80438efbfd70e4c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 14 Mar 2025 11:08:21 -0400
+Subject: drm/amdkfd: set precise mem ops caps to disabled for gfx 11 and 12
+
+From: Jonathan Kim <jonathan.kim@amd.com>
+
+[ Upstream commit f82d27dcff939d3cbecbc60e1b71e2518c37e81d ]
+
+Clause instructions with precise memory enabled currently hang the
+shader so set capabilities flag to disabled since it's unsafe to use
+for debugging.
+
+Signed-off-by: Jonathan Kim <jonathan.kim@amd.com>
+Tested-by: Lancelot Six <lancelot.six@amd.com>
+Reviewed-by: Harish Kasiviswanathan <harish.kasiviswanathan@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdkfd/kfd_topology.c | 4 ----
+ 1 file changed, 4 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
+index 62a9a9ccf9bb6..334c576a75b14 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
+@@ -2006,10 +2006,6 @@ static void kfd_topology_set_capabilities(struct kfd_topology_device *dev)
+ dev->node_props.debug_prop |= HSA_DBG_WATCH_ADDR_MASK_LO_BIT_GFX10 |
+ HSA_DBG_WATCH_ADDR_MASK_HI_BIT;
+
+- if (KFD_GC_VERSION(dev->gpu) >= IP_VERSION(11, 0, 0))
+- dev->node_props.capability |=
+- HSA_CAP_TRAP_DEBUG_PRECISE_MEMORY_OPERATIONS_SUPPORTED;
+-
+ if (KFD_GC_VERSION(dev->gpu) >= IP_VERSION(12, 0, 0))
+ dev->node_props.capability |=
+ HSA_CAP_TRAP_DEBUG_PRECISE_ALU_OPERATIONS_SUPPORTED;
+--
+2.39.5
+
--- /dev/null
+From 75f0b2f9250b97d8b6cf310c79a58e27831ea4ba Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jan 2025 10:21:08 +0100
+Subject: drm/ast: Find VBIOS mode from regular display size
+
+From: Thomas Zimmermann <tzimmermann@suse.de>
+
+[ Upstream commit c81202906b5cd56db403e95db3d29c9dfc8c74c1 ]
+
+The ast driver looks up supplied display modes from an internal list of
+display modes supported by the VBIOS.
+
+Do not use the crtc_-prefixed display values from struct drm_display_mode
+for looking up the VBIOS mode. The fields contain raw values that the
+driver programs to hardware. They are affected by display settings like
+double-scan or interlace.
+
+Instead use the regular vdisplay and hdisplay fields for lookup. As the
+programmed values can now differ from the values used for lookup, set
+struct drm_display_mode.crtc_vdisplay and .crtc_hdisplay from the VBIOS
+mode.
+
+Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
+Reviewed-by: Jocelyn Falempe <jfalempe@redhat.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250131092257.115596-9-tzimmermann@suse.de
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/ast/ast_mode.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
+index 9d5321c81e68d..a29fe1ae803f1 100644
+--- a/drivers/gpu/drm/ast/ast_mode.c
++++ b/drivers/gpu/drm/ast/ast_mode.c
+@@ -131,7 +131,7 @@ static bool ast_get_vbios_mode_info(const struct drm_format_info *format,
+ return false;
+ }
+
+- switch (mode->crtc_hdisplay) {
++ switch (mode->hdisplay) {
+ case 640:
+ vbios_mode->enh_table = &res_640x480[refresh_rate_index];
+ break;
+@@ -145,7 +145,7 @@ static bool ast_get_vbios_mode_info(const struct drm_format_info *format,
+ vbios_mode->enh_table = &res_1152x864[refresh_rate_index];
+ break;
+ case 1280:
+- if (mode->crtc_vdisplay == 800)
++ if (mode->vdisplay == 800)
+ vbios_mode->enh_table = &res_1280x800[refresh_rate_index];
+ else
+ vbios_mode->enh_table = &res_1280x1024[refresh_rate_index];
+@@ -157,7 +157,7 @@ static bool ast_get_vbios_mode_info(const struct drm_format_info *format,
+ vbios_mode->enh_table = &res_1440x900[refresh_rate_index];
+ break;
+ case 1600:
+- if (mode->crtc_vdisplay == 900)
++ if (mode->vdisplay == 900)
+ vbios_mode->enh_table = &res_1600x900[refresh_rate_index];
+ else
+ vbios_mode->enh_table = &res_1600x1200[refresh_rate_index];
+@@ -166,7 +166,7 @@ static bool ast_get_vbios_mode_info(const struct drm_format_info *format,
+ vbios_mode->enh_table = &res_1680x1050[refresh_rate_index];
+ break;
+ case 1920:
+- if (mode->crtc_vdisplay == 1080)
++ if (mode->vdisplay == 1080)
+ vbios_mode->enh_table = &res_1920x1080[refresh_rate_index];
+ else
+ vbios_mode->enh_table = &res_1920x1200[refresh_rate_index];
+@@ -210,6 +210,7 @@ static bool ast_get_vbios_mode_info(const struct drm_format_info *format,
+ hborder = (vbios_mode->enh_table->flags & HBorder) ? 8 : 0;
+ vborder = (vbios_mode->enh_table->flags & VBorder) ? 8 : 0;
+
++ adjusted_mode->crtc_hdisplay = vbios_mode->enh_table->hde;
+ adjusted_mode->crtc_htotal = vbios_mode->enh_table->ht;
+ adjusted_mode->crtc_hblank_start = vbios_mode->enh_table->hde + hborder;
+ adjusted_mode->crtc_hblank_end = vbios_mode->enh_table->ht - hborder;
+@@ -219,6 +220,7 @@ static bool ast_get_vbios_mode_info(const struct drm_format_info *format,
+ vbios_mode->enh_table->hfp +
+ vbios_mode->enh_table->hsync);
+
++ adjusted_mode->crtc_vdisplay = vbios_mode->enh_table->vde;
+ adjusted_mode->crtc_vtotal = vbios_mode->enh_table->vt;
+ adjusted_mode->crtc_vblank_start = vbios_mode->enh_table->vde + vborder;
+ adjusted_mode->crtc_vblank_end = vbios_mode->enh_table->vt - vborder;
+--
+2.39.5
+
--- /dev/null
+From 67fddc6a086ae46b2e41e9781b5ac77c6c149ecf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 17 Jan 2025 11:29:10 +0100
+Subject: drm/ast: Hide Gens 1 to 3 TX detection in branch
+
+From: Thomas Zimmermann <tzimmermann@suse.de>
+
+[ Upstream commit 87478ba50a05a1f44508316ae109622e8a85adc9 ]
+
+Gen7 only supports ASTDP. Gens 4 to 6 support various TX chips,
+except ASTDP. These boards detect the TX chips by reading the SoC
+scratch register as VGACRD1.
+
+Gens 1 to 3 only support SIL164. These boards read the DVO bit from
+VGACRA3. Hence move this test behind a branch, so that it does not
+run on later generations.
+
+Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
+Reviewed-by: Jocelyn Falempe <jfalempe@redhat.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250117103450.28692-6-tzimmermann@suse.de
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/ast/ast_main.c | 30 +++++++++++++++---------------
+ 1 file changed, 15 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c
+index bc37c65305d48..96470fc8e6e53 100644
+--- a/drivers/gpu/drm/ast/ast_main.c
++++ b/drivers/gpu/drm/ast/ast_main.c
+@@ -96,21 +96,21 @@ static void ast_detect_tx_chip(struct ast_device *ast, bool need_post)
+ /* Check 3rd Tx option (digital output afaik) */
+ ast->tx_chip = AST_TX_NONE;
+
+- /*
+- * VGACRA3 Enhanced Color Mode Register, check if DVO is already
+- * enabled, in that case, assume we have a SIL164 TMDS transmitter
+- *
+- * Don't make that assumption if we the chip wasn't enabled and
+- * is at power-on reset, otherwise we'll incorrectly "detect" a
+- * SIL164 when there is none.
+- */
+- if (!need_post) {
+- jreg = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xa3, 0xff);
+- if (jreg & 0x80)
+- ast->tx_chip = AST_TX_SIL164;
+- }
+-
+- if (IS_AST_GEN4(ast) || IS_AST_GEN5(ast) || IS_AST_GEN6(ast)) {
++ if (AST_GEN(ast) <= 3) {
++ /*
++ * VGACRA3 Enhanced Color Mode Register, check if DVO is already
++ * enabled, in that case, assume we have a SIL164 TMDS transmitter
++ *
++ * Don't make that assumption if we the chip wasn't enabled and
++ * is at power-on reset, otherwise we'll incorrectly "detect" a
++ * SIL164 when there is none.
++ */
++ if (!need_post) {
++ jreg = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xa3, 0xff);
++ if (jreg & 0x80)
++ ast->tx_chip = AST_TX_SIL164;
++ }
++ } else if (IS_AST_GEN4(ast) || IS_AST_GEN5(ast) || IS_AST_GEN6(ast)) {
+ /*
+ * On AST GEN4+, look the configuration set by the SoC in
+ * the SOC scratch register #1 bits 11:8 (interestingly marked
+--
+2.39.5
+
--- /dev/null
+From f12960ca80edca8d16feb03b0a730bca0e5d9fe8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 8 Jan 2025 18:24:16 +0100
+Subject: drm/atomic: clarify the rules around drm_atomic_state->allow_modeset
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Simona Vetter <simona.vetter@ffwll.ch>
+
+[ Upstream commit c5e3306a424b52e38ad2c28c7f3399fcd03e383d ]
+
+msm is automagically upgrading normal commits to full modesets, and
+that's a big no-no:
+
+- for one this results in full on->off->on transitions on all these
+ crtc, at least if you're using the usual helpers. Which seems to be
+ the case, and is breaking uapi
+
+- further even if the ctm change itself would not result in flicker,
+ this can hide modesets for other reasons. Which again breaks the
+ uapi
+
+v2: I forgot the case of adding unrelated crtc state. Add that case
+and link to the existing kerneldoc explainers. This has come up in an
+irc discussion with Manasi and Ville about intel's bigjoiner mode.
+Also cc everyone involved in the msm irc discussion, more people
+joined after I sent out v1.
+
+v3: Wording polish from Pekka and Thomas
+
+Acked-by: Pekka Paalanen <pekka.paalanen@collabora.com>
+Acked-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
+Cc: Maxime Ripard <mripard@kernel.org>
+Cc: Thomas Zimmermann <tzimmermann@suse.de>
+Cc: David Airlie <airlied@gmail.com>
+Cc: Daniel Vetter <daniel@ffwll.ch>
+Cc: Pekka Paalanen <pekka.paalanen@collabora.com>
+Cc: Rob Clark <robdclark@gmail.com>
+Cc: Simon Ser <contact@emersion.fr>
+Cc: Manasi Navare <navaremanasi@google.com>
+Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
+Cc: Abhinav Kumar <quic_abhinavk@quicinc.com>
+Cc: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Signed-off-by: Simona Vetter <simona.vetter@intel.com>
+Signed-off-by: Simona Vetter <simona.vetter@ffwll.ch>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250108172417.160831-1-simona.vetter@ffwll.ch
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/drm/drm_atomic.h | 23 +++++++++++++++++++++--
+ 1 file changed, 21 insertions(+), 2 deletions(-)
+
+diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
+index 31ca88deb10d2..1ded9a8d4e84d 100644
+--- a/include/drm/drm_atomic.h
++++ b/include/drm/drm_atomic.h
+@@ -376,8 +376,27 @@ struct drm_atomic_state {
+ *
+ * Allow full modeset. This is used by the ATOMIC IOCTL handler to
+ * implement the DRM_MODE_ATOMIC_ALLOW_MODESET flag. Drivers should
+- * never consult this flag, instead looking at the output of
+- * drm_atomic_crtc_needs_modeset().
++ * generally not consult this flag, but instead look at the output of
++ * drm_atomic_crtc_needs_modeset(). The detailed rules are:
++ *
++ * - Drivers must not consult @allow_modeset in the atomic commit path.
++ * Use drm_atomic_crtc_needs_modeset() instead.
++ *
++ * - Drivers must consult @allow_modeset before adding unrelated struct
++ * drm_crtc_state to this commit by calling
++ * drm_atomic_get_crtc_state(). See also the warning in the
++ * documentation for that function.
++ *
++ * - Drivers must never change this flag, it is under the exclusive
++ * control of userspace.
++ *
++ * - Drivers may consult @allow_modeset in the atomic check path, if
++ * they have the choice between an optimal hardware configuration
++ * which requires a modeset, and a less optimal configuration which
++ * can be committed without a modeset. An example would be suboptimal
++ * scanout FIFO allocation resulting in increased idle power
++ * consumption. This allows userspace to avoid flickering and delays
++ * for the normal composition loop at reasonable cost.
+ */
+ bool allow_modeset : 1;
+ /**
+--
+2.39.5
+
--- /dev/null
+From 67530350b444b0eaa136cb251796dca5b33b2441 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 8 Jan 2025 18:03:54 +0100
+Subject: drm: bridge: adv7511: fill stream capabilities
+
+From: Olivier Moysan <olivier.moysan@foss.st.com>
+
+[ Upstream commit c852646f12d4cd5b4f19eeec2976c5d98c0382f8 ]
+
+Set no_i2s_capture and no_spdif_capture flags in hdmi_codec_pdata structure
+to report that the ADV7511 HDMI bridge does not support i2s or spdif audio
+capture.
+
+Signed-off-by: Olivier Moysan <olivier.moysan@foss.st.com>
+Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250108170356.413063-2-olivier.moysan@foss.st.com
+Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/bridge/adv7511/adv7511_audio.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c b/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c
+index 657bc3dd18dff..98030500a978a 100644
+--- a/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c
++++ b/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c
+@@ -245,7 +245,9 @@ static const struct hdmi_codec_pdata codec_data = {
+ .ops = &adv7511_codec_ops,
+ .max_i2s_channels = 2,
+ .i2s = 1,
++ .no_i2s_capture = 1,
+ .spdif = 1,
++ .no_spdif_capture = 1,
+ };
+
+ int adv7511_audio_init(struct device *dev, struct adv7511 *adv7511)
+--
+2.39.5
+
--- /dev/null
+From 9a56e6e6ee79461fa282390635ba670309395d43 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Dec 2024 12:31:15 +0530
+Subject: drm/buddy: fix issue that force_merge cannot free all roots
+
+From: Lin.Cao <lincao12@amd.com>
+
+[ Upstream commit 467dce3817bd2b62ccd6fcfd7aae76f242ac907e ]
+
+If buddy manager have more than one roots and each root have sub-block
+need to be free. When drm_buddy_fini called, the first loop of
+force_merge will merge and free all of the sub block of first root,
+which offset is 0x0 and size is biggest(more than have of the mm size).
+In subsequent force_merge rounds, if we use 0 as start and use remaining
+mm size as end, the block of other roots will be skipped in
+__force_merge function. It will cause the other roots can not be freed.
+
+Solution: use roots' offset as the start could fix this issue.
+
+Signed-off-by: Lin.Cao <lincao12@amd.com>
+Signed-off-by: Arunpravin Paneer Selvam <Arunpravin.PaneerSelvam@amd.com>
+Reviewed-by: Matthew Auld <matthew.auld@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20241226070116.309290-1-Arunpravin.PaneerSelvam@amd.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/drm_buddy.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/drm_buddy.c b/drivers/gpu/drm/drm_buddy.c
+index 103c185bb1c8a..ca42e6081d27c 100644
+--- a/drivers/gpu/drm/drm_buddy.c
++++ b/drivers/gpu/drm/drm_buddy.c
+@@ -324,7 +324,7 @@ EXPORT_SYMBOL(drm_buddy_init);
+ */
+ void drm_buddy_fini(struct drm_buddy *mm)
+ {
+- u64 root_size, size;
++ u64 root_size, size, start;
+ unsigned int order;
+ int i;
+
+@@ -332,7 +332,8 @@ void drm_buddy_fini(struct drm_buddy *mm)
+
+ for (i = 0; i < mm->n_roots; ++i) {
+ order = ilog2(size) - ilog2(mm->chunk_size);
+- __force_merge(mm, 0, size, order);
++ start = drm_buddy_block_offset(mm->roots[i]);
++ __force_merge(mm, start, start + size, order);
+
+ WARN_ON(!drm_buddy_block_is_free(mm->roots[i]));
+ drm_block_free(mm, mm->roots[i]);
+--
+2.39.5
+
--- /dev/null
+From 8ba4876ebde31841371db11d560790e4ebff00a9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 16 Apr 2025 08:57:45 +0200
+Subject: drm/gem: Internally test import_attach for imported objects
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Thomas Zimmermann <tzimmermann@suse.de>
+
+[ Upstream commit 8260731ccad0451207b45844bb66eb161a209218 ]
+
+Test struct drm_gem_object.import_attach to detect imported objects.
+
+During object clenanup, the dma_buf field might be NULL. Testing it in
+an object's free callback then incorrectly does a cleanup as for native
+objects. Happens for calls to drm_mode_destroy_dumb_ioctl() that
+clears the dma_buf field in drm_gem_object_exported_dma_buf_free().
+
+v3:
+- only test for import_attach (Boris)
+v2:
+- use import_attach.dmabuf instead of dma_buf (Christian)
+
+Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
+Fixes: b57aa47d39e9 ("drm/gem: Test for imported GEM buffers with helper")
+Reported-by: Andy Yan <andyshrk@163.com>
+Closes: https://lore.kernel.org/dri-devel/38d09d34.4354.196379aa560.Coremail.andyshrk@163.com/
+Tested-by: Andy Yan <andyshrk@163.com>
+Cc: Thomas Zimmermann <tzimmermann@suse.de>
+Cc: Anusha Srivatsa <asrivats@redhat.com>
+Cc: Christian König <christian.koenig@amd.com>
+Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
+Cc: Maxime Ripard <mripard@kernel.org>
+Cc: David Airlie <airlied@gmail.com>
+Cc: Simona Vetter <simona@ffwll.ch>
+Cc: Sumit Semwal <sumit.semwal@linaro.org>
+Cc: "Christian König" <christian.koenig@amd.com>
+Cc: dri-devel@lists.freedesktop.org
+Cc: linux-media@vger.kernel.org
+Cc: linaro-mm-sig@lists.linaro.org
+Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
+Reviewed-by: Simona Vetter <simona.vetter@ffwll.ch>
+Link: https://lore.kernel.org/r/20250416065820.26076-1-tzimmermann@suse.de
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/drm/drm_gem.h | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
+index 2bf893eabb4b2..bcd54020d6ba5 100644
+--- a/include/drm/drm_gem.h
++++ b/include/drm/drm_gem.h
+@@ -585,8 +585,7 @@ static inline bool drm_gem_object_is_shared_for_memory_stats(struct drm_gem_obje
+ */
+ static inline bool drm_gem_is_imported(const struct drm_gem_object *obj)
+ {
+- /* The dma-buf's priv field points to the original GEM object. */
+- return obj->dma_buf && (obj->dma_buf->priv != obj);
++ return !!obj->import_attach;
+ }
+
+ #ifdef CONFIG_LOCKDEP
+--
+2.39.5
+
--- /dev/null
+From 9da09a08236b463703d0fb65495027a3a1cd0c1d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Feb 2025 18:03:04 +0100
+Subject: drm/gem: Test for imported GEM buffers with helper
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Thomas Zimmermann <tzimmermann@suse.de>
+
+[ Upstream commit b57aa47d39e94dc47403a745e2024664e544078c ]
+
+Add drm_gem_is_imported() that tests if a GEM object's buffer has
+been imported. Update the GEM code accordingly.
+
+GEM code usually tests for imports if import_attach has been set
+in struct drm_gem_object. But attaching a dma-buf on import requires
+a DMA-capable importer device, which is not the case for many serial
+busses like USB or I2C. The new helper tests if a GEM object's dma-buf
+has been created from the GEM object.
+
+Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
+Reviewed-by: Anusha Srivatsa <asrivats@redhat.com>
+Reviewed-by: Christian König <christian.koenig@amd.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250226172457.217725-2-tzimmermann@suse.de
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/drm_gem.c | 4 ++--
+ include/drm/drm_gem.h | 14 ++++++++++++++
+ 2 files changed, 16 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
+index ee811764c3df4..c6240bab3fa55 100644
+--- a/drivers/gpu/drm/drm_gem.c
++++ b/drivers/gpu/drm/drm_gem.c
+@@ -348,7 +348,7 @@ int drm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev,
+ return -ENOENT;
+
+ /* Don't allow imported objects to be mapped */
+- if (obj->import_attach) {
++ if (drm_gem_is_imported(obj)) {
+ ret = -EINVAL;
+ goto out;
+ }
+@@ -1178,7 +1178,7 @@ void drm_gem_print_info(struct drm_printer *p, unsigned int indent,
+ drm_vma_node_start(&obj->vma_node));
+ drm_printf_indent(p, indent, "size=%zu\n", obj->size);
+ drm_printf_indent(p, indent, "imported=%s\n",
+- str_yes_no(obj->import_attach));
++ str_yes_no(drm_gem_is_imported(obj)));
+
+ if (obj->funcs->print_info)
+ obj->funcs->print_info(p, indent, obj);
+diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
+index fdae947682cd0..2bf893eabb4b2 100644
+--- a/include/drm/drm_gem.h
++++ b/include/drm/drm_gem.h
+@@ -35,6 +35,7 @@
+ */
+
+ #include <linux/kref.h>
++#include <linux/dma-buf.h>
+ #include <linux/dma-resv.h>
+ #include <linux/list.h>
+ #include <linux/mutex.h>
+@@ -575,6 +576,19 @@ static inline bool drm_gem_object_is_shared_for_memory_stats(struct drm_gem_obje
+ return (obj->handle_count > 1) || obj->dma_buf;
+ }
+
++/**
++ * drm_gem_is_imported() - Tests if GEM object's buffer has been imported
++ * @obj: the GEM object
++ *
++ * Returns:
++ * True if the GEM object's buffer has been imported, false otherwise
++ */
++static inline bool drm_gem_is_imported(const struct drm_gem_object *obj)
++{
++ /* The dma-buf's priv field points to the original GEM object. */
++ return obj->dma_buf && (obj->dma_buf->priv != obj);
++}
++
+ #ifdef CONFIG_LOCKDEP
+ /**
+ * drm_gem_gpuva_set_lock() - Set the lock protecting accesses to the gpuva list.
+--
+2.39.5
+
--- /dev/null
+From 1720c79de16a5102e62e58abcda52055efd73de4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 17 Feb 2025 16:47:58 +0100
+Subject: drm/mediatek: mtk_dpi: Add checks for reg_h_fre_con existence
+
+From: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+
+[ Upstream commit 8c9da7cd0bbcc90ab444454fecf535320456a312 ]
+
+In preparation for adding support for newer DPI instances which
+do support direct-pin but do not have any H_FRE_CON register,
+like the one found in MT8195 and MT8188, add a branch to check
+if the reg_h_fre_con variable was declared in the mtk_dpi_conf
+structure for the probed SoC DPI version.
+
+As a note, this is useful specifically only for cases in which
+the support_direct_pin variable is true, so mt8195-dpintf is
+not affected by any issue.
+
+Reviewed-by: CK Hu <ck.hu@mediatek.com>
+Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://patchwork.kernel.org/project/dri-devel/patch/20250217154836.108895-6-angelogioacchino.delregno@collabora.com/
+Signed-off-by: Chun-Kuang Hu <chunkuang.hu@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/mediatek/mtk_dpi.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
+index a12ef24c77423..b7d90574df9a6 100644
+--- a/drivers/gpu/drm/mediatek/mtk_dpi.c
++++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
+@@ -410,12 +410,13 @@ static void mtk_dpi_config_swap_input(struct mtk_dpi *dpi, bool enable)
+
+ static void mtk_dpi_config_2n_h_fre(struct mtk_dpi *dpi)
+ {
+- mtk_dpi_mask(dpi, dpi->conf->reg_h_fre_con, H_FRE_2N, H_FRE_2N);
++ if (dpi->conf->reg_h_fre_con)
++ mtk_dpi_mask(dpi, dpi->conf->reg_h_fre_con, H_FRE_2N, H_FRE_2N);
+ }
+
+ static void mtk_dpi_config_disable_edge(struct mtk_dpi *dpi)
+ {
+- if (dpi->conf->edge_sel_en)
++ if (dpi->conf->edge_sel_en && dpi->conf->reg_h_fre_con)
+ mtk_dpi_mask(dpi, dpi->conf->reg_h_fre_con, 0, EDGE_SEL_EN);
+ }
+
+--
+2.39.5
+
--- /dev/null
+From e3e634883e3792b22e08a9993c3dc792120ac468 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 14 Feb 2025 16:14:37 -0800
+Subject: drm/msm/dpu: Set possible clones for all encoders
+
+From: Jessica Zhang <quic_jesszhan@quicinc.com>
+
+[ Upstream commit e8cd8224a30798b65e05b26de284e1702b22ba5e ]
+
+Set writeback encoders as possible clones for DSI encoders and vice
+versa.
+
+Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Reviewed-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
+Signed-off-by: Jessica Zhang <quic_jesszhan@quicinc.com>
+Patchwork: https://patchwork.freedesktop.org/patch/637498/
+Link: https://lore.kernel.org/r/20250214-concurrent-wb-v6-14-a44c293cf422@quicinc.com
+Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 32 +++++++++++++++++++++
+ drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h | 2 ++
+ drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 7 +++--
+ 3 files changed, 39 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+index 7b56da24711e4..eca9c7d4ec6f5 100644
+--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+@@ -2539,6 +2539,38 @@ static int dpu_encoder_virt_add_phys_encs(
+ return 0;
+ }
+
++/**
++ * dpu_encoder_get_clones - Calculate the possible_clones for DPU encoder
++ * @drm_enc: DRM encoder pointer
++ * Returns: possible_clones mask
++ */
++uint32_t dpu_encoder_get_clones(struct drm_encoder *drm_enc)
++{
++ struct drm_encoder *curr;
++ int type = drm_enc->encoder_type;
++ uint32_t clone_mask = drm_encoder_mask(drm_enc);
++
++ /*
++ * Set writeback as possible clones of real-time DSI encoders and vice
++ * versa
++ *
++ * Writeback encoders can't be clones of each other and DSI
++ * encoders can't be clones of each other.
++ *
++ * TODO: Add DP encoders as valid possible clones for writeback encoders
++ * (and vice versa) once concurrent writeback has been validated for DP
++ */
++ drm_for_each_encoder(curr, drm_enc->dev) {
++ if ((type == DRM_MODE_ENCODER_VIRTUAL &&
++ curr->encoder_type == DRM_MODE_ENCODER_DSI) ||
++ (type == DRM_MODE_ENCODER_DSI &&
++ curr->encoder_type == DRM_MODE_ENCODER_VIRTUAL))
++ clone_mask |= drm_encoder_mask(curr);
++ }
++
++ return clone_mask;
++}
++
+ static int dpu_encoder_setup_display(struct dpu_encoder_virt *dpu_enc,
+ struct dpu_kms *dpu_kms,
+ struct msm_display_info *disp_info)
+diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
+index da133ee4701a3..751be231ee7b1 100644
+--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
+@@ -60,6 +60,8 @@ enum dpu_intf_mode dpu_encoder_get_intf_mode(struct drm_encoder *encoder);
+
+ void dpu_encoder_virt_runtime_resume(struct drm_encoder *encoder);
+
++uint32_t dpu_encoder_get_clones(struct drm_encoder *drm_enc);
++
+ struct drm_encoder *dpu_encoder_init(struct drm_device *dev,
+ int drm_enc_mode,
+ struct msm_display_info *disp_info);
+diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+index 8741dc6fc8ddc..b8f4ebba8ac28 100644
+--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+@@ -2,7 +2,7 @@
+ /*
+ * Copyright (C) 2013 Red Hat
+ * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
+- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
++ * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ *
+ * Author: Rob Clark <robdclark@gmail.com>
+ */
+@@ -834,8 +834,11 @@ static int _dpu_kms_drm_obj_init(struct dpu_kms *dpu_kms)
+ return ret;
+
+ num_encoders = 0;
+- drm_for_each_encoder(encoder, dev)
++ drm_for_each_encoder(encoder, dev) {
+ num_encoders++;
++ if (catalog->cwb_count > 0)
++ encoder->possible_clones = dpu_encoder_get_clones(encoder);
++ }
+
+ max_crtc_count = min(catalog->mixer_count, num_encoders);
+
+--
+2.39.5
+
--- /dev/null
+From f6d17b34fb6686e339e324ccc0c5844cdf8473ed Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 24 Jan 2025 10:29:50 -0800
+Subject: drm/nouveau: fix the broken marco GSP_MSG_MAX_SIZE
+
+From: Zhi Wang <zhiw@nvidia.com>
+
+[ Upstream commit bbae6680cfe38b033250b483722e60ccd865976f ]
+
+The macro GSP_MSG_MAX_SIZE refers to another macro that doesn't exist.
+It represents the max GSP message element size.
+
+Fix the broken marco so it can be used to replace some magic numbers in
+the code.
+
+Signed-off-by: Zhi Wang <zhiw@nvidia.com>
+Signed-off-by: Danilo Krummrich <dakr@kernel.org>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250124182958.2040494-8-zhiw@nvidia.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/nouveau/nvkm/subdev/gsp/r535.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/r535.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/r535.c
+index 58502102926b6..bb86b6d4ca49e 100644
+--- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/r535.c
++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/r535.c
+@@ -61,7 +61,7 @@
+ extern struct dentry *nouveau_debugfs_root;
+
+ #define GSP_MSG_MIN_SIZE GSP_PAGE_SIZE
+-#define GSP_MSG_MAX_SIZE GSP_PAGE_MIN_SIZE * 16
++#define GSP_MSG_MAX_SIZE (GSP_MSG_MIN_SIZE * 16)
+
+ struct r535_gsp_msg {
+ u8 auth_tag_buffer[16];
+--
+2.39.5
+
--- /dev/null
+From e8c0ec13f899244b88ce77b10dc71b3d156c056d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jan 2025 14:28:53 -0800
+Subject: drm/panel-edp: Add Starry 116KHD024006
+
+From: Douglas Anderson <dianders@chromium.org>
+
+[ Upstream commit 749b5b279e5636cdcef51e15d67b77162cca6caa ]
+
+We have a few reports of sc7180-trogdor-pompom devices that have a
+panel in them that IDs as STA 0x0004 and has the following raw EDID:
+
+ 00 ff ff ff ff ff ff 00 4e 81 04 00 00 00 00 00
+ 10 20 01 04 a5 1a 0e 78 0a dc dd 96 5b 5b 91 28
+ 1f 52 54 00 00 00 01 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 8e 1c 56 a0 50 00 1e 30 28 20
+ 55 00 00 90 10 00 00 18 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fe
+ 00 31 31 36 4b 48 44 30 32 34 30 30 36 0a 00 e6
+
+We've been unable to locate a datasheet for this panel and our partner
+has not been responsive, but all Starry eDP datasheets that we can
+find agree on the same timing (delay_100_500_e200) so it should be
+safe to use that here instead of the super conservative timings. We'll
+still go a little extra conservative and allow `hpd_absent` of 200
+instead of 100 because that won't add any real-world delay in most
+cases.
+
+We'll associate the string from the EDID ("116KHD024006") with this
+panel. Given that the ID is the suspicious value of 0x0004 it seems
+likely that Starry doesn't always update their IDs but the string will
+still work to differentiate if we ever need to in the future.
+
+Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
+Signed-off-by: Douglas Anderson <dianders@chromium.org>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250109142853.1.Ibcc3009933fd19507cc9c713ad0c99c7a9e4fe17@changeid
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/panel/panel-edp.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c
+index f8511fe5fb0d6..b0315d3ba00a5 100644
+--- a/drivers/gpu/drm/panel/panel-edp.c
++++ b/drivers/gpu/drm/panel/panel-edp.c
+@@ -1993,6 +1993,7 @@ static const struct edp_panel_entry edp_panels[] = {
+ EDP_PANEL_ENTRY('S', 'H', 'P', 0x154c, &delay_200_500_p2e100, "LQ116M1JW10"),
+ EDP_PANEL_ENTRY('S', 'H', 'P', 0x1593, &delay_200_500_p2e100, "LQ134N1"),
+
++ EDP_PANEL_ENTRY('S', 'T', 'A', 0x0004, &delay_200_500_e200, "116KHD024006"),
+ EDP_PANEL_ENTRY('S', 'T', 'A', 0x0100, &delay_100_500_e200, "2081116HHD028001-51D"),
+
+ { /* sentinal */ }
+--
+2.39.5
+
--- /dev/null
+From 1c4e2757ae99c766e44295d146bef560546025c5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Mar 2025 11:44:17 +0800
+Subject: drm/rockchip: vop2: Add uv swap for cluster window
+
+From: Andy Yan <andy.yan@rock-chips.com>
+
+[ Upstream commit e7aae9f6d762139f8d2b86db03793ae0ab3dd802 ]
+
+The Cluster windows of upcoming VOP on rk3576 also support
+linear YUV support, we need to set uv swap bit for it.
+
+As the VOP2_WIN_UV_SWA register defined on rk3568/rk3588 is
+0xffffffff, so this register will not be touched on these
+two platforms.
+
+Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
+Tested-by: Michael Riesch <michael.riesch@wolfvision.net> # on RK3568
+Tested-by: Detlev Casanova <detlev.casanova@collabora.com>
+Signed-off-by: Heiko Stuebner <heiko@sntech.de>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250303034436.192400-4-andyshrk@163.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+index 17a98845fd31b..64029237358d8 100644
+--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+@@ -1547,10 +1547,8 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
+
+ rb_swap = vop2_win_rb_swap(fb->format->format);
+ vop2_win_write(win, VOP2_WIN_RB_SWAP, rb_swap);
+- if (!vop2_cluster_window(win)) {
+- uv_swap = vop2_win_uv_swap(fb->format->format);
+- vop2_win_write(win, VOP2_WIN_UV_SWAP, uv_swap);
+- }
++ uv_swap = vop2_win_uv_swap(fb->format->format);
++ vop2_win_write(win, VOP2_WIN_UV_SWAP, uv_swap);
+
+ if (fb->format->is_yuv) {
+ vop2_win_write(win, VOP2_WIN_UV_VIR, DIV_ROUND_UP(fb->pitches[1], 4));
+--
+2.39.5
+
--- /dev/null
+From d73375026d9619615d48de66bb5f59de5a4ab50b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Feb 2025 14:40:06 +0200
+Subject: drm/rockchip: vop2: Improve display modes handling on RK3588 HDMI0
+
+From: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
+
+[ Upstream commit 2c1268e7aad0819f38e56134bbc2095fd95fde1b ]
+
+The RK3588 specific implementation is currently quite limited in terms
+of handling the full range of display modes supported by the connected
+screens, e.g. 2560x1440@75Hz, 2048x1152@60Hz, 1024x768@60Hz are just a
+few of them.
+
+Additionally, it doesn't cope well with non-integer refresh rates like
+59.94, 29.97, 23.98, etc.
+
+Make use of HDMI0 PHY PLL as a more accurate DCLK source to handle
+all display modes up to 4K@60Hz.
+
+Tested-by: FUKAUMI Naoki <naoki@radxa.com>
+Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
+Signed-off-by: Heiko Stuebner <heiko@sntech.de>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250204-vop2-hdmi0-disp-modes-v3-3-d71c6a196e58@collabora.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 34 ++++++++++++++++++++
+ 1 file changed, 34 insertions(+)
+
+diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+index 64029237358d8..bcbd498823928 100644
+--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+@@ -159,6 +159,7 @@ struct vop2_video_port {
+ struct drm_crtc crtc;
+ struct vop2 *vop2;
+ struct clk *dclk;
++ struct clk *dclk_src;
+ unsigned int id;
+ const struct vop2_video_port_data *data;
+
+@@ -214,6 +215,7 @@ struct vop2 {
+ struct clk *hclk;
+ struct clk *aclk;
+ struct clk *pclk;
++ struct clk *pll_hdmiphy0;
+
+ /* optional internal rgb encoder */
+ struct rockchip_rgb *rgb;
+@@ -222,6 +224,8 @@ struct vop2 {
+ struct vop2_win win[];
+ };
+
++#define VOP2_MAX_DCLK_RATE 600000000
++
+ #define vop2_output_if_is_hdmi(x) ((x) == ROCKCHIP_VOP2_EP_HDMI0 || \
+ (x) == ROCKCHIP_VOP2_EP_HDMI1)
+
+@@ -1155,6 +1159,9 @@ static void vop2_crtc_atomic_disable(struct drm_crtc *crtc,
+
+ vop2_crtc_disable_irq(vp, VP_INT_DSP_HOLD_VALID);
+
++ if (vp->dclk_src)
++ clk_set_parent(vp->dclk, vp->dclk_src);
++
+ clk_disable_unprepare(vp->dclk);
+
+ vop2->enable_count--;
+@@ -2257,6 +2264,27 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc,
+
+ vop2_vp_write(vp, RK3568_VP_MIPI_CTRL, 0);
+
++ /*
++ * Switch to HDMI PHY PLL as DCLK source for display modes up
++ * to 4K@60Hz, if available, otherwise keep using the system CRU.
++ */
++ if (vop2->pll_hdmiphy0 && clock <= VOP2_MAX_DCLK_RATE) {
++ drm_for_each_encoder_mask(encoder, crtc->dev, crtc_state->encoder_mask) {
++ struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
++
++ if (rkencoder->crtc_endpoint_id == ROCKCHIP_VOP2_EP_HDMI0) {
++ if (!vp->dclk_src)
++ vp->dclk_src = clk_get_parent(vp->dclk);
++
++ ret = clk_set_parent(vp->dclk, vop2->pll_hdmiphy0);
++ if (ret < 0)
++ drm_warn(vop2->drm,
++ "Could not switch to HDMI0 PHY PLL: %d\n", ret);
++ break;
++ }
++ }
++ }
++
+ clk_set_rate(vp->dclk, clock);
+
+ vop2_post_config(crtc);
+@@ -3697,6 +3725,12 @@ static int vop2_bind(struct device *dev, struct device *master, void *data)
+ return PTR_ERR(vop2->pclk);
+ }
+
++ vop2->pll_hdmiphy0 = devm_clk_get_optional(vop2->dev, "pll_hdmiphy0");
++ if (IS_ERR(vop2->pll_hdmiphy0)) {
++ drm_err(vop2->drm, "failed to get pll_hdmiphy0\n");
++ return PTR_ERR(vop2->pll_hdmiphy0);
++ }
++
+ vop2->irq = platform_get_irq(pdev, 0);
+ if (vop2->irq < 0) {
+ drm_err(vop2->drm, "cannot find irq for vop2\n");
+--
+2.39.5
+
--- /dev/null
+From d1b8526cf72128528457136dcc023c653ff6727a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 23 Apr 2025 09:54:42 +0530
+Subject: drm/ttm: fix the warning for hit_low and evict_low
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Sunil Khatri <sunil.khatri@amd.com>
+
+[ Upstream commit 76047483fe94414edf409dc498498abf346e22f1 ]
+
+fix the below warning messages:
+ttm/ttm_bo.c:1098: warning: Function parameter or struct member 'hit_low' not described in 'ttm_bo_swapout_walk'
+ttm/ttm_bo.c:1098: warning: Function parameter or struct member 'evict_low' not described in 'ttm_bo_swapout_walk'
+
+Cc: Maarten Lankhorst <dev@lankhorst.se>
+Cc: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
+Signed-off-by: Sunil Khatri <sunil.khatri@amd.com>
+Reviewed-by: Maarten Lankhorst <dev@lankhorst.se>
+Signed-off-by: Christian König <christian.koenig@amd.com>
+Link: https://lore.kernel.org/r/20250423042442.762108-1-sunil.khatri@amd.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/ttm/ttm_bo.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
+index ea5e498588573..72c675191a022 100644
+--- a/drivers/gpu/drm/ttm/ttm_bo.c
++++ b/drivers/gpu/drm/ttm/ttm_bo.c
+@@ -1092,7 +1092,8 @@ struct ttm_bo_swapout_walk {
+ struct ttm_lru_walk walk;
+ /** @gfp_flags: The gfp flags to use for ttm_tt_swapout() */
+ gfp_t gfp_flags;
+-
++ /** @hit_low: Whether we should attempt to swap BO's with low watermark threshold */
++ /** @evict_low: If we cannot swap a bo when @try_low is false (first pass) */
+ bool hit_low, evict_low;
+ };
+
+--
+2.39.5
+
--- /dev/null
+From 984dc4d11e5b7edb44b1b7677fb20d0552df9137 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 1 Feb 2025 13:50:46 +0100
+Subject: drm/v3d: Add clock handling
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Stefan Wahren <wahrenst@gmx.net>
+
+[ Upstream commit 4dd40b5f9c3d89b67af0dbe059cf4a51aac6bf06 ]
+
+Since the initial commit 57692c94dcbe ("drm/v3d: Introduce a new DRM driver
+for Broadcom V3D V3.x+") the struct v3d_dev reserved a pointer for
+an optional V3D clock. But there wasn't any code, which fetched it.
+So add the missing clock handling before accessing any V3D registers.
+
+Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
+Reviewed-by: Maíra Canal <mcanal@igalia.com>
+Signed-off-by: Maíra Canal <mcanal@igalia.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250201125046.33030-1-wahrenst@gmx.net
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/v3d/v3d_drv.c | 25 ++++++++++++++++++++-----
+ 1 file changed, 20 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c
+index 930737a9347b6..852015214e971 100644
+--- a/drivers/gpu/drm/v3d/v3d_drv.c
++++ b/drivers/gpu/drm/v3d/v3d_drv.c
+@@ -295,11 +295,21 @@ static int v3d_platform_drm_probe(struct platform_device *pdev)
+ if (ret)
+ return ret;
+
++ v3d->clk = devm_clk_get_optional(dev, NULL);
++ if (IS_ERR(v3d->clk))
++ return dev_err_probe(dev, PTR_ERR(v3d->clk), "Failed to get V3D clock\n");
++
++ ret = clk_prepare_enable(v3d->clk);
++ if (ret) {
++ dev_err(&pdev->dev, "Couldn't enable the V3D clock\n");
++ return ret;
++ }
++
+ mmu_debug = V3D_READ(V3D_MMU_DEBUG_INFO);
+ mask = DMA_BIT_MASK(30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_PA_WIDTH));
+ ret = dma_set_mask_and_coherent(dev, mask);
+ if (ret)
+- return ret;
++ goto clk_disable;
+
+ v3d->va_width = 30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_VA_WIDTH);
+
+@@ -319,28 +329,29 @@ static int v3d_platform_drm_probe(struct platform_device *pdev)
+ ret = PTR_ERR(v3d->reset);
+
+ if (ret == -EPROBE_DEFER)
+- return ret;
++ goto clk_disable;
+
+ v3d->reset = NULL;
+ ret = map_regs(v3d, &v3d->bridge_regs, "bridge");
+ if (ret) {
+ dev_err(dev,
+ "Failed to get reset control or bridge regs\n");
+- return ret;
++ goto clk_disable;
+ }
+ }
+
+ if (v3d->ver < 41) {
+ ret = map_regs(v3d, &v3d->gca_regs, "gca");
+ if (ret)
+- return ret;
++ goto clk_disable;
+ }
+
+ v3d->mmu_scratch = dma_alloc_wc(dev, 4096, &v3d->mmu_scratch_paddr,
+ GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO);
+ if (!v3d->mmu_scratch) {
+ dev_err(dev, "Failed to allocate MMU scratch page\n");
+- return -ENOMEM;
++ ret = -ENOMEM;
++ goto clk_disable;
+ }
+
+ ret = v3d_gem_init(drm);
+@@ -369,6 +380,8 @@ static int v3d_platform_drm_probe(struct platform_device *pdev)
+ v3d_gem_destroy(drm);
+ dma_free:
+ dma_free_wc(dev, 4096, v3d->mmu_scratch, v3d->mmu_scratch_paddr);
++clk_disable:
++ clk_disable_unprepare(v3d->clk);
+ return ret;
+ }
+
+@@ -386,6 +399,8 @@ static void v3d_platform_drm_remove(struct platform_device *pdev)
+
+ dma_free_wc(v3d->drm.dev, 4096, v3d->mmu_scratch,
+ v3d->mmu_scratch_paddr);
++
++ clk_disable_unprepare(v3d->clk);
+ }
+
+ static struct platform_driver v3d_platform_driver = {
+--
+2.39.5
+
--- /dev/null
+From 3019c98b6332023de349e0f0e0a3debfe78ceb7a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 10 Jan 2025 09:33:09 -0800
+Subject: drm/xe: Add locks in gtidle code
+
+From: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
+
+[ Upstream commit d160dc6f53914d729be7fcb7afbd0e9e6a3725b2 ]
+
+The update of the residency values needs to be protected by a lock to
+avoid multiple entrypoints, for example when multiple userspace clients
+read the sysfs file. Other in-kernel clients are going to be added to
+sample these values, making the problem worse. Protect those updates
+with a raw_spinlock so it can be called by future integration with perf
+pmu.
+
+Suggested-by: Lucas De Marchi <lucas.demarchi@intel.com>
+Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
+Cc: Lucas De Marchi <lucas.demarchi@intel.com>
+Signed-off-by: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
+Reviewed-by: Lucas De Marchi <lucas.demarchi@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250110173308.2412232-2-lucas.demarchi@intel.com
+Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/xe_gt_idle.c | 23 ++++++++++++++++++++---
+ drivers/gpu/drm/xe/xe_gt_idle.h | 1 +
+ drivers/gpu/drm/xe/xe_gt_idle_types.h | 3 +++
+ 3 files changed, 24 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/gpu/drm/xe/xe_gt_idle.c b/drivers/gpu/drm/xe/xe_gt_idle.c
+index ffd3ba7f66561..fbbace7b0b12a 100644
+--- a/drivers/gpu/drm/xe/xe_gt_idle.c
++++ b/drivers/gpu/drm/xe/xe_gt_idle.c
+@@ -69,6 +69,8 @@ static u64 get_residency_ms(struct xe_gt_idle *gtidle, u64 cur_residency)
+ {
+ u64 delta, overflow_residency, prev_residency;
+
++ lockdep_assert_held(>idle->lock);
++
+ overflow_residency = BIT_ULL(32);
+
+ /*
+@@ -275,8 +277,21 @@ static ssize_t idle_status_show(struct device *dev,
+
+ return sysfs_emit(buff, "%s\n", gt_idle_state_to_string(state));
+ }
+-static DEVICE_ATTR_RO(idle_status);
+
++u64 xe_gt_idle_residency_msec(struct xe_gt_idle *gtidle)
++{
++ struct xe_guc_pc *pc = gtidle_to_pc(gtidle);
++ u64 residency;
++ unsigned long flags;
++
++ raw_spin_lock_irqsave(>idle->lock, flags);
++ residency = get_residency_ms(gtidle, gtidle->idle_residency(pc));
++ raw_spin_unlock_irqrestore(>idle->lock, flags);
++
++ return residency;
++}
++
++static DEVICE_ATTR_RO(idle_status);
+ static ssize_t idle_residency_ms_show(struct device *dev,
+ struct device_attribute *attr, char *buff)
+ {
+@@ -285,10 +300,10 @@ static ssize_t idle_residency_ms_show(struct device *dev,
+ u64 residency;
+
+ xe_pm_runtime_get(pc_to_xe(pc));
+- residency = gtidle->idle_residency(pc);
++ residency = xe_gt_idle_residency_msec(gtidle);
+ xe_pm_runtime_put(pc_to_xe(pc));
+
+- return sysfs_emit(buff, "%llu\n", get_residency_ms(gtidle, residency));
++ return sysfs_emit(buff, "%llu\n", residency);
+ }
+ static DEVICE_ATTR_RO(idle_residency_ms);
+
+@@ -331,6 +346,8 @@ int xe_gt_idle_init(struct xe_gt_idle *gtidle)
+ if (!kobj)
+ return -ENOMEM;
+
++ raw_spin_lock_init(>idle->lock);
++
+ if (xe_gt_is_media_type(gt)) {
+ snprintf(gtidle->name, sizeof(gtidle->name), "gt%d-mc", gt->info.id);
+ gtidle->idle_residency = xe_guc_pc_mc6_residency;
+diff --git a/drivers/gpu/drm/xe/xe_gt_idle.h b/drivers/gpu/drm/xe/xe_gt_idle.h
+index 4455a6501cb07..591a01e181bcc 100644
+--- a/drivers/gpu/drm/xe/xe_gt_idle.h
++++ b/drivers/gpu/drm/xe/xe_gt_idle.h
+@@ -17,5 +17,6 @@ void xe_gt_idle_disable_c6(struct xe_gt *gt);
+ void xe_gt_idle_enable_pg(struct xe_gt *gt);
+ void xe_gt_idle_disable_pg(struct xe_gt *gt);
+ int xe_gt_idle_pg_print(struct xe_gt *gt, struct drm_printer *p);
++u64 xe_gt_idle_residency_msec(struct xe_gt_idle *gtidle);
+
+ #endif /* _XE_GT_IDLE_H_ */
+diff --git a/drivers/gpu/drm/xe/xe_gt_idle_types.h b/drivers/gpu/drm/xe/xe_gt_idle_types.h
+index b8b297a3f8848..a3667c567f8a7 100644
+--- a/drivers/gpu/drm/xe/xe_gt_idle_types.h
++++ b/drivers/gpu/drm/xe/xe_gt_idle_types.h
+@@ -6,6 +6,7 @@
+ #ifndef _XE_GT_IDLE_SYSFS_TYPES_H_
+ #define _XE_GT_IDLE_SYSFS_TYPES_H_
+
++#include <linux/spinlock.h>
+ #include <linux/types.h>
+
+ struct xe_guc_pc;
+@@ -31,6 +32,8 @@ struct xe_gt_idle {
+ u64 cur_residency;
+ /** @prev_residency: previous residency counter */
+ u64 prev_residency;
++ /** @lock: Lock protecting idle residency counters */
++ raw_spinlock_t lock;
+ /** @idle_status: get the current idle state */
+ enum xe_gt_idle_state (*idle_status)(struct xe_guc_pc *pc);
+ /** @idle_residency: get idle residency counter */
+--
+2.39.5
+
--- /dev/null
+From be6f7a4ad38eef99c3969c840dc867a0eb90ecee Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 14 Nov 2024 18:59:54 +0100
+Subject: drm/xe: Always setup GT MMIO adjustment data
+
+From: Michal Wajdeczko <michal.wajdeczko@intel.com>
+
+[ Upstream commit bbd8429264baf8bc3c40cefda048560ae0eb7890 ]
+
+While we believed that xe_gt_mmio_init() will be called just once
+per GT, this might not be a case due to some tweaks that need to
+performed by the VF driver during early probe. To avoid leaving
+any stale data in case of the re-run, reset the GT MMIO adjustment
+data for the non-media GT case.
+
+Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
+Cc: Matt Roper <matthew.d.roper@intel.com>
+Reviewed-by: Lucas De Marchi <lucas.demarchi@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20241114175955.2299-2-michal.wajdeczko@intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/xe_gt.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/gpu/drm/xe/xe_gt.c b/drivers/gpu/drm/xe/xe_gt.c
+index 150dca2f91033..6b4b9eca2c384 100644
+--- a/drivers/gpu/drm/xe/xe_gt.c
++++ b/drivers/gpu/drm/xe/xe_gt.c
+@@ -650,6 +650,9 @@ void xe_gt_mmio_init(struct xe_gt *gt)
+ if (gt->info.type == XE_GT_TYPE_MEDIA) {
+ gt->mmio.adj_offset = MEDIA_GT_GSI_OFFSET;
+ gt->mmio.adj_limit = MEDIA_GT_GSI_LENGTH;
++ } else {
++ gt->mmio.adj_offset = 0;
++ gt->mmio.adj_limit = 0;
+ }
+
+ if (IS_SRIOV_VF(gt_to_xe(gt)))
+--
+2.39.5
+
--- /dev/null
+From 9f679234267233be694e219459a04ed1fc5e6d0a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Feb 2025 20:16:44 +0100
+Subject: drm/xe/client: Skip show_run_ticks if unable to read timestamp
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
+
+[ Upstream commit 94030a1d3283251778411cf74553607a65260f78 ]
+
+RING_TIMESTAMP registers are inaccessible in VF mode.
+Without drm-total-cycles-*, other keys provide little value.
+Skip all optional "run_ticks" keys in this case.
+
+Signed-off-by: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
+Cc: Lucas De Marchi <lucas.demarchi@intel.com>
+Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
+Cc: Michał Winiarski <michal.winiarski@intel.com>
+Cc: Umesh Nerlige Ramappa <umesh.nerlige.ramappa@intel.com>
+Reviewed-by: Satyanarayana K V P <satyanarayana.k.v.p@intel.com>
+Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250205191644.2550879-3-marcin.bernatowicz@linux.intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/xe_drm_client.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/drivers/gpu/drm/xe/xe_drm_client.c b/drivers/gpu/drm/xe/xe_drm_client.c
+index 2d4874d2b9225..31f688e953d7b 100644
+--- a/drivers/gpu/drm/xe/xe_drm_client.c
++++ b/drivers/gpu/drm/xe/xe_drm_client.c
+@@ -324,6 +324,14 @@ static void show_run_ticks(struct drm_printer *p, struct drm_file *file)
+ u64 gpu_timestamp;
+ unsigned int fw_ref;
+
++ /*
++ * RING_TIMESTAMP registers are inaccessible in VF mode.
++ * Without drm-total-cycles-*, other keys provide little value.
++ * Show all or none of the optional "run_ticks" keys in this case.
++ */
++ if (IS_SRIOV_VF(xe))
++ return;
++
+ /*
+ * Wait for any exec queue going away: their cycles will get updated on
+ * context switch out, so wait for that to happen
+--
+2.39.5
+
--- /dev/null
+From 43c161088ef291ab95dcfaf9fbc46c4abd57b5a7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 13 Feb 2025 23:03:22 +0000
+Subject: drm/xe/debugfs: Add missing xe_pm_runtime_put in wedge_mode_set
+
+From: Shuicheng Lin <shuicheng.lin@intel.com>
+
+[ Upstream commit b31e668d3111b100d16fd7db8db335328ce8c6d5 ]
+
+xe_pm_runtime_put is missed in the failure path.
+
+Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
+Signed-off-by: Shuicheng Lin <shuicheng.lin@intel.com>
+Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250213230322.1180621-1-shuicheng.lin@intel.com
+Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/xe_debugfs.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/gpu/drm/xe/xe_debugfs.c b/drivers/gpu/drm/xe/xe_debugfs.c
+index 6bfdd3a9913fd..92e6fa8fe3a17 100644
+--- a/drivers/gpu/drm/xe/xe_debugfs.c
++++ b/drivers/gpu/drm/xe/xe_debugfs.c
+@@ -175,6 +175,7 @@ static ssize_t wedged_mode_set(struct file *f, const char __user *ubuf,
+ ret = xe_guc_ads_scheduler_policy_toggle_reset(>->uc.guc.ads);
+ if (ret) {
+ xe_gt_err(gt, "Failed to update GuC ADS scheduler policy. GuC may still cause engine reset even with wedged_mode=2\n");
++ xe_pm_runtime_put(xe);
+ return -EIO;
+ }
+ }
+--
+2.39.5
+
--- /dev/null
+From 556c72b0aab2eda53b0459c3920c8de92f3d9274 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 14 Feb 2025 06:36:15 +0800
+Subject: drm/xe/debugfs: fixed the return value of wedged_mode_set
+
+From: Xin Wang <x.wang@intel.com>
+
+[ Upstream commit 6884d2051011f4db9e2f0b85709c79a8ced13bd6 ]
+
+It is generally expected that the write() function should return a
+positive value indicating the number of bytes written or a negative
+error code if an error occurs. Returning 0 is unusual and can lead
+to unexpected behavior.
+
+When the user program writes the same value to wedged_mode twice in
+a row, a lockup will occur, because the value expected to be
+returned by the write() function inside the program should be equal
+to the actual written value instead of 0.
+
+To reproduce the issue:
+echo 1 > /sys/kernel/debug/dri/0/wedged_mode
+echo 1 > /sys/kernel/debug/dri/0/wedged_mode <- lockup here
+
+Signed-off-by: Xin Wang <x.wang@intel.com>
+Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
+Cc: Fei Yang <fei.yang@intel.com>
+Cc: Shuicheng Lin <shuicheng.lin@intel.com>
+Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250213223615.2327367-1-x.wang@intel.com
+Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/xe_debugfs.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/xe/xe_debugfs.c b/drivers/gpu/drm/xe/xe_debugfs.c
+index 492b4877433f1..6bfdd3a9913fd 100644
+--- a/drivers/gpu/drm/xe/xe_debugfs.c
++++ b/drivers/gpu/drm/xe/xe_debugfs.c
+@@ -166,7 +166,7 @@ static ssize_t wedged_mode_set(struct file *f, const char __user *ubuf,
+ return -EINVAL;
+
+ if (xe->wedged.mode == wedged_mode)
+- return 0;
++ return size;
+
+ xe->wedged.mode = wedged_mode;
+
+--
+2.39.5
+
--- /dev/null
+From c1e924ce8f93779c740a9b5e3ecaf04934048d06 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 21 Feb 2025 15:51:41 -0300
+Subject: drm/xe: Disambiguate GMDID-based IP names
+
+From: Gustavo Sousa <gustavo.sousa@intel.com>
+
+[ Upstream commit 0695c746f55c875f4cf20bab92533a800a0fe4d6 ]
+
+The name of an IP is a function of its version. As such, given an IP
+version, it should be clear to identify the name of that IP release.
+
+With the current code, we keep that mapping clear for pre-GMDID IPs, but
+ambiguous for GMDID-based ones. That causes two types of inconveniences:
+
+ 1. The end user, who might not have all the necessary mapping at hand,
+ might be confused when seeing different possible IP names in the
+ dmesg log.
+
+ 2. It makes a developer who is not familiar with the "IP version" to
+ "Release name" need to resort to looking at the specs to understand
+ see what version maps to what. While the specs should be the
+ authority on the mapping, we should make our lives easier by
+ reflecting that mapping in the source code.
+
+Thus, since the IP name is tied to the version, let's remove the
+ambiguity by using a "name" field in struct gmdid_map instead of
+accumulating names in the descriptor instances.
+
+This does result in the code having IP name being defined in
+different structs (gmdid_map, xe_graphics_desc, xe_media_desc), but that
+will be resolved in upcoming changes.
+
+A side-effect of this change is that media_xe2 exactly matches
+media_xelpmp now, so we just re-use the latter.
+
+v2:
+ - Drop media_xe2 and re-use media_xelpmp. (Matt)
+
+Reviewed-by: Matt Roper <matthew.d.roper@intel.com>
+Signed-off-by: Gustavo Sousa <gustavo.sousa@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250221-xe-unify-ip-descriptors-v2-2-5bc0c6d0c13f@intel.com
+Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/xe_pci.c | 36 +++++++++++--------------------
+ drivers/gpu/drm/xe/xe_pci_types.h | 1 +
+ 2 files changed, 14 insertions(+), 23 deletions(-)
+
+diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c
+index 39be74848e447..9b8813a518d72 100644
+--- a/drivers/gpu/drm/xe/xe_pci.c
++++ b/drivers/gpu/drm/xe/xe_pci.c
+@@ -150,7 +150,6 @@ static const struct xe_graphics_desc graphics_xehpc = {
+ };
+
+ static const struct xe_graphics_desc graphics_xelpg = {
+- .name = "Xe_LPG",
+ .hw_engine_mask =
+ BIT(XE_HW_ENGINE_RCS0) | BIT(XE_HW_ENGINE_BCS0) |
+ BIT(XE_HW_ENGINE_CCS0),
+@@ -174,8 +173,6 @@ static const struct xe_graphics_desc graphics_xelpg = {
+ GENMASK(XE_HW_ENGINE_CCS3, XE_HW_ENGINE_CCS0)
+
+ static const struct xe_graphics_desc graphics_xe2 = {
+- .name = "Xe2_LPG / Xe2_HPG / Xe3_LPG",
+-
+ XE2_GFX_FEATURES,
+ };
+
+@@ -200,15 +197,6 @@ static const struct xe_media_desc media_xehpm = {
+ };
+
+ static const struct xe_media_desc media_xelpmp = {
+- .name = "Xe_LPM+",
+- .hw_engine_mask =
+- GENMASK(XE_HW_ENGINE_VCS7, XE_HW_ENGINE_VCS0) |
+- GENMASK(XE_HW_ENGINE_VECS3, XE_HW_ENGINE_VECS0) |
+- BIT(XE_HW_ENGINE_GSCCS0)
+-};
+-
+-static const struct xe_media_desc media_xe2 = {
+- .name = "Xe2_LPM / Xe2_HPM / Xe3_LPM",
+ .hw_engine_mask =
+ GENMASK(XE_HW_ENGINE_VCS7, XE_HW_ENGINE_VCS0) |
+ GENMASK(XE_HW_ENGINE_VECS3, XE_HW_ENGINE_VECS0) |
+@@ -357,21 +345,21 @@ __diag_pop();
+
+ /* Map of GMD_ID values to graphics IP */
+ static const struct gmdid_map graphics_ip_map[] = {
+- { 1270, &graphics_xelpg },
+- { 1271, &graphics_xelpg },
+- { 1274, &graphics_xelpg }, /* Xe_LPG+ */
+- { 2001, &graphics_xe2 },
+- { 2004, &graphics_xe2 },
+- { 3000, &graphics_xe2 },
+- { 3001, &graphics_xe2 },
++ { 1270, "Xe_LPG", &graphics_xelpg },
++ { 1271, "Xe_LPG", &graphics_xelpg },
++ { 1274, "Xe_LPG+", &graphics_xelpg },
++ { 2001, "Xe2_HPG", &graphics_xe2 },
++ { 2004, "Xe2_LPG", &graphics_xe2 },
++ { 3000, "Xe3_LPG", &graphics_xe2 },
++ { 3001, "Xe3_LPG", &graphics_xe2 },
+ };
+
+ /* Map of GMD_ID values to media IP */
+ static const struct gmdid_map media_ip_map[] = {
+- { 1300, &media_xelpmp },
+- { 1301, &media_xe2 },
+- { 2000, &media_xe2 },
+- { 3000, &media_xe2 },
++ { 1300, "Xe_LPM+", &media_xelpmp },
++ { 1301, "Xe2_HPM", &media_xelpmp },
++ { 2000, "Xe2_LPM", &media_xelpmp },
++ { 3000, "Xe3_LPM", &media_xelpmp },
+ };
+
+ /*
+@@ -566,6 +554,7 @@ static void handle_gmdid(struct xe_device *xe,
+ for (int i = 0; i < ARRAY_SIZE(graphics_ip_map); i++) {
+ if (ver == graphics_ip_map[i].ver) {
+ xe->info.graphics_verx100 = ver;
++ xe->info.graphics_name = graphics_ip_map[i].name;
+ *graphics = graphics_ip_map[i].ip;
+
+ break;
+@@ -586,6 +575,7 @@ static void handle_gmdid(struct xe_device *xe,
+ for (int i = 0; i < ARRAY_SIZE(media_ip_map); i++) {
+ if (ver == media_ip_map[i].ver) {
+ xe->info.media_verx100 = ver;
++ xe->info.media_name = media_ip_map[i].name;
+ *media = media_ip_map[i].ip;
+
+ break;
+diff --git a/drivers/gpu/drm/xe/xe_pci_types.h b/drivers/gpu/drm/xe/xe_pci_types.h
+index 79b0f80376a4d..665b4447b2ebc 100644
+--- a/drivers/gpu/drm/xe/xe_pci_types.h
++++ b/drivers/gpu/drm/xe/xe_pci_types.h
+@@ -44,6 +44,7 @@ struct xe_media_desc {
+
+ struct gmdid_map {
+ unsigned int ver;
++ const char *name;
+ const void *ip;
+ };
+
+--
+2.39.5
+
--- /dev/null
+From e736f29ea8d5e7a8b59f1b282fc42f3fbf7b45a8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 12 Feb 2025 14:24:47 -0500
+Subject: drm/xe/display: Remove hpd cancel work sync from runtime pm path
+
+From: Rodrigo Vivi <rodrigo.vivi@intel.com>
+
+[ Upstream commit 1ed591582b7b894d2f7e7ab5cef2e9b0b6fef12b ]
+
+This function will synchronously cancel and wait for many display
+work queue items, which might try to take the runtime pm reference
+causing a bad deadlock. So, remove it from the runtime_pm suspend patch.
+
+Reported-by: Imre Deak <imre.deak@intel.com>
+Reviewed-by: Imre Deak <imre.deak@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250212192447.402715-1-rodrigo.vivi@intel.com
+Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/display/xe_display.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/xe/display/xe_display.c b/drivers/gpu/drm/xe/display/xe_display.c
+index b3921dbc52ff6..b735e30953cee 100644
+--- a/drivers/gpu/drm/xe/display/xe_display.c
++++ b/drivers/gpu/drm/xe/display/xe_display.c
+@@ -346,7 +346,8 @@ static void __xe_display_pm_suspend(struct xe_device *xe, bool runtime)
+
+ xe_display_flush_cleanup_work(xe);
+
+- intel_hpd_cancel_work(xe);
++ if (!runtime)
++ intel_hpd_cancel_work(xe);
+
+ if (!runtime && has_display(xe)) {
+ intel_display_driver_suspend_access(display);
+--
+2.39.5
+
--- /dev/null
+From 2b1d02d71533738f976b1903f9cec492672e17d9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 10 Dec 2024 09:31:11 +0100
+Subject: drm/xe: Do not attempt to bootstrap VF in execlists mode
+
+From: Maarten Lankhorst <dev@lankhorst.se>
+
+[ Upstream commit f3b59457808f61d88178b0afa67cbd017d7ce79e ]
+
+It was mentioned in a review that there is a possibility of choosing
+to load the module with VF in execlists mode.
+
+Of course this doesn't work, just bomb out as hard as possible.
+
+Reviewed-by: Lucas De Marchi <lucas.demarchi@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20241210083111.230484-12-dev@lankhorst.se
+Signed-off-by: Maarten Lankhorst <dev@lankhorst.se>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/xe_gt_sriov_vf.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_vf.c b/drivers/gpu/drm/xe/xe_gt_sriov_vf.c
+index 1c764f200b2a5..a439261bf4d72 100644
+--- a/drivers/gpu/drm/xe/xe_gt_sriov_vf.c
++++ b/drivers/gpu/drm/xe/xe_gt_sriov_vf.c
+@@ -236,6 +236,9 @@ int xe_gt_sriov_vf_bootstrap(struct xe_gt *gt)
+ {
+ int err;
+
++ if (!xe_device_uc_enabled(gt_to_xe(gt)))
++ return -ENODEV;
++
+ err = vf_reset_guc_state(gt);
+ if (unlikely(err))
+ return err;
+--
+2.39.5
+
--- /dev/null
+From 22987f7201f6aca444d016e314ea3705b31936a1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jan 2025 14:52:19 -0500
+Subject: drm/xe: Fix PVC RPe and RPa information
+
+From: Rodrigo Vivi <rodrigo.vivi@intel.com>
+
+[ Upstream commit 8a734b9359cfa1bdb805f5ca23e20bd99dd18a0a ]
+
+A simple lazy buggy copy and paste of the PVC comment has brought
+the attention to the incorrect masks of the PVC register for RPa
+and RPe. So, let's fix them all.
+
+Cc: Lucas De Marchi <lucas.demarchi@intel.com>
+Cc: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
+Reviewed-by: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250109195219.658557-1-rodrigo.vivi@intel.com
+Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/xe_guc_pc.c | 22 ++++++++++++----------
+ 1 file changed, 12 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/gpu/drm/xe/xe_guc_pc.c b/drivers/gpu/drm/xe/xe_guc_pc.c
+index f382f5d53ca8b..2276d85926fcb 100644
+--- a/drivers/gpu/drm/xe/xe_guc_pc.c
++++ b/drivers/gpu/drm/xe/xe_guc_pc.c
+@@ -371,16 +371,17 @@ static void tgl_update_rpa_value(struct xe_guc_pc *pc)
+ u32 reg;
+
+ /*
+- * For PVC we still need to use fused RP1 as the approximation for RPe
+- * For other platforms than PVC we get the resolved RPe directly from
++ * For PVC we still need to use fused RP0 as the approximation for RPa
++ * For other platforms than PVC we get the resolved RPa directly from
+ * PCODE at a different register
+ */
+- if (xe->info.platform == XE_PVC)
++ if (xe->info.platform == XE_PVC) {
+ reg = xe_mmio_read32(>->mmio, PVC_RP_STATE_CAP);
+- else
++ pc->rpa_freq = REG_FIELD_GET(RP0_MASK, reg) * GT_FREQUENCY_MULTIPLIER;
++ } else {
+ reg = xe_mmio_read32(>->mmio, FREQ_INFO_REC);
+-
+- pc->rpa_freq = REG_FIELD_GET(RPA_MASK, reg) * GT_FREQUENCY_MULTIPLIER;
++ pc->rpa_freq = REG_FIELD_GET(RPA_MASK, reg) * GT_FREQUENCY_MULTIPLIER;
++ }
+ }
+
+ static void tgl_update_rpe_value(struct xe_guc_pc *pc)
+@@ -394,12 +395,13 @@ static void tgl_update_rpe_value(struct xe_guc_pc *pc)
+ * For other platforms than PVC we get the resolved RPe directly from
+ * PCODE at a different register
+ */
+- if (xe->info.platform == XE_PVC)
++ if (xe->info.platform == XE_PVC) {
+ reg = xe_mmio_read32(>->mmio, PVC_RP_STATE_CAP);
+- else
++ pc->rpe_freq = REG_FIELD_GET(RP1_MASK, reg) * GT_FREQUENCY_MULTIPLIER;
++ } else {
+ reg = xe_mmio_read32(>->mmio, FREQ_INFO_REC);
+-
+- pc->rpe_freq = REG_FIELD_GET(RPE_MASK, reg) * GT_FREQUENCY_MULTIPLIER;
++ pc->rpe_freq = REG_FIELD_GET(RPE_MASK, reg) * GT_FREQUENCY_MULTIPLIER;
++ }
+ }
+
+ static void pc_update_rp_values(struct xe_guc_pc *pc)
+--
+2.39.5
+
--- /dev/null
+From a7c6159f19ee5abb01035592fe7c28bbde8e576a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 13 Feb 2025 11:29:00 -0800
+Subject: drm/xe: Fix xe_tile_init_noalloc() error propagation
+
+From: Lucas De Marchi <lucas.demarchi@intel.com>
+
+[ Upstream commit 0bcf41171c64234e79eb3552d00f0aad8a47e8d3 ]
+
+Propagate the error to the caller so initialization properly stops if
+sysfs creation fails.
+
+Reviewed-by: Francois Dugast <francois.dugast@intel.com>
+Reviewed-by: Himal Prasad Ghimiray <himal.prasad.ghimiray@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250213192909.996148-4-lucas.demarchi@intel.com
+Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/xe_tile.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+diff --git a/drivers/gpu/drm/xe/xe_tile.c b/drivers/gpu/drm/xe/xe_tile.c
+index 07cf7cfe4abd5..37f170effcd67 100644
+--- a/drivers/gpu/drm/xe/xe_tile.c
++++ b/drivers/gpu/drm/xe/xe_tile.c
+@@ -176,9 +176,7 @@ int xe_tile_init_noalloc(struct xe_tile *tile)
+
+ xe_wa_apply_tile_workarounds(tile);
+
+- err = xe_tile_sysfs_init(tile);
+-
+- return 0;
++ return xe_tile_sysfs_init(tile);
+ }
+
+ void xe_tile_migrate_wait(struct xe_tile *tile)
+--
+2.39.5
+
--- /dev/null
+From 3ccce22a43e408c352e137f8b82e213d1b9d9e16 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Jan 2025 11:44:04 -0800
+Subject: drm/xe/guc: Drop error messages about missing GuC logs
+
+From: John Harrison <John.C.Harrison@Intel.com>
+
+[ Upstream commit 174e9ce0daf6af791386e96e76e743eb59e8a401 ]
+
+The GuC log snapshot code would complain loudly if there was no GuC
+log to take a snapshot of or if the snapshot alloc failed. Originally,
+this code was only called on demand when a user (or developer)
+explicitly requested a dump of the log. Hence an error message was
+useful.
+
+However, it is now part of the general devcoredump file and is called
+for any GPU hang. Most people don't care about GuC logs and GPU hangs
+do not generally mean a kernel/GuC bug. More importantly, there are
+valid situations where there is no GuC log, e.g. SRIOV VFs.
+
+So drop the error message.
+
+Closes: https://gitlab.freedesktop.org/drm/xe/kernel/-/issues/3958
+Signed-off-by: John Harrison <John.C.Harrison@Intel.com>
+Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250113194405.2033085-1-John.C.Harrison@Intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/xe_guc_log.c | 8 ++------
+ 1 file changed, 2 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/gpu/drm/xe/xe_guc_log.c b/drivers/gpu/drm/xe/xe_guc_log.c
+index 0ca3056d8bd3f..80514a446ba28 100644
+--- a/drivers/gpu/drm/xe/xe_guc_log.c
++++ b/drivers/gpu/drm/xe/xe_guc_log.c
+@@ -149,16 +149,12 @@ struct xe_guc_log_snapshot *xe_guc_log_snapshot_capture(struct xe_guc_log *log,
+ size_t remain;
+ int i;
+
+- if (!log->bo) {
+- xe_gt_err(gt, "GuC log buffer not allocated\n");
++ if (!log->bo)
+ return NULL;
+- }
+
+ snapshot = xe_guc_log_snapshot_alloc(log, atomic);
+- if (!snapshot) {
+- xe_gt_err(gt, "GuC log snapshot not allocated\n");
++ if (!snapshot)
+ return NULL;
+- }
+
+ remain = snapshot->size;
+ for (i = 0; i < snapshot->num_chunks; i++) {
+--
+2.39.5
+
--- /dev/null
+From ad19b7951a55413ff7513b43ff48e78b34bfed62 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 10 Dec 2024 09:31:03 +0100
+Subject: drm/xe: Move suballocator init to after display init
+
+From: Maarten Lankhorst <dev@lankhorst.se>
+
+[ Upstream commit 380b0cdaa76bc8f5c16db16eaf48751e792ff041 ]
+
+No allocations should be done before we have had a chance to preserve
+the display fb.
+
+Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20241210083111.230484-4-dev@lankhorst.se
+Signed-off-by: Maarten Lankhorst <dev@lankhorst.se>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/xe_device.c | 6 ++++++
+ drivers/gpu/drm/xe/xe_tile.c | 12 ++++++++----
+ drivers/gpu/drm/xe/xe_tile.h | 1 +
+ 3 files changed, 15 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
+index e22f29ac96631..74516e73ba4e5 100644
+--- a/drivers/gpu/drm/xe/xe_device.c
++++ b/drivers/gpu/drm/xe/xe_device.c
+@@ -736,6 +736,12 @@ int xe_device_probe(struct xe_device *xe)
+ if (err)
+ goto err;
+
++ for_each_tile(tile, xe, id) {
++ err = xe_tile_init(tile);
++ if (err)
++ goto err;
++ }
++
+ for_each_gt(gt, xe, id) {
+ last_gt = id;
+
+diff --git a/drivers/gpu/drm/xe/xe_tile.c b/drivers/gpu/drm/xe/xe_tile.c
+index 37f170effcd67..377438ea6b838 100644
+--- a/drivers/gpu/drm/xe/xe_tile.c
++++ b/drivers/gpu/drm/xe/xe_tile.c
+@@ -170,15 +170,19 @@ int xe_tile_init_noalloc(struct xe_tile *tile)
+ if (err)
+ return err;
+
+- tile->mem.kernel_bb_pool = xe_sa_bo_manager_init(tile, SZ_1M, 16);
+- if (IS_ERR(tile->mem.kernel_bb_pool))
+- return PTR_ERR(tile->mem.kernel_bb_pool);
+-
+ xe_wa_apply_tile_workarounds(tile);
+
+ return xe_tile_sysfs_init(tile);
+ }
+
++int xe_tile_init(struct xe_tile *tile)
++{
++ tile->mem.kernel_bb_pool = xe_sa_bo_manager_init(tile, SZ_1M, 16);
++ if (IS_ERR(tile->mem.kernel_bb_pool))
++ return PTR_ERR(tile->mem.kernel_bb_pool);
++
++ return 0;
++}
+ void xe_tile_migrate_wait(struct xe_tile *tile)
+ {
+ xe_migrate_wait(tile->migrate);
+diff --git a/drivers/gpu/drm/xe/xe_tile.h b/drivers/gpu/drm/xe/xe_tile.h
+index 1c9e42ade6b05..eb939316d55b0 100644
+--- a/drivers/gpu/drm/xe/xe_tile.h
++++ b/drivers/gpu/drm/xe/xe_tile.h
+@@ -12,6 +12,7 @@ struct xe_tile;
+
+ int xe_tile_init_early(struct xe_tile *tile, struct xe_device *xe, u8 id);
+ int xe_tile_init_noalloc(struct xe_tile *tile);
++int xe_tile_init(struct xe_tile *tile);
+
+ void xe_tile_migrate_wait(struct xe_tile *tile);
+
+--
+2.39.5
+
--- /dev/null
+From 9ad70d195ae7be3c52f42a2830325c9839dacdc6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Mar 2025 17:26:36 -0800
+Subject: drm/xe: Nuke VM's mapping upon close
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Matthew Brost <matthew.brost@intel.com>
+
+[ Upstream commit 074e40d9c2a84939fe28d7121d3469db50f34a3d ]
+
+Clear root PT entry and invalidate entire VM's address space when
+closing the VM. Will prevent the GPU from accessing any of the VM's
+memory after closing.
+
+v2:
+ - s/vma/vm in kernel doc (CI)
+ - Don't nuke migration VM as this occur at driver unload (CI)
+v3:
+ - Rebase and pull into SVM series (Thomas)
+ - Wait for pending binds (Thomas)
+v5:
+ - Remove xe_gt_tlb_invalidation_fence_fini in error case (Matt Auld)
+ - Drop local migration bool (Thomas)
+v7:
+ - Add drm_dev_enter/exit protecting invalidation (CI, Matt Auld)
+
+Signed-off-by: Matthew Brost <matthew.brost@intel.com>
+Reviewed-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250306012657.3505757-12-matthew.brost@intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/xe_gt_tlb_invalidation.c | 22 ++++++++++++++
+ drivers/gpu/drm/xe/xe_gt_tlb_invalidation.h | 2 ++
+ drivers/gpu/drm/xe/xe_pt.c | 14 +++++++++
+ drivers/gpu/drm/xe/xe_pt.h | 3 ++
+ drivers/gpu/drm/xe/xe_vm.c | 32 +++++++++++++++++++++
+ 5 files changed, 73 insertions(+)
+
+diff --git a/drivers/gpu/drm/xe/xe_gt_tlb_invalidation.c b/drivers/gpu/drm/xe/xe_gt_tlb_invalidation.c
+index 9405d83d4db2a..084cbdeba8eaa 100644
+--- a/drivers/gpu/drm/xe/xe_gt_tlb_invalidation.c
++++ b/drivers/gpu/drm/xe/xe_gt_tlb_invalidation.c
+@@ -418,6 +418,28 @@ int xe_gt_tlb_invalidation_range(struct xe_gt *gt,
+ return send_tlb_invalidation(>->uc.guc, fence, action, len);
+ }
+
++/**
++ * xe_gt_tlb_invalidation_vm - Issue a TLB invalidation on this GT for a VM
++ * @gt: graphics tile
++ * @vm: VM to invalidate
++ *
++ * Invalidate entire VM's address space
++ */
++void xe_gt_tlb_invalidation_vm(struct xe_gt *gt, struct xe_vm *vm)
++{
++ struct xe_gt_tlb_invalidation_fence fence;
++ u64 range = 1ull << vm->xe->info.va_bits;
++ int ret;
++
++ xe_gt_tlb_invalidation_fence_init(gt, &fence, true);
++
++ ret = xe_gt_tlb_invalidation_range(gt, &fence, 0, range, vm->usm.asid);
++ if (ret < 0)
++ return;
++
++ xe_gt_tlb_invalidation_fence_wait(&fence);
++}
++
+ /**
+ * xe_gt_tlb_invalidation_vma - Issue a TLB invalidation on this GT for a VMA
+ * @gt: GT structure
+diff --git a/drivers/gpu/drm/xe/xe_gt_tlb_invalidation.h b/drivers/gpu/drm/xe/xe_gt_tlb_invalidation.h
+index 672acfcdf0d70..abe9b03d543e6 100644
+--- a/drivers/gpu/drm/xe/xe_gt_tlb_invalidation.h
++++ b/drivers/gpu/drm/xe/xe_gt_tlb_invalidation.h
+@@ -12,6 +12,7 @@
+
+ struct xe_gt;
+ struct xe_guc;
++struct xe_vm;
+ struct xe_vma;
+
+ int xe_gt_tlb_invalidation_init_early(struct xe_gt *gt);
+@@ -21,6 +22,7 @@ int xe_gt_tlb_invalidation_ggtt(struct xe_gt *gt);
+ int xe_gt_tlb_invalidation_vma(struct xe_gt *gt,
+ struct xe_gt_tlb_invalidation_fence *fence,
+ struct xe_vma *vma);
++void xe_gt_tlb_invalidation_vm(struct xe_gt *gt, struct xe_vm *vm);
+ int xe_gt_tlb_invalidation_range(struct xe_gt *gt,
+ struct xe_gt_tlb_invalidation_fence *fence,
+ u64 start, u64 end, u32 asid);
+diff --git a/drivers/gpu/drm/xe/xe_pt.c b/drivers/gpu/drm/xe/xe_pt.c
+index dc24baa840924..148d90611eebf 100644
+--- a/drivers/gpu/drm/xe/xe_pt.c
++++ b/drivers/gpu/drm/xe/xe_pt.c
+@@ -218,6 +218,20 @@ void xe_pt_destroy(struct xe_pt *pt, u32 flags, struct llist_head *deferred)
+ xe_pt_free(pt);
+ }
+
++/**
++ * xe_pt_clear() - Clear a page-table.
++ * @xe: xe device.
++ * @pt: The page-table.
++ *
++ * Clears page-table by setting to zero.
++ */
++void xe_pt_clear(struct xe_device *xe, struct xe_pt *pt)
++{
++ struct iosys_map *map = &pt->bo->vmap;
++
++ xe_map_memset(xe, map, 0, 0, SZ_4K);
++}
++
+ /**
+ * DOC: Pagetable building
+ *
+diff --git a/drivers/gpu/drm/xe/xe_pt.h b/drivers/gpu/drm/xe/xe_pt.h
+index 9ab386431cadd..8e43912ae8e94 100644
+--- a/drivers/gpu/drm/xe/xe_pt.h
++++ b/drivers/gpu/drm/xe/xe_pt.h
+@@ -13,6 +13,7 @@ struct dma_fence;
+ struct xe_bo;
+ struct xe_device;
+ struct xe_exec_queue;
++struct xe_svm_range;
+ struct xe_sync_entry;
+ struct xe_tile;
+ struct xe_vm;
+@@ -35,6 +36,8 @@ void xe_pt_populate_empty(struct xe_tile *tile, struct xe_vm *vm,
+
+ void xe_pt_destroy(struct xe_pt *pt, u32 flags, struct llist_head *deferred);
+
++void xe_pt_clear(struct xe_device *xe, struct xe_pt *pt);
++
+ int xe_pt_update_ops_prepare(struct xe_tile *tile, struct xe_vma_ops *vops);
+ struct dma_fence *xe_pt_update_ops_run(struct xe_tile *tile,
+ struct xe_vma_ops *vops);
+diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
+index 5956631c0d40a..785b8960050bd 100644
+--- a/drivers/gpu/drm/xe/xe_vm.c
++++ b/drivers/gpu/drm/xe/xe_vm.c
+@@ -8,6 +8,7 @@
+ #include <linux/dma-fence-array.h>
+ #include <linux/nospec.h>
+
++#include <drm/drm_drv.h>
+ #include <drm/drm_exec.h>
+ #include <drm/drm_print.h>
+ #include <drm/ttm/ttm_tt.h>
+@@ -1582,9 +1583,40 @@ struct xe_vm *xe_vm_create(struct xe_device *xe, u32 flags)
+
+ static void xe_vm_close(struct xe_vm *vm)
+ {
++ struct xe_device *xe = vm->xe;
++ bool bound;
++ int idx;
++
++ bound = drm_dev_enter(&xe->drm, &idx);
++
+ down_write(&vm->lock);
++
+ vm->size = 0;
++
++ if (!((vm->flags & XE_VM_FLAG_MIGRATION))) {
++ struct xe_tile *tile;
++ struct xe_gt *gt;
++ u8 id;
++
++ /* Wait for pending binds */
++ dma_resv_wait_timeout(xe_vm_resv(vm),
++ DMA_RESV_USAGE_BOOKKEEP,
++ false, MAX_SCHEDULE_TIMEOUT);
++
++ if (bound) {
++ for_each_tile(tile, xe, id)
++ if (vm->pt_root[id])
++ xe_pt_clear(xe, vm->pt_root[id]);
++
++ for_each_gt(gt, xe, id)
++ xe_gt_tlb_invalidation_vm(gt, vm);
++ }
++ }
++
+ up_write(&vm->lock);
++
++ if (bound)
++ drm_dev_exit(idx);
+ }
+
+ void xe_vm_close_and_put(struct xe_vm *vm)
+--
+2.39.5
+
--- /dev/null
+From 5a3e69febd14d6dba17375c62fe6bb1ce3cee418 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Feb 2025 17:02:55 -0800
+Subject: drm/xe/oa: Ensure that polled read returns latest data
+
+From: Umesh Nerlige Ramappa <umesh.nerlige.ramappa@intel.com>
+
+[ Upstream commit 98c9d27ab30aa9c6451d3a34e6e297171f273e51 ]
+
+In polled mode, user calls poll() for read data to be available before
+performing a read(). In the duration between these 2 calls, there may be
+new data available in the OA buffer. To ensure user reads all available
+data, check for latest data in the OA buffer in polled read.
+
+Signed-off-by: Umesh Nerlige Ramappa <umesh.nerlige.ramappa@intel.com>
+Reviewed-by: Ashutosh Dixit <ashutosh.dixit@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250212010255.1423343-1-umesh.nerlige.ramappa@intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/xe_oa.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/gpu/drm/xe/xe_oa.c b/drivers/gpu/drm/xe/xe_oa.c
+index eb6cd91e1e226..abf37d9ab2212 100644
+--- a/drivers/gpu/drm/xe/xe_oa.c
++++ b/drivers/gpu/drm/xe/xe_oa.c
+@@ -548,6 +548,7 @@ static ssize_t xe_oa_read(struct file *file, char __user *buf,
+ mutex_unlock(&stream->stream_lock);
+ } while (!offset && !ret);
+ } else {
++ xe_oa_buffer_check_unlocked(stream);
+ mutex_lock(&stream->stream_lock);
+ ret = __xe_oa_read(stream, buf, count, &offset);
+ mutex_unlock(&stream->stream_lock);
+--
+2.39.5
+
--- /dev/null
+From 50a29a8692e12200b2ac7f88fa3bdd29093f10a3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 24 Feb 2025 15:58:06 +0530
+Subject: drm/xe/pf: Create a link between PF and VF devices
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Satyanarayana K V P <satyanarayana.k.v.p@intel.com>
+
+[ Upstream commit 8c0aff7d92e2be25717669eb65a81a89740a24f2 ]
+
+When both PF and VF devices are enabled on the host, they
+resume simultaneously during system resume.
+
+However, the PF must finish provisioning the VF before any
+VFs can successfully resume.
+
+Establish a parent-child device link between the PF and VF
+devices to ensure the correct order of resumption.
+
+V4 -> V5:
+- Added missing break in the error condition.
+V3 -> V4:
+- Made xe_pci_pf_get_vf_dev() as a static function and updated
+ input parameter types.
+- Updated xe_sriov_warn() to xe_sriov_abort() when VF device
+ cannot be found.
+V2 -> V3:
+- Added function documentation for xe_pci_pf_get_vf_dev().
+- Added assertion if not called from PF.
+V1 -> V2:
+- Added a helper function to get VF pci_dev.
+- Updated xe_sriov_notice() to xe_sriov_warn() if vf pci_dev
+ is not found.
+
+Signed-off-by: Satyanarayana K V P <satyanarayana.k.v.p@intel.com>
+Cc: Michał Wajdeczko <michal.wajdeczko@intel.com>
+Cc: Michał Winiarski <michal.winiarski@intel.com>
+Cc: Piotr Piórkowski <piotr.piorkowski@intel.com>
+Reviewed-by: Piotr Piorkowski <piotr.piorkowski@intel.com>
+Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250224102807.11065-2-satyanarayana.k.v.p@intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/xe_pci_sriov.c | 51 +++++++++++++++++++++++++++++++
+ 1 file changed, 51 insertions(+)
+
+diff --git a/drivers/gpu/drm/xe/xe_pci_sriov.c b/drivers/gpu/drm/xe/xe_pci_sriov.c
+index aaceee748287e..09ee8a06fe2ed 100644
+--- a/drivers/gpu/drm/xe/xe_pci_sriov.c
++++ b/drivers/gpu/drm/xe/xe_pci_sriov.c
+@@ -62,6 +62,55 @@ static void pf_reset_vfs(struct xe_device *xe, unsigned int num_vfs)
+ xe_gt_sriov_pf_control_trigger_flr(gt, n);
+ }
+
++static struct pci_dev *xe_pci_pf_get_vf_dev(struct xe_device *xe, unsigned int vf_id)
++{
++ struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
++
++ xe_assert(xe, IS_SRIOV_PF(xe));
++
++ /* caller must use pci_dev_put() */
++ return pci_get_domain_bus_and_slot(pci_domain_nr(pdev->bus),
++ pdev->bus->number,
++ pci_iov_virtfn_devfn(pdev, vf_id));
++}
++
++static void pf_link_vfs(struct xe_device *xe, int num_vfs)
++{
++ struct pci_dev *pdev_pf = to_pci_dev(xe->drm.dev);
++ struct device_link *link;
++ struct pci_dev *pdev_vf;
++ unsigned int n;
++
++ /*
++ * When both PF and VF devices are enabled on the host, during system
++ * resume they are resuming in parallel.
++ *
++ * But PF has to complete the provision of VF first to allow any VFs to
++ * successfully resume.
++ *
++ * Create a parent-child device link between PF and VF devices that will
++ * enforce correct resume order.
++ */
++ for (n = 1; n <= num_vfs; n++) {
++ pdev_vf = xe_pci_pf_get_vf_dev(xe, n - 1);
++
++ /* unlikely, something weird is happening, abort */
++ if (!pdev_vf) {
++ xe_sriov_err(xe, "Cannot find VF%u device, aborting link%s creation!\n",
++ n, str_plural(num_vfs));
++ break;
++ }
++
++ link = device_link_add(&pdev_vf->dev, &pdev_pf->dev,
++ DL_FLAG_AUTOREMOVE_CONSUMER);
++ /* unlikely and harmless, continue with other VFs */
++ if (!link)
++ xe_sriov_notice(xe, "Failed linking VF%u\n", n);
++
++ pci_dev_put(pdev_vf);
++ }
++}
++
+ static int pf_enable_vfs(struct xe_device *xe, int num_vfs)
+ {
+ struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
+@@ -92,6 +141,8 @@ static int pf_enable_vfs(struct xe_device *xe, int num_vfs)
+ if (err < 0)
+ goto failed;
+
++ pf_link_vfs(xe, num_vfs);
++
+ xe_sriov_info(xe, "Enabled %u of %u VF%s\n",
+ num_vfs, total_vfs, str_plural(total_vfs));
+ return num_vfs;
+--
+2.39.5
+
--- /dev/null
+From d09443dcd1dcb2ac89b9ae0910875a1d44174575 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 25 Jan 2025 22:55:05 +0100
+Subject: drm/xe/pf: Move VFs reprovisioning to worker
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Michal Wajdeczko <michal.wajdeczko@intel.com>
+
+[ Upstream commit a4d1c5d0b99b75263a5626d2e52d569db3844b33 ]
+
+Since the GuC is reset during GT reset, we need to re-send the
+entire SR-IOV provisioning configuration to the GuC. But since
+this whole configuration is protected by the PF master mutex and
+we can't avoid making allocations under this mutex (like during
+LMEM provisioning), we can't do this reprovisioning from gt-reset
+path if we want to be reclaim-safe. Move VFs reprovisioning to a
+async worker that we will start from the gt-reset path.
+
+Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
+Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
+Cc: Matthew Brost <matthew.brost@intel.com>
+Reviewed-by: Michał Winiarski <michal.winiarski@intel.com>
+Reviewed-by: Stuart Summers <stuart.summers@intel.com>
+Reviewed-by: Matthew Brost <matthew.brost@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250125215505.720-1-michal.wajdeczko@intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/xe_gt_sriov_pf.c | 43 +++++++++++++++++++++--
+ drivers/gpu/drm/xe/xe_gt_sriov_pf_types.h | 10 ++++++
+ 2 files changed, 51 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf.c b/drivers/gpu/drm/xe/xe_gt_sriov_pf.c
+index b80930a6bc1a2..c08efca6420e7 100644
+--- a/drivers/gpu/drm/xe/xe_gt_sriov_pf.c
++++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf.c
+@@ -15,7 +15,11 @@
+ #include "xe_gt_sriov_pf_helpers.h"
+ #include "xe_gt_sriov_pf_migration.h"
+ #include "xe_gt_sriov_pf_service.h"
++#include "xe_gt_sriov_printk.h"
+ #include "xe_mmio.h"
++#include "xe_pm.h"
++
++static void pf_worker_restart_func(struct work_struct *w);
+
+ /*
+ * VF's metadata is maintained in the flexible array where:
+@@ -41,6 +45,11 @@ static int pf_alloc_metadata(struct xe_gt *gt)
+ return 0;
+ }
+
++static void pf_init_workers(struct xe_gt *gt)
++{
++ INIT_WORK(>->sriov.pf.workers.restart, pf_worker_restart_func);
++}
++
+ /**
+ * xe_gt_sriov_pf_init_early - Prepare SR-IOV PF data structures on PF.
+ * @gt: the &xe_gt to initialize
+@@ -65,6 +74,8 @@ int xe_gt_sriov_pf_init_early(struct xe_gt *gt)
+ if (err)
+ return err;
+
++ pf_init_workers(gt);
++
+ return 0;
+ }
+
+@@ -161,6 +172,35 @@ void xe_gt_sriov_pf_sanitize_hw(struct xe_gt *gt, unsigned int vfid)
+ pf_clear_vf_scratch_regs(gt, vfid);
+ }
+
++static void pf_restart(struct xe_gt *gt)
++{
++ struct xe_device *xe = gt_to_xe(gt);
++
++ xe_pm_runtime_get(xe);
++ xe_gt_sriov_pf_config_restart(gt);
++ xe_gt_sriov_pf_control_restart(gt);
++ xe_pm_runtime_put(xe);
++
++ xe_gt_sriov_dbg(gt, "restart completed\n");
++}
++
++static void pf_worker_restart_func(struct work_struct *w)
++{
++ struct xe_gt *gt = container_of(w, typeof(*gt), sriov.pf.workers.restart);
++
++ pf_restart(gt);
++}
++
++static void pf_queue_restart(struct xe_gt *gt)
++{
++ struct xe_device *xe = gt_to_xe(gt);
++
++ xe_gt_assert(gt, IS_SRIOV_PF(xe));
++
++ if (!queue_work(xe->sriov.wq, >->sriov.pf.workers.restart))
++ xe_gt_sriov_dbg(gt, "restart already in queue!\n");
++}
++
+ /**
+ * xe_gt_sriov_pf_restart - Restart SR-IOV support after a GT reset.
+ * @gt: the &xe_gt
+@@ -169,6 +209,5 @@ void xe_gt_sriov_pf_sanitize_hw(struct xe_gt *gt, unsigned int vfid)
+ */
+ void xe_gt_sriov_pf_restart(struct xe_gt *gt)
+ {
+- xe_gt_sriov_pf_config_restart(gt);
+- xe_gt_sriov_pf_control_restart(gt);
++ pf_queue_restart(gt);
+ }
+diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_types.h b/drivers/gpu/drm/xe/xe_gt_sriov_pf_types.h
+index 0426b1a77069a..a64a6835ad656 100644
+--- a/drivers/gpu/drm/xe/xe_gt_sriov_pf_types.h
++++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_types.h
+@@ -35,8 +35,17 @@ struct xe_gt_sriov_metadata {
+ struct xe_gt_sriov_state_snapshot snapshot;
+ };
+
++/**
++ * struct xe_gt_sriov_pf_workers - GT level workers used by the PF.
++ */
++struct xe_gt_sriov_pf_workers {
++ /** @restart: worker that executes actions post GT reset */
++ struct work_struct restart;
++};
++
+ /**
+ * struct xe_gt_sriov_pf - GT level PF virtualization data.
++ * @workers: workers data.
+ * @service: service data.
+ * @control: control data.
+ * @policy: policy data.
+@@ -45,6 +54,7 @@ struct xe_gt_sriov_metadata {
+ * @vfs: metadata for all VFs.
+ */
+ struct xe_gt_sriov_pf {
++ struct xe_gt_sriov_pf_workers workers;
+ struct xe_gt_sriov_pf_service service;
+ struct xe_gt_sriov_pf_control control;
+ struct xe_gt_sriov_pf_policy policy;
+--
+2.39.5
+
--- /dev/null
+From 92a348b3db75e258d99bdb6cf2421c31fa16134e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Feb 2025 16:50:34 +0100
+Subject: drm/xe/pf: Release all VFs configs on device removal
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Michal Wajdeczko <michal.wajdeczko@intel.com>
+
+[ Upstream commit 611160b02a40ce3f60ab94eea85b394dca1cafd2 ]
+
+If we try to manually provision VFs using debugfs and then we
+try to unload the driver, we will see complains like:
+
+ [ ] Memory manager not clean during takedown.
+ [ ] RIP: 0010:drm_mm_takedown+0x3f/0x100
+ [ ] [drm:drm_mm_takedown] *ERROR* node [fedff000 + 00001000]: inserted at
+ drm_mm_insert_node_in_range+0x2bd/0x520
+ xe_ggtt_node_insert+0x52/0x90 [xe]
+ pf_provision_vf_ggtt+0x1fa/0xac0 [xe]
+ xe_gt_sriov_pf_config_set_ggtt+0x79/0x7a0 [xe]
+ ggtt_set+0x53/0x80 [xe]
+ simple_attr_write_xsigned.isra.0+0xd2/0x150
+ simple_attr_write+0x14/0x30
+ debugfs_attr_write+0x4e/0x80
+
+ [ ] xe 0000:00:02.0: [drm] *ERROR* GT0: GUC ID manager unclean (1/65535)
+ [ ] xe 0000:00:02.0: [drm] GT0: total 65535
+ [ ] xe 0000:00:02.0: [drm] GT0: used 1
+ [ ] xe 0000:00:02.0: [drm] GT0: range 65534..65534 (1)
+
+ [ ] xe 0000:00:02.0: [drm] *ERROR* GT0: GuC doorbells manager unclean (1/256)
+ [ ] xe 0000:00:02.0: [drm] GT0: count: 256
+ [ ] xe 0000:00:02.0: [drm] GT0: available range: 1..255 (255)
+ [ ] xe 0000:00:02.0: [drm] GT0: available total: 255
+ [ ] xe 0000:00:02.0: [drm] GT0: reserved range: 0..0 (1)
+ [ ] xe 0000:00:02.0: [drm] GT0: reserved total: 1
+
+This could be easily fixed by adding config release action.
+
+Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
+Cc: Piotr Piórkowski <piotr.piorkowski@intel.com>
+Reviewed-by: Piotr Piórkowski <piotr.piorkowski@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250211155034.1028-1-michal.wajdeczko@intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/xe_gt_sriov_pf.c | 6 +++++
+ drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c | 29 ++++++++++++++++++++++
+ drivers/gpu/drm/xe/xe_gt_sriov_pf_config.h | 1 +
+ 3 files changed, 36 insertions(+)
+
+diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf.c b/drivers/gpu/drm/xe/xe_gt_sriov_pf.c
+index 6f906c8e8108b..b80930a6bc1a2 100644
+--- a/drivers/gpu/drm/xe/xe_gt_sriov_pf.c
++++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf.c
+@@ -78,6 +78,12 @@ int xe_gt_sriov_pf_init_early(struct xe_gt *gt)
+ */
+ int xe_gt_sriov_pf_init(struct xe_gt *gt)
+ {
++ int err;
++
++ err = xe_gt_sriov_pf_config_init(gt);
++ if (err)
++ return err;
++
+ return xe_gt_sriov_pf_migration_init(gt);
+ }
+
+diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c
+index 4bd255adfb401..aaca54b40091f 100644
+--- a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c
++++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c
+@@ -2320,6 +2320,35 @@ int xe_gt_sriov_pf_config_restore(struct xe_gt *gt, unsigned int vfid,
+ return err;
+ }
+
++static void fini_config(void *arg)
++{
++ struct xe_gt *gt = arg;
++ struct xe_device *xe = gt_to_xe(gt);
++ unsigned int n, total_vfs = xe_sriov_pf_get_totalvfs(xe);
++
++ mutex_lock(xe_gt_sriov_pf_master_mutex(gt));
++ for (n = 1; n <= total_vfs; n++)
++ pf_release_vf_config(gt, n);
++ mutex_unlock(xe_gt_sriov_pf_master_mutex(gt));
++}
++
++/**
++ * xe_gt_sriov_pf_config_init - Initialize SR-IOV configuration data.
++ * @gt: the &xe_gt
++ *
++ * This function can only be called on PF.
++ *
++ * Return: 0 on success or a negative error code on failure.
++ */
++int xe_gt_sriov_pf_config_init(struct xe_gt *gt)
++{
++ struct xe_device *xe = gt_to_xe(gt);
++
++ xe_gt_assert(gt, IS_SRIOV_PF(xe));
++
++ return devm_add_action_or_reset(xe->drm.dev, fini_config, gt);
++}
++
+ /**
+ * xe_gt_sriov_pf_config_restart - Restart SR-IOV configurations after a GT reset.
+ * @gt: the &xe_gt
+diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.h b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.h
+index f894e9d4abba2..513e6512a575b 100644
+--- a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.h
++++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.h
+@@ -63,6 +63,7 @@ int xe_gt_sriov_pf_config_restore(struct xe_gt *gt, unsigned int vfid,
+
+ bool xe_gt_sriov_pf_config_is_empty(struct xe_gt *gt, unsigned int vfid);
+
++int xe_gt_sriov_pf_config_init(struct xe_gt *gt);
+ void xe_gt_sriov_pf_config_restart(struct xe_gt *gt);
+
+ int xe_gt_sriov_pf_config_print_ggtt(struct xe_gt *gt, struct drm_printer *p);
+--
+2.39.5
+
--- /dev/null
+From e8a49c2490f5523645df9e30f0c99bec2fc0f427 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jan 2025 20:59:47 +0100
+Subject: drm/xe/pf: Reset GuC VF config when unprovisioning critical resource
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Michal Wajdeczko <michal.wajdeczko@intel.com>
+
+[ Upstream commit 33f17e2cbd930a2a00eb007d9b241b6db010a880 ]
+
+GuC firmware counts received VF configuration KLVs and may start
+validation of the complete VF config even if some resources where
+unprovisioned in the meantime, leading to unexpected errors like:
+
+ $ echo 1 | sudo tee /sys/kernel/debug/dri/0000:00:02.0/gt0/vf1/contexts_quota
+ $ echo 0 | sudo tee /sys/kernel/debug/dri/0000:00:02.0/gt0/vf1/contexts_quota
+ $ echo 1 | sudo tee /sys/kernel/debug/dri/0000:00:02.0/gt0/vf1/doorbells_quota
+ $ echo 0 | sudo tee /sys/kernel/debug/dri/0000:00:02.0/gt0/vf1/doorbells_quota
+ $ echo 1 | sudo tee /sys/kernel/debug/dri/0000:00:02.0/gt0/vf1/ggtt_quota
+ tee: '/sys/kernel/debug/dri/0000:00:02.0/gt0/vf1/ggtt_quota': Input/output error
+
+To mitigate this problem trigger explicit VF config reset after
+unprovisioning any of the critical resources (GGTT, context or
+doorbell IDs) that GuC is monitoring.
+
+Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
+Reviewed-by: Michał Winiarski <michal.winiarski@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250129195947.764-3-michal.wajdeczko@intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c | 37 +++++++++++++++++++---
+ 1 file changed, 33 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c
+index aaca54b40091f..27f309e3a76e6 100644
+--- a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c
++++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c
+@@ -336,6 +336,26 @@ static int pf_push_full_vf_config(struct xe_gt *gt, unsigned int vfid)
+ return err;
+ }
+
++static int pf_push_vf_cfg(struct xe_gt *gt, unsigned int vfid, bool reset)
++{
++ int err = 0;
++
++ xe_gt_assert(gt, vfid);
++ lockdep_assert_held(xe_gt_sriov_pf_master_mutex(gt));
++
++ if (reset)
++ err = pf_send_vf_cfg_reset(gt, vfid);
++ if (!err)
++ err = pf_push_full_vf_config(gt, vfid);
++
++ return err;
++}
++
++static int pf_refresh_vf_cfg(struct xe_gt *gt, unsigned int vfid)
++{
++ return pf_push_vf_cfg(gt, vfid, true);
++}
++
+ static u64 pf_get_ggtt_alignment(struct xe_gt *gt)
+ {
+ struct xe_device *xe = gt_to_xe(gt);
+@@ -432,6 +452,10 @@ static int pf_provision_vf_ggtt(struct xe_gt *gt, unsigned int vfid, u64 size)
+ return err;
+
+ pf_release_vf_config_ggtt(gt, config);
++
++ err = pf_refresh_vf_cfg(gt, vfid);
++ if (unlikely(err))
++ return err;
+ }
+ xe_gt_assert(gt, !xe_ggtt_node_allocated(config->ggtt_region));
+
+@@ -757,6 +781,10 @@ static int pf_provision_vf_ctxs(struct xe_gt *gt, unsigned int vfid, u32 num_ctx
+ return ret;
+
+ pf_release_config_ctxs(gt, config);
++
++ ret = pf_refresh_vf_cfg(gt, vfid);
++ if (unlikely(ret))
++ return ret;
+ }
+
+ if (!num_ctxs)
+@@ -1054,6 +1082,10 @@ static int pf_provision_vf_dbs(struct xe_gt *gt, unsigned int vfid, u32 num_dbs)
+ return ret;
+
+ pf_release_config_dbs(gt, config);
++
++ ret = pf_refresh_vf_cfg(gt, vfid);
++ if (unlikely(ret))
++ return ret;
+ }
+
+ if (!num_dbs)
+@@ -2085,10 +2117,7 @@ int xe_gt_sriov_pf_config_push(struct xe_gt *gt, unsigned int vfid, bool refresh
+ xe_gt_assert(gt, vfid);
+
+ mutex_lock(xe_gt_sriov_pf_master_mutex(gt));
+- if (refresh)
+- err = pf_send_vf_cfg_reset(gt, vfid);
+- if (!err)
+- err = pf_push_full_vf_config(gt, vfid);
++ err = pf_push_vf_cfg(gt, vfid, refresh);
+ mutex_unlock(xe_gt_sriov_pf_master_mutex(gt));
+
+ if (unlikely(err)) {
+--
+2.39.5
+
--- /dev/null
+From 41485a1ec895d7f1b60e3f166300e673cf3d5906 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 10 Jan 2025 16:01:37 -0500
+Subject: drm/xe: Reject BO eviction if BO is bound to current VM
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Oak Zeng <oak.zeng@intel.com>
+
+[ Upstream commit 0af944f0e3082ff517958b1cea76fb9b8cb379dd ]
+
+This is a follow up fix for
+https://patchwork.freedesktop.org/patch/msgid/20241203021929.1919730-1-oak.zeng@intel.com
+The overall goal is to fail vm_bind when there is memory pressure. See more
+details in the commit message of above patch. Abbove patch fixes the issue
+when user pass in a vm_id parameter during gem_create. If user doesn't pass
+in a vm_id during gem_create, above patch doesn't help.
+
+This patch further reject BO eviction (which could be triggered by bo validation)
+if BO is bound to the current VM. vm_bind could fail due to the eviction failure.
+The BO to VM reverse mapping structure is used to determine whether BO is bound
+to VM.
+
+v2:
+Move vm_bo definition from function scope to if(evict) clause (Thomas)
+Further constraint the condition by adding ctx->resv (Thomas)
+Add a short comment describe the change.
+
+Suggested-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
+Signed-off-by: Oak Zeng <oak.zeng@intel.com>
+Reviewed-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
+Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250110210137.3181576-1-oak.zeng@intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/xe_bo.c | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c
+index d1eb87cb178bd..2070aa12059ce 100644
+--- a/drivers/gpu/drm/xe/xe_bo.c
++++ b/drivers/gpu/drm/xe/xe_bo.c
+@@ -713,6 +713,21 @@ static int xe_bo_move(struct ttm_buffer_object *ttm_bo, bool evict,
+ goto out;
+ }
+
++ /* Reject BO eviction if BO is bound to current VM. */
++ if (evict && ctx->resv) {
++ struct drm_gpuvm_bo *vm_bo;
++
++ drm_gem_for_each_gpuvm_bo(vm_bo, &bo->ttm.base) {
++ struct xe_vm *vm = gpuvm_to_vm(vm_bo->vm);
++
++ if (xe_vm_resv(vm) == ctx->resv &&
++ xe_vm_in_preempt_fence_mode(vm)) {
++ ret = -EBUSY;
++ goto out;
++ }
++ }
++ }
++
+ /*
+ * Failed multi-hop where the old_mem is still marked as
+ * TTM_PL_FLAG_TEMPORARY, should just be a dummy move.
+--
+2.39.5
+
--- /dev/null
+From 6c2a81d91f3b8827778ca792bd98ec31afb2bf55 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jan 2025 16:37:13 +0100
+Subject: drm/xe/relay: Don't use GFP_KERNEL for new transactions
+
+From: Michal Wajdeczko <michal.wajdeczko@intel.com>
+
+[ Upstream commit 78d5d1e20d1de9422f013338a0f2311448588ba7 ]
+
+VFs use a relay transaction during the resume/reset flow and use
+of the GFP_KERNEL flag may conflict with the reclaim:
+
+ -> #0 (fs_reclaim){+.+.}-{0:0}:
+ [ ] __lock_acquire+0x1874/0x2bc0
+ [ ] lock_acquire+0xd2/0x310
+ [ ] fs_reclaim_acquire+0xc5/0x100
+ [ ] mempool_alloc_noprof+0x5c/0x1b0
+ [ ] __relay_get_transaction+0xdc/0xa10 [xe]
+ [ ] relay_send_to+0x251/0xe50 [xe]
+ [ ] xe_guc_relay_send_to_pf+0x79/0x3a0 [xe]
+ [ ] xe_gt_sriov_vf_connect+0x90/0x4d0 [xe]
+ [ ] xe_uc_init_hw+0x157/0x3b0 [xe]
+ [ ] do_gt_restart+0x1ae/0x650 [xe]
+ [ ] xe_gt_resume+0xb6/0x120 [xe]
+ [ ] xe_pm_runtime_resume+0x15b/0x370 [xe]
+ [ ] xe_pci_runtime_resume+0x73/0x90 [xe]
+ [ ] pci_pm_runtime_resume+0xa0/0x100
+ [ ] __rpm_callback+0x4d/0x170
+ [ ] rpm_callback+0x64/0x70
+ [ ] rpm_resume+0x594/0x790
+ [ ] __pm_runtime_resume+0x4e/0x90
+ [ ] xe_pm_runtime_get_ioctl+0x9c/0x160 [xe]
+
+Since we have a preallocated pool of relay transactions, which
+should cover all our normal relay use cases, we may use the
+GFP_NOWAIT flag when allocating new outgoing transactions.
+
+Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
+Tested-by: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
+Reviewed-by: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250131153713.808-1-michal.wajdeczko@intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/xe_guc_relay.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/xe/xe_guc_relay.c b/drivers/gpu/drm/xe/xe_guc_relay.c
+index 8f62de026724c..e5dc94f3e6181 100644
+--- a/drivers/gpu/drm/xe/xe_guc_relay.c
++++ b/drivers/gpu/drm/xe/xe_guc_relay.c
+@@ -225,7 +225,7 @@ __relay_get_transaction(struct xe_guc_relay *relay, bool incoming, u32 remote, u
+ * with CTB lock held which is marked as used in the reclaim path.
+ * Btw, that's one of the reason why we use mempool here!
+ */
+- txn = mempool_alloc(&relay->pool, incoming ? GFP_ATOMIC : GFP_KERNEL);
++ txn = mempool_alloc(&relay->pool, incoming ? GFP_ATOMIC : GFP_NOWAIT);
+ if (!txn)
+ return ERR_PTR(-ENOMEM);
+
+--
+2.39.5
+
--- /dev/null
+From 6aed486a81c20855106f1f93eabf04b610a23f63 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Mar 2025 17:26:26 -0800
+Subject: drm/xe: Retry BO allocation
+
+From: Matthew Brost <matthew.brost@intel.com>
+
+[ Upstream commit 1d724a2f1b2c3f0cba4975784a808482e0631adf ]
+
+TTM doesn't support fair eviction via WW locking, this mitigated in by
+using retry loops in exec and preempt rebind worker. Extend this retry
+loop to BO allocation. Once TTM supports fair eviction this patch can be
+reverted.
+
+v4:
+ - Keep line break (Stuart)
+
+Signed-off-by: Matthew Brost <matthew.brost@intel.com>
+Reviewed-by: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
+Reviewed-by: Stuart Summers <stuart.summers@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250306012657.3505757-2-matthew.brost@intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/xe_bo.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c
+index 3f5391d416d46..d1eb87cb178bd 100644
+--- a/drivers/gpu/drm/xe/xe_bo.c
++++ b/drivers/gpu/drm/xe/xe_bo.c
+@@ -2142,6 +2142,7 @@ int xe_gem_create_ioctl(struct drm_device *dev, void *data,
+ struct xe_file *xef = to_xe_file(file);
+ struct drm_xe_gem_create *args = data;
+ struct xe_vm *vm = NULL;
++ ktime_t end = 0;
+ struct xe_bo *bo;
+ unsigned int bo_flags;
+ u32 handle;
+@@ -2214,6 +2215,10 @@ int xe_gem_create_ioctl(struct drm_device *dev, void *data,
+ vm = xe_vm_lookup(xef, args->vm_id);
+ if (XE_IOCTL_DBG(xe, !vm))
+ return -ENOENT;
++ }
++
++retry:
++ if (vm) {
+ err = xe_vm_lock(vm, true);
+ if (err)
+ goto out_vm;
+@@ -2227,6 +2232,8 @@ int xe_gem_create_ioctl(struct drm_device *dev, void *data,
+
+ if (IS_ERR(bo)) {
+ err = PTR_ERR(bo);
++ if (xe_vm_validate_should_retry(NULL, err, &end))
++ goto retry;
+ goto out_vm;
+ }
+
+--
+2.39.5
+
--- /dev/null
+From 6b10d835d233cc7310b4514c8e11938fa2d3387e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 20 Dec 2024 20:41:54 +0100
+Subject: drm/xe/sa: Always call drm_suballoc_manager_fini()
+
+From: Michal Wajdeczko <michal.wajdeczko@intel.com>
+
+[ Upstream commit 9cd3f4efc870463f17f6c29114c61fb6bfcaa291 ]
+
+After successful call to drm_suballoc_manager_init() we should
+make sure to call drm_suballoc_manager_fini() as it may include
+some cleanup code even if we didn't start using it for real.
+
+As we can abort init() early due to kvzalloc() failure, we should
+either explicitly call drm_suballoc_manager_fini() or, even better,
+postpone drm_suballoc_manager_init() once we finish all other
+preparation steps, so we can rely on fini() that will do cleanup.
+
+Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
+Cc: Matthew Brost <matthew.brost@intel.com>
+Reviewed-by: Matthew Brost <matthew.brost@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20241220194205.995-2-michal.wajdeczko@intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/xe_sa.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/xe/xe_sa.c b/drivers/gpu/drm/xe/xe_sa.c
+index e055bed7ae555..4e7aba445ebc8 100644
+--- a/drivers/gpu/drm/xe/xe_sa.c
++++ b/drivers/gpu/drm/xe/xe_sa.c
+@@ -57,8 +57,6 @@ struct xe_sa_manager *xe_sa_bo_manager_init(struct xe_tile *tile, u32 size, u32
+ }
+ sa_manager->bo = bo;
+ sa_manager->is_iomem = bo->vmap.is_iomem;
+-
+- drm_suballoc_manager_init(&sa_manager->base, managed_size, align);
+ sa_manager->gpu_addr = xe_bo_ggtt_addr(bo);
+
+ if (bo->vmap.is_iomem) {
+@@ -72,6 +70,7 @@ struct xe_sa_manager *xe_sa_bo_manager_init(struct xe_tile *tile, u32 size, u32
+ memset(sa_manager->cpu_ptr, 0, bo->ttm.base.size);
+ }
+
++ drm_suballoc_manager_init(&sa_manager->base, managed_size, align);
+ ret = drmm_add_action_or_reset(&xe->drm, xe_sa_bo_manager_fini,
+ sa_manager);
+ if (ret)
+--
+2.39.5
+
--- /dev/null
+From b746540489d60b19c998113ff8867db61ff0e3bb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 13 Feb 2025 11:29:01 -0800
+Subject: drm/xe: Stop ignoring errors from xe_ttm_stolen_mgr_init()
+
+From: Lucas De Marchi <lucas.demarchi@intel.com>
+
+[ Upstream commit ff57025c358603555f1e0ae0d50282a460433594 ]
+
+Make sure to differentiate normal behavior, e.g. there's no stolen, from
+allocation errors or failure to initialize lower layers.
+
+Reviewed-by: Francois Dugast <francois.dugast@intel.com>
+Reviewed-by: Himal Prasad Ghimiray <himal.prasad.ghimiray@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250213192909.996148-5-lucas.demarchi@intel.com
+Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/xe_device.c | 4 +++-
+ drivers/gpu/drm/xe/xe_ttm_stolen_mgr.c | 17 +++++++++--------
+ drivers/gpu/drm/xe/xe_ttm_stolen_mgr.h | 2 +-
+ 3 files changed, 13 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
+index 4e1839b483a00..e22f29ac96631 100644
+--- a/drivers/gpu/drm/xe/xe_device.c
++++ b/drivers/gpu/drm/xe/xe_device.c
+@@ -722,7 +722,9 @@ int xe_device_probe(struct xe_device *xe)
+ }
+
+ /* Allocate and map stolen after potential VRAM resize */
+- xe_ttm_stolen_mgr_init(xe);
++ err = xe_ttm_stolen_mgr_init(xe);
++ if (err)
++ return err;
+
+ /*
+ * Now that GT is initialized (TTM in particular),
+diff --git a/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.c b/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.c
+index d414421f8c131..d9c9d2547aadf 100644
+--- a/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.c
++++ b/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.c
+@@ -207,17 +207,16 @@ static u64 detect_stolen(struct xe_device *xe, struct xe_ttm_stolen_mgr *mgr)
+ #endif
+ }
+
+-void xe_ttm_stolen_mgr_init(struct xe_device *xe)
++int xe_ttm_stolen_mgr_init(struct xe_device *xe)
+ {
+- struct xe_ttm_stolen_mgr *mgr = drmm_kzalloc(&xe->drm, sizeof(*mgr), GFP_KERNEL);
+ struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
++ struct xe_ttm_stolen_mgr *mgr;
+ u64 stolen_size, io_size;
+ int err;
+
+- if (!mgr) {
+- drm_dbg_kms(&xe->drm, "Stolen mgr init failed\n");
+- return;
+- }
++ mgr = drmm_kzalloc(&xe->drm, sizeof(*mgr), GFP_KERNEL);
++ if (!mgr)
++ return -ENOMEM;
+
+ if (IS_SRIOV_VF(xe))
+ stolen_size = 0;
+@@ -230,7 +229,7 @@ void xe_ttm_stolen_mgr_init(struct xe_device *xe)
+
+ if (!stolen_size) {
+ drm_dbg_kms(&xe->drm, "No stolen memory support\n");
+- return;
++ return 0;
+ }
+
+ /*
+@@ -246,7 +245,7 @@ void xe_ttm_stolen_mgr_init(struct xe_device *xe)
+ io_size, PAGE_SIZE);
+ if (err) {
+ drm_dbg_kms(&xe->drm, "Stolen mgr init failed: %i\n", err);
+- return;
++ return err;
+ }
+
+ drm_dbg_kms(&xe->drm, "Initialized stolen memory support with %llu bytes\n",
+@@ -254,6 +253,8 @@ void xe_ttm_stolen_mgr_init(struct xe_device *xe)
+
+ if (io_size)
+ mgr->mapping = devm_ioremap_wc(&pdev->dev, mgr->io_base, io_size);
++
++ return 0;
+ }
+
+ u64 xe_ttm_stolen_io_offset(struct xe_bo *bo, u32 offset)
+diff --git a/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.h b/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.h
+index 1777245ff8101..8e877d1e839bd 100644
+--- a/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.h
++++ b/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.h
+@@ -12,7 +12,7 @@ struct ttm_resource;
+ struct xe_bo;
+ struct xe_device;
+
+-void xe_ttm_stolen_mgr_init(struct xe_device *xe);
++int xe_ttm_stolen_mgr_init(struct xe_device *xe);
+ int xe_ttm_stolen_io_mem_reserve(struct xe_device *xe, struct ttm_resource *mem);
+ bool xe_ttm_stolen_cpu_access_needs_ggtt(struct xe_device *xe);
+ u64 xe_ttm_stolen_io_offset(struct xe_bo *bo, u32 offset);
+--
+2.39.5
+
--- /dev/null
+From e19a89aafc30e1f1fa633b9da4d0ca620f496ce9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 14 Jan 2025 22:13:47 +0100
+Subject: drm/xe/vf: Perform early GT MMIO initialization to read GMDID
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Michal Wajdeczko <michal.wajdeczko@intel.com>
+
+[ Upstream commit 13265fe7426ec9ba5aa86baab913417ca361e8a4 ]
+
+VFs need to communicate with the GuC to obtain the GMDID value
+and existing GuC functions used for that assume that the GT has
+it's MMIO members already setup. However, due to recent refactoring
+the gt->mmio is initialized later, and any attempt by the VF to use
+xe_mmio_read|write() from GuC functions will lead to NPD crash due
+to unset MMIO register address:
+
+[] xe 0000:00:02.1: [drm] Running in SR-IOV VF mode
+[] xe 0000:00:02.1: [drm] GT0: sending H2G MMIO 0x5507
+[] BUG: unable to handle page fault for address: 0000000000190240
+
+Since we are already tweaking the id and type of the primary GT to
+mimic it's a Media GT before initializing the GuC communication,
+we can also call xe_gt_mmio_init() to perform early setup of the
+gt->mmio which will make those GuC functions work again.
+
+Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
+Cc: Matt Roper <matthew.d.roper@intel.com>
+Cc: Piotr Piórkowski <piotr.piorkowski@intel.com>
+Reviewed-by: Piotr Piórkowski <piotr.piorkowski@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250114211347.1083-1-michal.wajdeczko@intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/xe_pci.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c
+index 9b8813a518d72..d92b2e5885b98 100644
+--- a/drivers/gpu/drm/xe/xe_pci.c
++++ b/drivers/gpu/drm/xe/xe_pci.c
+@@ -490,6 +490,7 @@ static void read_gmdid(struct xe_device *xe, enum xe_gmdid_type type, u32 *ver,
+ gt->info.type = XE_GT_TYPE_MAIN;
+ }
+
++ xe_gt_mmio_init(gt);
+ xe_guc_comm_init_early(>->uc.guc);
+
+ /* Don't bother with GMDID if failed to negotiate the GuC ABI */
+--
+2.39.5
+
--- /dev/null
+From 19a2af81605a205be86b6238991ec83658e70630 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 24 Feb 2025 15:58:07 +0530
+Subject: drm/xe/vf: Retry sending MMIO request to GUC on timeout error
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Satyanarayana K V P <satyanarayana.k.v.p@intel.com>
+
+[ Upstream commit ba757a65d2a28d46a8ccf50538f4f05036983f1b ]
+
+Add support to allow retrying the sending of MMIO requests
+from the VF to the GUC in the event of an error. During the
+suspend/resume process, VFs begin resuming only after the PF has
+resumed. Although the PF resumes, the GUC reset and provisioning
+occur later in a separate worker process.
+
+When there are a large number of VFs, some may attempt to resume
+before the PF has completed its provisioning. Therefore, if a
+MMIO request from a VF fails during this period, we will retry
+sending the request up to GUC_RESET_VF_STATE_RETRY_MAX times,
+which is set to a maximum of 10 attempts.
+
+Signed-off-by: Satyanarayana K V P <satyanarayana.k.v.p@intel.com>
+Cc: Michał Wajdeczko <michal.wajdeczko@intel.com>
+Cc: Michał Winiarski <michal.winiarski@intel.com>
+Cc: Piotr Piórkowski <piotr.piorkowski@intel.com>
+Reviewed-by: Piotr Piorkowski <piotr.piorkowski@intel.com>
+Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250224102807.11065-3-satyanarayana.k.v.p@intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/xe_gt_sriov_vf.c | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_vf.c b/drivers/gpu/drm/xe/xe_gt_sriov_vf.c
+index 9c30cbd9af6e1..1c764f200b2a5 100644
+--- a/drivers/gpu/drm/xe/xe_gt_sriov_vf.c
++++ b/drivers/gpu/drm/xe/xe_gt_sriov_vf.c
+@@ -47,12 +47,19 @@ static int guc_action_vf_reset(struct xe_guc *guc)
+ return ret > 0 ? -EPROTO : ret;
+ }
+
++#define GUC_RESET_VF_STATE_RETRY_MAX 10
+ static int vf_reset_guc_state(struct xe_gt *gt)
+ {
++ unsigned int retry = GUC_RESET_VF_STATE_RETRY_MAX;
+ struct xe_guc *guc = >->uc.guc;
+ int err;
+
+- err = guc_action_vf_reset(guc);
++ do {
++ err = guc_action_vf_reset(guc);
++ if (!err || err != -ETIMEDOUT)
++ break;
++ } while (--retry);
++
+ if (unlikely(err))
+ xe_gt_sriov_err(gt, "Failed to reset GuC state (%pe)\n", ERR_PTR(err));
+ return err;
+--
+2.39.5
+
--- /dev/null
+From 19921603bb28385398066b66b2c20fda44780624 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 24 Feb 2025 07:23:13 +0100
+Subject: drm/xe: xe_gen_wa_oob: replace program_invocation_short_name
+
+From: Daniel Gomez <da.gomez@samsung.com>
+
+[ Upstream commit 89eb42b5539f6ae6a0cabcb39e5b6fcc83c106a1 ]
+
+program_invocation_short_name may not be available in other systems.
+Instead, replace it with the argv[0] to pass the executable name.
+
+Fixes build error when program_invocation_short_name is not available:
+
+drivers/gpu/drm/xe/xe_gen_wa_oob.c:34:3: error: use of
+undeclared identifier 'program_invocation_short_name' 34 |
+program_invocation_short_name); | ^ 1 error
+generated.
+
+Suggested-by: Masahiro Yamada <masahiroy@kernel.org>
+Signed-off-by: Daniel Gomez <da.gomez@samsung.com>
+Reviewed-by: Lucas De Marchi <lucas.demarchi@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250224-macos-build-support-xe-v3-1-d2c9ed3a27cc@samsung.com
+Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/xe_gen_wa_oob.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/gpu/drm/xe/xe_gen_wa_oob.c b/drivers/gpu/drm/xe/xe_gen_wa_oob.c
+index 904cf47925aa1..ed9183599e31c 100644
+--- a/drivers/gpu/drm/xe/xe_gen_wa_oob.c
++++ b/drivers/gpu/drm/xe/xe_gen_wa_oob.c
+@@ -28,10 +28,10 @@
+ "\n" \
+ "#endif\n"
+
+-static void print_usage(FILE *f)
++static void print_usage(FILE *f, const char *progname)
+ {
+ fprintf(f, "usage: %s <input-rule-file> <generated-c-source-file> <generated-c-header-file>\n",
+- program_invocation_short_name);
++ progname);
+ }
+
+ static void print_parse_error(const char *err_msg, const char *line,
+@@ -144,7 +144,7 @@ int main(int argc, const char *argv[])
+
+ if (argc < 3) {
+ fprintf(stderr, "ERROR: wrong arguments\n");
+- print_usage(stderr);
++ print_usage(stderr, argv[0]);
+ return 1;
+ }
+
+--
+2.39.5
+
--- /dev/null
+From f0e7dc7ec7eab1400ac7d1506c58cdd9a199ecbf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 22 Jan 2025 07:50:26 +0100
+Subject: EDAC/ie31200: work around false positive build warning
+
+From: Arnd Bergmann <arnd@arndb.de>
+
+[ Upstream commit c29dfd661fe2f8d1b48c7f00590929c04b25bf40 ]
+
+gcc-14 produces a bogus warning in some configurations:
+
+drivers/edac/ie31200_edac.c: In function 'ie31200_probe1.isra':
+drivers/edac/ie31200_edac.c:412:26: error: 'dimm_info' is used uninitialized [-Werror=uninitialized]
+ 412 | struct dimm_data dimm_info[IE31200_CHANNELS][IE31200_DIMMS_PER_CHANNEL];
+ | ^~~~~~~~~
+drivers/edac/ie31200_edac.c:412:26: note: 'dimm_info' declared here
+ 412 | struct dimm_data dimm_info[IE31200_CHANNELS][IE31200_DIMMS_PER_CHANNEL];
+ | ^~~~~~~~~
+
+I don't see any way the unintialized access could really happen here,
+but I can see why the compiler gets confused by the two loops.
+
+Instead, rework the two nested loops to only read the addr_decode
+registers and then keep only one instance of the dimm info structure.
+
+[Tony: Qiuxu pointed out that the "populate DIMM info" comment was left
+behind in the refactor and suggested moving it. I deleted the comment
+as unnecessry in front os a call to populate_dimm_info(). That seems
+pretty self-describing.]
+
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Acked-by: Jason Baron <jbaron@akamai.com>
+Signed-off-by: Tony Luck <tony.luck@intel.com>
+Link: https://lore.kernel.org/all/20250122065031.1321015-1-arnd@kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/edac/ie31200_edac.c | 28 +++++++++++++---------------
+ 1 file changed, 13 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/edac/ie31200_edac.c b/drivers/edac/ie31200_edac.c
+index 9b02a6b43ab58..a8dd55ec52cea 100644
+--- a/drivers/edac/ie31200_edac.c
++++ b/drivers/edac/ie31200_edac.c
+@@ -408,10 +408,9 @@ static int ie31200_probe1(struct pci_dev *pdev, int dev_idx)
+ int i, j, ret;
+ struct mem_ctl_info *mci = NULL;
+ struct edac_mc_layer layers[2];
+- struct dimm_data dimm_info[IE31200_CHANNELS][IE31200_DIMMS_PER_CHANNEL];
+ void __iomem *window;
+ struct ie31200_priv *priv;
+- u32 addr_decode, mad_offset;
++ u32 addr_decode[IE31200_CHANNELS], mad_offset;
+
+ /*
+ * Kaby Lake, Coffee Lake seem to work like Skylake. Please re-visit
+@@ -469,19 +468,10 @@ static int ie31200_probe1(struct pci_dev *pdev, int dev_idx)
+ mad_offset = IE31200_MAD_DIMM_0_OFFSET;
+ }
+
+- /* populate DIMM info */
+ for (i = 0; i < IE31200_CHANNELS; i++) {
+- addr_decode = readl(window + mad_offset +
++ addr_decode[i] = readl(window + mad_offset +
+ (i * 4));
+- edac_dbg(0, "addr_decode: 0x%x\n", addr_decode);
+- for (j = 0; j < IE31200_DIMMS_PER_CHANNEL; j++) {
+- populate_dimm_info(&dimm_info[i][j], addr_decode, j,
+- skl);
+- edac_dbg(0, "size: 0x%x, rank: %d, width: %d\n",
+- dimm_info[i][j].size,
+- dimm_info[i][j].dual_rank,
+- dimm_info[i][j].x16_width);
+- }
++ edac_dbg(0, "addr_decode: 0x%x\n", addr_decode[i]);
+ }
+
+ /*
+@@ -492,14 +482,22 @@ static int ie31200_probe1(struct pci_dev *pdev, int dev_idx)
+ */
+ for (i = 0; i < IE31200_DIMMS_PER_CHANNEL; i++) {
+ for (j = 0; j < IE31200_CHANNELS; j++) {
++ struct dimm_data dimm_info;
+ struct dimm_info *dimm;
+ unsigned long nr_pages;
+
+- nr_pages = IE31200_PAGES(dimm_info[j][i].size, skl);
++ populate_dimm_info(&dimm_info, addr_decode[j], i,
++ skl);
++ edac_dbg(0, "size: 0x%x, rank: %d, width: %d\n",
++ dimm_info.size,
++ dimm_info.dual_rank,
++ dimm_info.x16_width);
++
++ nr_pages = IE31200_PAGES(dimm_info.size, skl);
+ if (nr_pages == 0)
+ continue;
+
+- if (dimm_info[j][i].dual_rank) {
++ if (dimm_info.dual_rank) {
+ nr_pages = nr_pages / 2;
+ dimm = edac_get_dimm(mci, (i * 2) + 1, j, 0);
+ dimm->nr_pages = nr_pages;
+--
+2.39.5
+
--- /dev/null
+From 97885b6a7468c514970a96ff7d37043664854ccd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Feb 2025 16:09:59 -0600
+Subject: eeprom: ee1004: Check chip before probing
+
+From: Eddie James <eajames@linux.ibm.com>
+
+[ Upstream commit d9406677428e9234ea62bb2d2f5e996d1b777760 ]
+
+Like other eeprom drivers, check if the device is really there and
+functional before probing.
+
+Signed-off-by: Eddie James <eajames@linux.ibm.com>
+Link: https://lore.kernel.org/r/20250218220959.721698-1-eajames@linux.ibm.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/misc/eeprom/ee1004.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/misc/eeprom/ee1004.c b/drivers/misc/eeprom/ee1004.c
+index 89224d4af4a20..e13f9fdd9d7b1 100644
+--- a/drivers/misc/eeprom/ee1004.c
++++ b/drivers/misc/eeprom/ee1004.c
+@@ -304,6 +304,10 @@ static int ee1004_probe(struct i2c_client *client)
+ I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_READ_BYTE_DATA))
+ return -EPFNOSUPPORT;
+
++ err = i2c_smbus_read_byte(client);
++ if (err < 0)
++ return -ENODEV;
++
+ mutex_lock(&ee1004_bus_lock);
+
+ err = ee1004_init_bus_data(client);
+--
+2.39.5
+
--- /dev/null
+From 7259d62c9be0f64eebe0ded4a4de6c27353f2b23 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 17 Mar 2025 13:48:40 +0800
+Subject: erofs: initialize decompression early
+
+From: Gao Xiang <hsiangkao@linux.alibaba.com>
+
+[ Upstream commit fe1e57d44d7f106df9048e815e4862cf63921220 ]
+
+ - Rename erofs_init_managed_cache() to z_erofs_init_super();
+ - Move the initialization of managed_pslots into z_erofs_init_super() too;
+ - Move z_erofs_init_super() and packed inode preparation upwards, before
+ the root inode initialization.
+
+Therefore, the root directory can also be compressible.
+
+Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
+Acked-by: Chao Yu <chao@kernel.org>
+Link: https://lore.kernel.org/r/20250317054840.3483000-1-hsiangkao@linux.alibaba.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/erofs/internal.h | 4 ++--
+ fs/erofs/super.c | 46 ++++++++++++++++++++++-----------------------
+ fs/erofs/zdata.c | 4 ++--
+ 3 files changed, 26 insertions(+), 28 deletions(-)
+
+diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h
+index efd25f3101f1f..2b8d9a10f0026 100644
+--- a/fs/erofs/internal.h
++++ b/fs/erofs/internal.h
+@@ -446,6 +446,7 @@ int __init erofs_init_shrinker(void);
+ void erofs_exit_shrinker(void);
+ int __init z_erofs_init_subsystem(void);
+ void z_erofs_exit_subsystem(void);
++int z_erofs_init_super(struct super_block *sb);
+ unsigned long z_erofs_shrink_scan(struct erofs_sb_info *sbi,
+ unsigned long nr_shrink);
+ int z_erofs_map_blocks_iter(struct inode *inode, struct erofs_map_blocks *map,
+@@ -455,7 +456,6 @@ void z_erofs_put_gbuf(void *ptr);
+ int z_erofs_gbuf_growsize(unsigned int nrpages);
+ int __init z_erofs_gbuf_init(void);
+ void z_erofs_gbuf_exit(void);
+-int erofs_init_managed_cache(struct super_block *sb);
+ int z_erofs_parse_cfgs(struct super_block *sb, struct erofs_super_block *dsb);
+ #else
+ static inline void erofs_shrinker_register(struct super_block *sb) {}
+@@ -464,7 +464,7 @@ static inline int erofs_init_shrinker(void) { return 0; }
+ static inline void erofs_exit_shrinker(void) {}
+ static inline int z_erofs_init_subsystem(void) { return 0; }
+ static inline void z_erofs_exit_subsystem(void) {}
+-static inline int erofs_init_managed_cache(struct super_block *sb) { return 0; }
++static inline int z_erofs_init_super(struct super_block *sb) { return 0; }
+ #endif /* !CONFIG_EROFS_FS_ZIP */
+
+ #ifdef CONFIG_EROFS_FS_BACKED_BY_FILE
+diff --git a/fs/erofs/super.c b/fs/erofs/super.c
+index 9f2bce5af9c83..b30125a2a5011 100644
+--- a/fs/erofs/super.c
++++ b/fs/erofs/super.c
+@@ -631,9 +631,16 @@ static int erofs_fc_fill_super(struct super_block *sb, struct fs_context *fc)
+ else
+ sb->s_flags &= ~SB_POSIXACL;
+
+-#ifdef CONFIG_EROFS_FS_ZIP
+- xa_init(&sbi->managed_pslots);
+-#endif
++ err = z_erofs_init_super(sb);
++ if (err)
++ return err;
++
++ if (erofs_sb_has_fragments(sbi) && sbi->packed_nid) {
++ inode = erofs_iget(sb, sbi->packed_nid);
++ if (IS_ERR(inode))
++ return PTR_ERR(inode);
++ sbi->packed_inode = inode;
++ }
+
+ inode = erofs_iget(sb, sbi->root_nid);
+ if (IS_ERR(inode))
+@@ -645,24 +652,11 @@ static int erofs_fc_fill_super(struct super_block *sb, struct fs_context *fc)
+ iput(inode);
+ return -EINVAL;
+ }
+-
+ sb->s_root = d_make_root(inode);
+ if (!sb->s_root)
+ return -ENOMEM;
+
+ erofs_shrinker_register(sb);
+- if (erofs_sb_has_fragments(sbi) && sbi->packed_nid) {
+- sbi->packed_inode = erofs_iget(sb, sbi->packed_nid);
+- if (IS_ERR(sbi->packed_inode)) {
+- err = PTR_ERR(sbi->packed_inode);
+- sbi->packed_inode = NULL;
+- return err;
+- }
+- }
+- err = erofs_init_managed_cache(sb);
+- if (err)
+- return err;
+-
+ err = erofs_xattr_prefixes_init(sb);
+ if (err)
+ return err;
+@@ -798,6 +792,16 @@ static int erofs_init_fs_context(struct fs_context *fc)
+ return 0;
+ }
+
++static void erofs_drop_internal_inodes(struct erofs_sb_info *sbi)
++{
++ iput(sbi->packed_inode);
++ sbi->packed_inode = NULL;
++#ifdef CONFIG_EROFS_FS_ZIP
++ iput(sbi->managed_cache);
++ sbi->managed_cache = NULL;
++#endif
++}
++
+ static void erofs_kill_sb(struct super_block *sb)
+ {
+ struct erofs_sb_info *sbi = EROFS_SB(sb);
+@@ -807,6 +811,7 @@ static void erofs_kill_sb(struct super_block *sb)
+ kill_anon_super(sb);
+ else
+ kill_block_super(sb);
++ erofs_drop_internal_inodes(sbi);
+ fs_put_dax(sbi->dif0.dax_dev, NULL);
+ erofs_fscache_unregister_fs(sb);
+ erofs_sb_free(sbi);
+@@ -817,17 +822,10 @@ static void erofs_put_super(struct super_block *sb)
+ {
+ struct erofs_sb_info *const sbi = EROFS_SB(sb);
+
+- DBG_BUGON(!sbi);
+-
+ erofs_unregister_sysfs(sb);
+ erofs_shrinker_unregister(sb);
+ erofs_xattr_prefixes_cleanup(sb);
+-#ifdef CONFIG_EROFS_FS_ZIP
+- iput(sbi->managed_cache);
+- sbi->managed_cache = NULL;
+-#endif
+- iput(sbi->packed_inode);
+- sbi->packed_inode = NULL;
++ erofs_drop_internal_inodes(sbi);
+ erofs_free_dev_context(sbi->devs);
+ sbi->devs = NULL;
+ erofs_fscache_unregister_fs(sb);
+diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c
+index 67acef591646c..87192635b2d20 100644
+--- a/fs/erofs/zdata.c
++++ b/fs/erofs/zdata.c
+@@ -641,18 +641,18 @@ static const struct address_space_operations z_erofs_cache_aops = {
+ .invalidate_folio = z_erofs_cache_invalidate_folio,
+ };
+
+-int erofs_init_managed_cache(struct super_block *sb)
++int z_erofs_init_super(struct super_block *sb)
+ {
+ struct inode *const inode = new_inode(sb);
+
+ if (!inode)
+ return -ENOMEM;
+-
+ set_nlink(inode, 1);
+ inode->i_size = OFFSET_MAX;
+ inode->i_mapping->a_ops = &z_erofs_cache_aops;
+ mapping_set_gfp_mask(inode->i_mapping, GFP_KERNEL);
+ EROFS_SB(sb)->managed_cache = inode;
++ xa_init(&EROFS_SB(sb)->managed_pslots);
+ return 0;
+ }
+
+--
+2.39.5
+
--- /dev/null
+From 291f1627c127c88531be87370456fcd9a509cc6d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 28 Feb 2025 11:15:26 -0800
+Subject: eth: fbnic: Prepend TSENE FW fields with FBNIC_FW
+
+From: Lee Trager <lee@trager.us>
+
+[ Upstream commit 56bcc6ecff8fdc06258c637226986ed522027ca5 ]
+
+All other firmware fields are prepended with FBNIC_FW. Update TSENE fields
+to follow the same format.
+
+Signed-off-by: Lee Trager <lee@trager.us>
+Link: https://patch.msgid.link/20250228191935.3953712-2-lee@trager.us
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/meta/fbnic/fbnic_fw.c | 16 ++++++++--------
+ drivers/net/ethernet/meta/fbnic/fbnic_fw.h | 8 ++++----
+ 2 files changed, 12 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_fw.c b/drivers/net/ethernet/meta/fbnic/fbnic_fw.c
+index 9351a874689f8..cdd6c3a210944 100644
+--- a/drivers/net/ethernet/meta/fbnic/fbnic_fw.c
++++ b/drivers/net/ethernet/meta/fbnic/fbnic_fw.c
+@@ -747,9 +747,9 @@ int fbnic_fw_xmit_tsene_read_msg(struct fbnic_dev *fbd,
+ }
+
+ static const struct fbnic_tlv_index fbnic_tsene_read_resp_index[] = {
+- FBNIC_TLV_ATTR_S32(FBNIC_TSENE_THERM),
+- FBNIC_TLV_ATTR_S32(FBNIC_TSENE_VOLT),
+- FBNIC_TLV_ATTR_S32(FBNIC_TSENE_ERROR),
++ FBNIC_TLV_ATTR_S32(FBNIC_FW_TSENE_THERM),
++ FBNIC_TLV_ATTR_S32(FBNIC_FW_TSENE_VOLT),
++ FBNIC_TLV_ATTR_S32(FBNIC_FW_TSENE_ERROR),
+ FBNIC_TLV_ATTR_LAST
+ };
+
+@@ -766,21 +766,21 @@ static int fbnic_fw_parse_tsene_read_resp(void *opaque,
+ if (!cmpl_data)
+ return -EINVAL;
+
+- if (results[FBNIC_TSENE_ERROR]) {
+- err = fbnic_tlv_attr_get_unsigned(results[FBNIC_TSENE_ERROR]);
++ if (results[FBNIC_FW_TSENE_ERROR]) {
++ err = fbnic_tlv_attr_get_unsigned(results[FBNIC_FW_TSENE_ERROR]);
+ if (err)
+ goto exit_complete;
+ }
+
+- if (!results[FBNIC_TSENE_THERM] || !results[FBNIC_TSENE_VOLT]) {
++ if (!results[FBNIC_FW_TSENE_THERM] || !results[FBNIC_FW_TSENE_VOLT]) {
+ err = -EINVAL;
+ goto exit_complete;
+ }
+
+ cmpl_data->u.tsene.millidegrees =
+- fbnic_tlv_attr_get_signed(results[FBNIC_TSENE_THERM]);
++ fbnic_tlv_attr_get_signed(results[FBNIC_FW_TSENE_THERM]);
+ cmpl_data->u.tsene.millivolts =
+- fbnic_tlv_attr_get_signed(results[FBNIC_TSENE_VOLT]);
++ fbnic_tlv_attr_get_signed(results[FBNIC_FW_TSENE_VOLT]);
+
+ exit_complete:
+ cmpl_data->result = err;
+diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_fw.h b/drivers/net/ethernet/meta/fbnic/fbnic_fw.h
+index fe68333d51b18..a3618e7826c25 100644
+--- a/drivers/net/ethernet/meta/fbnic/fbnic_fw.h
++++ b/drivers/net/ethernet/meta/fbnic/fbnic_fw.h
+@@ -139,10 +139,10 @@ enum {
+ };
+
+ enum {
+- FBNIC_TSENE_THERM = 0x0,
+- FBNIC_TSENE_VOLT = 0x1,
+- FBNIC_TSENE_ERROR = 0x2,
+- FBNIC_TSENE_MSG_MAX
++ FBNIC_FW_TSENE_THERM = 0x0,
++ FBNIC_FW_TSENE_VOLT = 0x1,
++ FBNIC_FW_TSENE_ERROR = 0x2,
++ FBNIC_FW_TSENE_MSG_MAX
+ };
+
+ enum {
+--
+2.39.5
+
--- /dev/null
+From 52853c978fa8eb9b9fea744ce3e6097fe6fbf110 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Feb 2025 17:00:38 -0800
+Subject: eth: fbnic: set IFF_UNICAST_FLT to avoid enabling promiscuous mode
+ when adding unicast addrs
+
+From: Alexander Duyck <alexanderduyck@meta.com>
+
+[ Upstream commit 09717c28b76c30b1dc8c261c855ffb2406abab2e ]
+
+I realized when we were adding unicast addresses we were enabling
+promiscuous mode. I did a bit of digging and realized we had overlooked
+setting the driver private flag to indicate we supported unicast filtering.
+
+Example below shows the table with 00deadbeef01 as the main NIC address,
+and 5 additional addresses in the 00deadbeefX0 format.
+
+ # cat $dbgfs/mac_addr
+ Idx S TCAM Bitmap Addr/Mask
+ ----------------------------------
+ 00 0 00000000,00000000 000000000000
+ 000000000000
+ 01 0 00000000,00000000 000000000000
+ 000000000000
+ 02 0 00000000,00000000 000000000000
+ 000000000000
+ ...
+ 24 0 00000000,00000000 000000000000
+ 000000000000
+ 25 1 00100000,00000000 00deadbeef50
+ 000000000000
+ 26 1 00100000,00000000 00deadbeef40
+ 000000000000
+ 27 1 00100000,00000000 00deadbeef30
+ 000000000000
+ 28 1 00100000,00000000 00deadbeef20
+ 000000000000
+ 29 1 00100000,00000000 00deadbeef10
+ 000000000000
+ 30 1 00100000,00000000 00deadbeef01
+ 000000000000
+ 31 0 00000000,00000000 000000000000
+ 000000000000
+
+Before rule 31 would be active. With this change it correctly sticks
+to just the unicast filters.
+
+Signed-off-by: Alexander Duyck <alexanderduyck@meta.com>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20250204010038.1404268-2-kuba@kernel.org
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/meta/fbnic/fbnic_netdev.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c
+index 7a96b6ee773f3..1db57c42333ef 100644
+--- a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c
++++ b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c
+@@ -628,6 +628,8 @@ struct net_device *fbnic_netdev_alloc(struct fbnic_dev *fbd)
+ fbnic_rss_key_fill(fbn->rss_key);
+ fbnic_rss_init_en_mask(fbn);
+
++ netdev->priv_flags |= IFF_UNICAST_FLT;
++
+ netdev->features |=
+ NETIF_F_RXHASH |
+ NETIF_F_SG |
+--
+2.39.5
+
--- /dev/null
+From f1e4ba993b2b455f55cab90f6a297ab6ae9baa28 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 12 Feb 2025 17:06:33 -0800
+Subject: eth: mlx4: don't try to complete XDP frames in netpoll
+
+From: Jakub Kicinski <kuba@kernel.org>
+
+[ Upstream commit 8fdeafd66edaf420ea0063a1f13442fe3470fe70 ]
+
+mlx4 doesn't support ndo_xdp_xmit / XDP_REDIRECT and wasn't
+using page pool until now, so it could run XDP completions
+in netpoll (NAPI budget == 0) just fine. Page pool has calling
+context requirements, make sure we don't try to call it from
+what is potentially HW IRQ context.
+
+Reviewed-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/20250213010635.1354034-3-kuba@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mellanox/mlx4/en_tx.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
+index 1ddb11cb25f91..6e077d202827a 100644
+--- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c
++++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
+@@ -450,6 +450,8 @@ int mlx4_en_process_tx_cq(struct net_device *dev,
+
+ if (unlikely(!priv->port_up))
+ return 0;
++ if (unlikely(!napi_budget) && cq->type == TX_XDP)
++ return 0;
+
+ netdev_txq_bql_complete_prefetchw(ring->tx_queue);
+
+--
+2.39.5
+
--- /dev/null
+From 663b648c046ac206bbfe2de4bf71ac4faff5b33f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Mar 2025 00:01:16 +0900
+Subject: exfat: call bh_read in get_block only when necessary
+
+From: Sungjong Seo <sj1557.seo@samsung.com>
+
+[ Upstream commit c73e680d1f84059e1b1ea82a537f6ccc1c563eb4 ]
+
+With commit 11a347fb6cef ("exfat: change to get file size from DataLength"),
+exfat_get_block() can now handle valid_size. However, most partial
+unwritten blocks that could be mapped with other blocks are being
+inefficiently processed separately as individual blocks.
+
+Except for partial unwritten blocks that require independent processing,
+let's handle them simply as before.
+
+Signed-off-by: Sungjong Seo <sj1557.seo@samsung.com>
+Reviewed-by: Yuezhang Mo <Yuezhang.Mo@sony.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/exfat/inode.c | 159 +++++++++++++++++++++++------------------------
+ 1 file changed, 77 insertions(+), 82 deletions(-)
+
+diff --git a/fs/exfat/inode.c b/fs/exfat/inode.c
+index a23677de4544f..b22c02d6000f7 100644
+--- a/fs/exfat/inode.c
++++ b/fs/exfat/inode.c
+@@ -274,9 +274,11 @@ static int exfat_get_block(struct inode *inode, sector_t iblock,
+ sector_t last_block;
+ sector_t phys = 0;
+ sector_t valid_blks;
++ loff_t i_size;
+
+ mutex_lock(&sbi->s_lock);
+- last_block = EXFAT_B_TO_BLK_ROUND_UP(i_size_read(inode), sb);
++ i_size = i_size_read(inode);
++ last_block = EXFAT_B_TO_BLK_ROUND_UP(i_size, sb);
+ if (iblock >= last_block && !create)
+ goto done;
+
+@@ -305,102 +307,95 @@ static int exfat_get_block(struct inode *inode, sector_t iblock,
+ if (buffer_delay(bh_result))
+ clear_buffer_delay(bh_result);
+
+- if (create) {
++ /*
++ * In most cases, we just need to set bh_result to mapped, unmapped
++ * or new status as follows:
++ * 1. i_size == valid_size
++ * 2. write case (create == 1)
++ * 3. direct_read (!bh_result->b_folio)
++ * -> the unwritten part will be zeroed in exfat_direct_IO()
++ *
++ * Otherwise, in the case of buffered read, it is necessary to take
++ * care the last nested block if valid_size is not equal to i_size.
++ */
++ if (i_size == ei->valid_size || create || !bh_result->b_folio)
+ valid_blks = EXFAT_B_TO_BLK_ROUND_UP(ei->valid_size, sb);
++ else
++ valid_blks = EXFAT_B_TO_BLK(ei->valid_size, sb);
+
+- if (iblock + max_blocks < valid_blks) {
+- /* The range has been written, map it */
+- goto done;
+- } else if (iblock < valid_blks) {
+- /*
+- * The range has been partially written,
+- * map the written part.
+- */
+- max_blocks = valid_blks - iblock;
+- goto done;
+- }
++ /* The range has been fully written, map it */
++ if (iblock + max_blocks < valid_blks)
++ goto done;
+
+- /* The area has not been written, map and mark as new. */
+- set_buffer_new(bh_result);
++ /* The range has been partially written, map the written part */
++ if (iblock < valid_blks) {
++ max_blocks = valid_blks - iblock;
++ goto done;
++ }
+
++ /* The area has not been written, map and mark as new for create case */
++ if (create) {
++ set_buffer_new(bh_result);
+ ei->valid_size = EXFAT_BLK_TO_B(iblock + max_blocks, sb);
+ mark_inode_dirty(inode);
+- } else {
+- valid_blks = EXFAT_B_TO_BLK(ei->valid_size, sb);
++ goto done;
++ }
+
+- if (iblock + max_blocks < valid_blks) {
+- /* The range has been written, map it */
+- goto done;
+- } else if (iblock < valid_blks) {
+- /*
+- * The area has been partially written,
+- * map the written part.
+- */
+- max_blocks = valid_blks - iblock;
++ /*
++ * The area has just one block partially written.
++ * In that case, we should read and fill the unwritten part of
++ * a block with zero.
++ */
++ if (bh_result->b_folio && iblock == valid_blks &&
++ (ei->valid_size & (sb->s_blocksize - 1))) {
++ loff_t size, pos;
++ void *addr;
++
++ max_blocks = 1;
++
++ /*
++ * No buffer_head is allocated.
++ * (1) bmap: It's enough to set blocknr without I/O.
++ * (2) read: The unwritten part should be filled with zero.
++ * If a folio does not have any buffers,
++ * let's returns -EAGAIN to fallback to
++ * block_read_full_folio() for per-bh IO.
++ */
++ if (!folio_buffers(bh_result->b_folio)) {
++ err = -EAGAIN;
+ goto done;
+- } else if (iblock == valid_blks &&
+- (ei->valid_size & (sb->s_blocksize - 1))) {
+- /*
+- * The block has been partially written,
+- * zero the unwritten part and map the block.
+- */
+- loff_t size, pos;
+- void *addr;
+-
+- max_blocks = 1;
+-
+- /*
+- * For direct read, the unwritten part will be zeroed in
+- * exfat_direct_IO()
+- */
+- if (!bh_result->b_folio)
+- goto done;
+-
+- /*
+- * No buffer_head is allocated.
+- * (1) bmap: It's enough to fill bh_result without I/O.
+- * (2) read: The unwritten part should be filled with 0
+- * If a folio does not have any buffers,
+- * let's returns -EAGAIN to fallback to
+- * per-bh IO like block_read_full_folio().
+- */
+- if (!folio_buffers(bh_result->b_folio)) {
+- err = -EAGAIN;
+- goto done;
+- }
++ }
+
+- pos = EXFAT_BLK_TO_B(iblock, sb);
+- size = ei->valid_size - pos;
+- addr = folio_address(bh_result->b_folio) +
+- offset_in_folio(bh_result->b_folio, pos);
++ pos = EXFAT_BLK_TO_B(iblock, sb);
++ size = ei->valid_size - pos;
++ addr = folio_address(bh_result->b_folio) +
++ offset_in_folio(bh_result->b_folio, pos);
+
+- /* Check if bh->b_data points to proper addr in folio */
+- if (bh_result->b_data != addr) {
+- exfat_fs_error_ratelimit(sb,
++ /* Check if bh->b_data points to proper addr in folio */
++ if (bh_result->b_data != addr) {
++ exfat_fs_error_ratelimit(sb,
+ "b_data(%p) != folio_addr(%p)",
+ bh_result->b_data, addr);
+- err = -EINVAL;
+- goto done;
+- }
+-
+- /* Read a block */
+- err = bh_read(bh_result, 0);
+- if (err < 0)
+- goto done;
++ err = -EINVAL;
++ goto done;
++ }
+
+- /* Zero unwritten part of a block */
+- memset(bh_result->b_data + size, 0,
+- bh_result->b_size - size);
++ /* Read a block */
++ err = bh_read(bh_result, 0);
++ if (err < 0)
++ goto done;
+
+- err = 0;
+- } else {
+- /*
+- * The range has not been written, clear the mapped flag
+- * to only zero the cache and do not read from disk.
+- */
+- clear_buffer_mapped(bh_result);
+- }
++ /* Zero unwritten part of a block */
++ memset(bh_result->b_data + size, 0, bh_result->b_size - size);
++ err = 0;
++ goto done;
+ }
++
++ /*
++ * The area has not been written, clear mapped for read/bmap cases.
++ * If so, it will be filled with zero without reading from disk.
++ */
++ clear_buffer_mapped(bh_result);
+ done:
+ bh_result->b_size = EXFAT_BLK_TO_B(max_blocks, sb);
+ if (err < 0)
+--
+2.39.5
+
--- /dev/null
+From 909fe6c95cb78648e9b6398dbb8c3bba92459c46 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 24 Mar 2025 18:19:41 +0100
+Subject: exit: fix the usage of delay_group_leader->exit_code in
+ do_notify_parent() and pidfs_exit()
+
+From: Oleg Nesterov <oleg@redhat.com>
+
+[ Upstream commit 9133607de37a4887c6f89ed937176a0a0c1ebb17 ]
+
+Consider a process with a group leader L and a sub-thread T.
+L does sys_exit(1), then T does sys_exit_group(2).
+
+In this case wait_task_zombie(L) will notice SIGNAL_GROUP_EXIT and use
+L->signal->group_exit_code, this is correct.
+
+But, before that, do_notify_parent(L) called by release_task(T) will use
+L->exit_code != L->signal->group_exit_code, and this is not consistent.
+We don't really care, I think that nobody relies on the info which comes
+with SIGCHLD, if nothing else SIGCHLD < SIGRTMIN can be queued only once.
+
+But pidfs_exit() is more problematic, I think pidfs_exit_info->exit_code
+should report ->group_exit_code in this case, just like wait_task_zombie().
+
+TODO: with this change we can hopefully cleanup (or may be even kill) the
+similar SIGNAL_GROUP_EXIT checks, at least in wait_task_zombie().
+
+Signed-off-by: Oleg Nesterov <oleg@redhat.com>
+Link: https://lore.kernel.org/r/20250324171941.GA13114@redhat.com
+Signed-off-by: Christian Brauner <brauner@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/exit.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/kernel/exit.c b/kernel/exit.c
+index 3485e5fc499e4..6bb59b16e33e1 100644
+--- a/kernel/exit.c
++++ b/kernel/exit.c
+@@ -265,6 +265,9 @@ void release_task(struct task_struct *p)
+ leader = p->group_leader;
+ if (leader != p && thread_group_empty(leader)
+ && leader->exit_state == EXIT_ZOMBIE) {
++ /* for pidfs_exit() and do_notify_parent() */
++ if (leader->signal->flags & SIGNAL_GROUP_EXIT)
++ leader->exit_code = leader->signal->group_exit_code;
+ /*
+ * If we were the last child thread and the leader has
+ * exited already, and the leader's parent ignores SIGCHLD,
+--
+2.39.5
+
--- /dev/null
+From 4e2defa15845ab8406b3214e4c1ffb2a5a7a4aff Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 22 Jan 2025 19:05:26 +0800
+Subject: ext4: do not convert the unwritten extents if data writeback fails
+
+From: Baokun Li <libaokun1@huawei.com>
+
+[ Upstream commit e856f93e0fb249955f7d5efb18fe20500a9ccc6d ]
+
+When dioread_nolock is turned on (the default), it will convert unwritten
+extents to written at ext4_end_io_end(), even if the data writeback fails.
+
+It leads to the possibility that stale data may be exposed when the
+physical block corresponding to the file data is read-only (i.e., writes
+return -EIO, but reads are normal).
+
+Therefore a new ext4_io_end->flags EXT4_IO_END_FAILED is added, which
+indicates that some bio write-back failed in the current ext4_io_end.
+When this flag is set, the unwritten to written conversion is no longer
+performed. Users can read the data normally until the caches are dropped,
+after that, the failed extents can only be read to all 0.
+
+Signed-off-by: Baokun Li <libaokun1@huawei.com>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Reviewed-by: Zhang Yi <yi.zhang@huawei.com>
+Link: https://patch.msgid.link/20250122110533.4116662-3-libaokun@huaweicloud.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/ext4.h | 3 ++-
+ fs/ext4/page-io.c | 16 ++++++++++++++--
+ 2 files changed, 16 insertions(+), 3 deletions(-)
+
+diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
+index df30d9f235123..d4d285d999311 100644
+--- a/fs/ext4/ext4.h
++++ b/fs/ext4/ext4.h
+@@ -278,7 +278,8 @@ struct ext4_system_blocks {
+ /*
+ * Flags for ext4_io_end->flags
+ */
+-#define EXT4_IO_END_UNWRITTEN 0x0001
++#define EXT4_IO_END_UNWRITTEN 0x0001
++#define EXT4_IO_END_FAILED 0x0002
+
+ struct ext4_io_end_vec {
+ struct list_head list; /* list of io_end_vec */
+diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c
+index 69b8a7221a2b1..f041a5d93716f 100644
+--- a/fs/ext4/page-io.c
++++ b/fs/ext4/page-io.c
+@@ -181,14 +181,25 @@ static int ext4_end_io_end(ext4_io_end_t *io_end)
+ "list->prev 0x%p\n",
+ io_end, inode->i_ino, io_end->list.next, io_end->list.prev);
+
+- io_end->handle = NULL; /* Following call will use up the handle */
+- ret = ext4_convert_unwritten_io_end_vec(handle, io_end);
++ /*
++ * Do not convert the unwritten extents if data writeback fails,
++ * or stale data may be exposed.
++ */
++ io_end->handle = NULL; /* Following call will use up the handle */
++ if (unlikely(io_end->flag & EXT4_IO_END_FAILED)) {
++ ret = -EIO;
++ if (handle)
++ jbd2_journal_free_reserved(handle);
++ } else {
++ ret = ext4_convert_unwritten_io_end_vec(handle, io_end);
++ }
+ if (ret < 0 && !ext4_forced_shutdown(inode->i_sb)) {
+ ext4_msg(inode->i_sb, KERN_EMERG,
+ "failed to convert unwritten extents to written "
+ "extents -- potential data loss! "
+ "(inode %lu, error %d)", inode->i_ino, ret);
+ }
++
+ ext4_clear_io_unwritten_flag(io_end);
+ ext4_release_io_end(io_end);
+ return ret;
+@@ -344,6 +355,7 @@ static void ext4_end_bio(struct bio *bio)
+ bio->bi_status, inode->i_ino,
+ (unsigned long long)
+ bi_sector >> (inode->i_blkbits - 9));
++ io_end->flag |= EXT4_IO_END_FAILED;
+ mapping_set_error(inode->i_mapping,
+ blk_status_to_errno(bio->bi_status));
+ }
+--
+2.39.5
+
--- /dev/null
+From db753dabca4329d99109850965c2b3a1e207cce5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 20 Dec 2024 09:16:30 +0800
+Subject: ext4: don't write back data before punch hole in nojournal mode
+
+From: Zhang Yi <yi.zhang@huawei.com>
+
+[ Upstream commit 43d0105e2c7523cc6b14cad65e2044e829c0a07a ]
+
+There is no need to write back all data before punching a hole in
+non-journaled mode since it will be dropped soon after removing space.
+Therefore, the call to filemap_write_and_wait_range() can be eliminated.
+Besides, similar to ext4_zero_range(), we must address the case of
+partially punched folios when block size < page size. It is essential to
+remove writable userspace mappings to ensure that the folio can be
+faulted again during subsequent mmap write access.
+
+In journaled mode, we need to write dirty pages out before discarding
+page cache in case of crash before committing the freeing data
+transaction, which could expose old, stale data, even if synchronization
+has been performed.
+
+Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
+Link: https://patch.msgid.link/20241220011637.1157197-4-yi.zhang@huaweicloud.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/inode.c | 18 +++++-------------
+ 1 file changed, 5 insertions(+), 13 deletions(-)
+
+diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
+index 74c5e2a381a6b..377fec39b24be 100644
+--- a/fs/ext4/inode.c
++++ b/fs/ext4/inode.c
+@@ -3957,17 +3957,6 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length)
+
+ trace_ext4_punch_hole(inode, offset, length, 0);
+
+- /*
+- * Write out all dirty pages to avoid race conditions
+- * Then release them.
+- */
+- if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) {
+- ret = filemap_write_and_wait_range(mapping, offset,
+- offset + length - 1);
+- if (ret)
+- return ret;
+- }
+-
+ inode_lock(inode);
+
+ /* No need to punch hole beyond i_size */
+@@ -4029,8 +4018,11 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length)
+ ret = ext4_update_disksize_before_punch(inode, offset, length);
+ if (ret)
+ goto out_dio;
+- truncate_pagecache_range(inode, first_block_offset,
+- last_block_offset);
++
++ ret = ext4_truncate_page_cache_block_range(inode,
++ first_block_offset, last_block_offset + 1);
++ if (ret)
++ goto out_dio;
+ }
+
+ if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
+--
+2.39.5
+
--- /dev/null
+From b62f7d64d57f729188d8b4e99f57be318d0bed5c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 19 Mar 2025 11:10:11 -0600
+Subject: ext4: on a remount, only log the ro or r/w state when it has changed
+
+From: Nicolas Bretz <bretznic@gmail.com>
+
+[ Upstream commit d7b0befd09320e3356a75cb96541c030515e7f5f ]
+
+A user complained that a message such as:
+
+EXT4-fs (nvme0n1p3): re-mounted UUID ro. Quota mode: none.
+
+implied that the file system was previously mounted read/write and was
+now remounted read-only, when it could have been some other mount
+state that had changed by the "mount -o remount" operation. Fix this
+by only logging "ro"or "r/w" when it has changed.
+
+https://bugzilla.kernel.org/show_bug.cgi?id=219132
+
+Signed-off-by: Nicolas Bretz <bretznic@gmail.com>
+Link: https://patch.msgid.link/20250319171011.8372-1-bretznic@gmail.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/super.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/fs/ext4/super.c b/fs/ext4/super.c
+index 528979de0f7c1..b4a02be2eacf6 100644
+--- a/fs/ext4/super.c
++++ b/fs/ext4/super.c
+@@ -6776,6 +6776,7 @@ static int ext4_reconfigure(struct fs_context *fc)
+ {
+ struct super_block *sb = fc->root->d_sb;
+ int ret;
++ bool old_ro = sb_rdonly(sb);
+
+ fc->s_fs_info = EXT4_SB(sb);
+
+@@ -6787,9 +6788,9 @@ static int ext4_reconfigure(struct fs_context *fc)
+ if (ret < 0)
+ return ret;
+
+- ext4_msg(sb, KERN_INFO, "re-mounted %pU %s. Quota mode: %s.",
+- &sb->s_uuid, sb_rdonly(sb) ? "ro" : "r/w",
+- ext4_quota_mode(sb));
++ ext4_msg(sb, KERN_INFO, "re-mounted %pU%s.",
++ &sb->s_uuid,
++ (old_ro != sb_rdonly(sb)) ? (sb_rdonly(sb) ? " ro" : " r/w") : "");
+
+ return 0;
+ }
+--
+2.39.5
+
--- /dev/null
+From 8936a5df34cb3db706ccd0f8d997faed5d7ba9f9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 22 Jan 2025 19:05:27 +0800
+Subject: ext4: reject the 'data_err=abort' option in nojournal mode
+
+From: Baokun Li <libaokun1@huawei.com>
+
+[ Upstream commit 26343ca0df715097065b02a6cddb4a029d5b9327 ]
+
+data_err=abort aborts the journal on I/O errors. However, this option is
+meaningless if journal is disabled, so it is rejected in nojournal mode
+to reduce unnecessary checks. Also, this option is ignored upon remount.
+
+Signed-off-by: Baokun Li <libaokun1@huawei.com>
+Reviewed-by: Zhang Yi <yi.zhang@huawei.com>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Link: https://patch.msgid.link/20250122110533.4116662-4-libaokun@huaweicloud.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/super.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/fs/ext4/super.c b/fs/ext4/super.c
+index b4a02be2eacf6..b956e1ee98290 100644
+--- a/fs/ext4/super.c
++++ b/fs/ext4/super.c
+@@ -2785,6 +2785,13 @@ static int ext4_check_opt_consistency(struct fs_context *fc,
+ }
+
+ if (is_remount) {
++ if (!sbi->s_journal &&
++ ctx_test_mount_opt(ctx, EXT4_MOUNT_DATA_ERR_ABORT)) {
++ ext4_msg(NULL, KERN_WARNING,
++ "Remounting fs w/o journal so ignoring data_err option");
++ ctx_clear_mount_opt(ctx, EXT4_MOUNT_DATA_ERR_ABORT);
++ }
++
+ if (ctx_test_mount_opt(ctx, EXT4_MOUNT_DAX_ALWAYS) &&
+ (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA)) {
+ ext4_msg(NULL, KERN_ERR, "can't mount with "
+@@ -5428,6 +5435,11 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb)
+ "data=, fs mounted w/o journal");
+ goto failed_mount3a;
+ }
++ if (test_opt(sb, DATA_ERR_ABORT)) {
++ ext4_msg(sb, KERN_ERR,
++ "can't mount with data_err=abort, fs mounted w/o journal");
++ goto failed_mount3a;
++ }
+ sbi->s_def_mount_opt &= ~EXT4_MOUNT_JOURNAL_CHECKSUM;
+ clear_opt(sb, JOURNAL_CHECKSUM);
+ clear_opt(sb, DATA_FLAGS);
+--
+2.39.5
+
--- /dev/null
+From 8cabec0d6bc2b2903e87472cd4992cc6f864c592 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 20 Dec 2024 09:16:28 +0800
+Subject: ext4: remove writable userspace mappings before truncating page cache
+
+From: Zhang Yi <yi.zhang@huawei.com>
+
+[ Upstream commit 17207d0bb209e8b40f27d7f3f96e82a78af0bf2c ]
+
+When zeroing a range of folios on the filesystem which block size is
+less than the page size, the file's mapped blocks within one page will
+be marked as unwritten, we should remove writable userspace mappings to
+ensure that ext4_page_mkwrite() can be called during subsequent write
+access to these partial folios. Otherwise, data written by subsequent
+mmap writes may not be saved to disk.
+
+ $mkfs.ext4 -b 1024 /dev/vdb
+ $mount /dev/vdb /mnt
+ $xfs_io -t -f -c "pwrite -S 0x58 0 4096" -c "mmap -rw 0 4096" \
+ -c "mwrite -S 0x5a 2048 2048" -c "fzero 2048 2048" \
+ -c "mwrite -S 0x59 2048 2048" -c "close" /mnt/foo
+
+ $od -Ax -t x1z /mnt/foo
+ 000000 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58
+ *
+ 000800 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59
+ *
+ 001000
+
+ $umount /mnt && mount /dev/vdb /mnt
+ $od -Ax -t x1z /mnt/foo
+ 000000 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58
+ *
+ 000800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ *
+ 001000
+
+Fix this by introducing ext4_truncate_page_cache_block_range() to remove
+writable userspace mappings when truncating a partial folio range.
+Additionally, move the journal data mode-specific handlers and
+truncate_pagecache_range() into this function, allowing it to serve as a
+common helper that correctly manages the page cache in preparation for
+block range manipulations.
+
+Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
+Link: https://patch.msgid.link/20241220011637.1157197-2-yi.zhang@huaweicloud.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/ext4.h | 2 ++
+ fs/ext4/extents.c | 19 ++++----------
+ fs/ext4/inode.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 70 insertions(+), 14 deletions(-)
+
+diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
+index d4d285d999311..4f81983b79186 100644
+--- a/fs/ext4/ext4.h
++++ b/fs/ext4/ext4.h
+@@ -3011,6 +3011,8 @@ extern int ext4_inode_attach_jinode(struct inode *inode);
+ extern int ext4_can_truncate(struct inode *inode);
+ extern int ext4_truncate(struct inode *);
+ extern int ext4_break_layouts(struct inode *);
++extern int ext4_truncate_page_cache_block_range(struct inode *inode,
++ loff_t start, loff_t end);
+ extern int ext4_punch_hole(struct file *file, loff_t offset, loff_t length);
+ extern void ext4_set_inode_flags(struct inode *, bool init);
+ extern int ext4_alloc_da_blocks(struct inode *inode);
+diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
+index a07a98a4b97a5..8dc6b4271b15d 100644
+--- a/fs/ext4/extents.c
++++ b/fs/ext4/extents.c
+@@ -4667,22 +4667,13 @@ static long ext4_zero_range(struct file *file, loff_t offset,
+ goto out_mutex;
+ }
+
+- /*
+- * For journalled data we need to write (and checkpoint) pages
+- * before discarding page cache to avoid inconsitent data on
+- * disk in case of crash before zeroing trans is committed.
+- */
+- if (ext4_should_journal_data(inode)) {
+- ret = filemap_write_and_wait_range(mapping, start,
+- end - 1);
+- if (ret) {
+- filemap_invalidate_unlock(mapping);
+- goto out_mutex;
+- }
++ /* Now release the pages and zero block aligned part of pages */
++ ret = ext4_truncate_page_cache_block_range(inode, start, end);
++ if (ret) {
++ filemap_invalidate_unlock(mapping);
++ goto out_mutex;
+ }
+
+- /* Now release the pages and zero block aligned part of pages */
+- truncate_pagecache_range(inode, start, end - 1);
+ inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
+
+ ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size,
+diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
+index 377fec39b24be..44780bb537f95 100644
+--- a/fs/ext4/inode.c
++++ b/fs/ext4/inode.c
+@@ -31,6 +31,7 @@
+ #include <linux/writeback.h>
+ #include <linux/pagevec.h>
+ #include <linux/mpage.h>
++#include <linux/rmap.h>
+ #include <linux/namei.h>
+ #include <linux/uio.h>
+ #include <linux/bio.h>
+@@ -3903,6 +3904,68 @@ int ext4_update_disksize_before_punch(struct inode *inode, loff_t offset,
+ return ret;
+ }
+
++static inline void ext4_truncate_folio(struct inode *inode,
++ loff_t start, loff_t end)
++{
++ unsigned long blocksize = i_blocksize(inode);
++ struct folio *folio;
++
++ /* Nothing to be done if no complete block needs to be truncated. */
++ if (round_up(start, blocksize) >= round_down(end, blocksize))
++ return;
++
++ folio = filemap_lock_folio(inode->i_mapping, start >> PAGE_SHIFT);
++ if (IS_ERR(folio))
++ return;
++
++ if (folio_mkclean(folio))
++ folio_mark_dirty(folio);
++ folio_unlock(folio);
++ folio_put(folio);
++}
++
++int ext4_truncate_page_cache_block_range(struct inode *inode,
++ loff_t start, loff_t end)
++{
++ unsigned long blocksize = i_blocksize(inode);
++ int ret;
++
++ /*
++ * For journalled data we need to write (and checkpoint) pages
++ * before discarding page cache to avoid inconsitent data on disk
++ * in case of crash before freeing or unwritten converting trans
++ * is committed.
++ */
++ if (ext4_should_journal_data(inode)) {
++ ret = filemap_write_and_wait_range(inode->i_mapping, start,
++ end - 1);
++ if (ret)
++ return ret;
++ goto truncate_pagecache;
++ }
++
++ /*
++ * If the block size is less than the page size, the file's mapped
++ * blocks within one page could be freed or converted to unwritten.
++ * So it's necessary to remove writable userspace mappings, and then
++ * ext4_page_mkwrite() can be called during subsequent write access
++ * to these partial folios.
++ */
++ if (!IS_ALIGNED(start | end, PAGE_SIZE) &&
++ blocksize < PAGE_SIZE && start < inode->i_size) {
++ loff_t page_boundary = round_up(start, PAGE_SIZE);
++
++ ext4_truncate_folio(inode, start, min(page_boundary, end));
++ if (end > page_boundary)
++ ext4_truncate_folio(inode,
++ round_down(end, PAGE_SIZE), end);
++ }
++
++truncate_pagecache:
++ truncate_pagecache_range(inode, start, end - 1);
++ return 0;
++}
++
+ static void ext4_wait_dax_page(struct inode *inode)
+ {
+ filemap_invalidate_unlock(inode->i_mapping);
+--
+2.39.5
+
--- /dev/null
+From 344dee38f237f5bbd8d74857a9f59cf10df01ee4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 2 Mar 2025 17:06:39 +0100
+Subject: ext4: reorder capability check last
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Christian Göttsche <cgzones@googlemail.com>
+
+[ Upstream commit 1b419c889c0767a5b66d0a6c566cae491f1cb0f7 ]
+
+capable() calls refer to enabled LSMs whether to permit or deny the
+request. This is relevant in connection with SELinux, where a
+capability check results in a policy decision and by default a denial
+message on insufficient permission is issued.
+It can lead to three undesired cases:
+ 1. A denial message is generated, even in case the operation was an
+ unprivileged one and thus the syscall succeeded, creating noise.
+ 2. To avoid the noise from 1. the policy writer adds a rule to ignore
+ those denial messages, hiding future syscalls, where the task
+ performs an actual privileged operation, leading to hidden limited
+ functionality of that task.
+ 3. To avoid the noise from 1. the policy writer adds a rule to permit
+ the task the requested capability, while it does not need it,
+ violating the principle of least privilege.
+
+Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
+Reviewed-by: Serge Hallyn <serge@hallyn.com>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Link: https://patch.msgid.link/20250302160657.127253-2-cgoettsche@seltendoof.de
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/balloc.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
+index 8042ad8738089..c48fd36b2d74c 100644
+--- a/fs/ext4/balloc.c
++++ b/fs/ext4/balloc.c
+@@ -649,8 +649,8 @@ static int ext4_has_free_clusters(struct ext4_sb_info *sbi,
+ /* Hm, nope. Are (enough) root reserved clusters available? */
+ if (uid_eq(sbi->s_resuid, current_fsuid()) ||
+ (!gid_eq(sbi->s_resgid, GLOBAL_ROOT_GID) && in_group_p(sbi->s_resgid)) ||
+- capable(CAP_SYS_RESOURCE) ||
+- (flags & EXT4_MB_USE_ROOT_BLOCKS)) {
++ (flags & EXT4_MB_USE_ROOT_BLOCKS) ||
++ capable(CAP_SYS_RESOURCE)) {
+
+ if (free_clusters >= (nclusters + dirty_clusters +
+ resv_clusters))
+--
+2.39.5
+
--- /dev/null
+From 442e4090bb78d5dce4506a591214ce2447d6ea50 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Mar 2025 11:12:17 -0600
+Subject: f2fs: defer readonly check vs norecovery
+
+From: Eric Sandeen <sandeen@redhat.com>
+
+[ Upstream commit 9cca49875997a1a7e92800a828a62bacb0f577b9 ]
+
+Defer the readonly-vs-norecovery check until after option parsing is done
+so that option parsing does not require an active superblock for the test.
+Add a helpful message, while we're at it.
+
+(I think could be moved back into parsing after we switch to the new mount
+API if desired, as the fs context will have RO state available.)
+
+Signed-off-by: Eric Sandeen <sandeen@redhat.com>
+Reviewed-by: Chao Yu <chao@kernel.org>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/f2fs/super.c | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
+index b8a0e925a4011..d3b04a589b525 100644
+--- a/fs/f2fs/super.c
++++ b/fs/f2fs/super.c
+@@ -728,10 +728,8 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount)
+ set_opt(sbi, DISABLE_ROLL_FORWARD);
+ break;
+ case Opt_norecovery:
+- /* this option mounts f2fs with ro */
++ /* requires ro mount, checked in f2fs_default_check */
+ set_opt(sbi, NORECOVERY);
+- if (!f2fs_readonly(sb))
+- return -EINVAL;
+ break;
+ case Opt_discard:
+ if (!f2fs_hw_support_discard(sbi)) {
+@@ -1418,6 +1416,12 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount)
+ f2fs_err(sbi, "Allow to mount readonly mode only");
+ return -EROFS;
+ }
++
++ if (test_opt(sbi, NORECOVERY) && !f2fs_readonly(sbi->sb)) {
++ f2fs_err(sbi, "norecovery requires readonly mount");
++ return -EINVAL;
++ }
++
+ return 0;
+ }
+
+--
+2.39.5
+
--- /dev/null
+From 14ce4b28aacc75f397cf8d1265effffec7dfd861 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jan 2025 05:06:07 +0000
+Subject: f2fs: introduce f2fs_base_attr for global sysfs entries
+
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+
+[ Upstream commit 21925ede449e038ed6f9efdfe0e79f15bddc34bc ]
+
+In /sys/fs/f2fs/features, there's no f2fs_sb_info, so let's avoid to get
+the pointer.
+
+Reviewed-by: Chao Yu <chao@kernel.org>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/f2fs/sysfs.c | 74 ++++++++++++++++++++++++++++++++++---------------
+ 1 file changed, 52 insertions(+), 22 deletions(-)
+
+diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c
+index d15c68b28952b..b419555e1ea7f 100644
+--- a/fs/f2fs/sysfs.c
++++ b/fs/f2fs/sysfs.c
+@@ -61,6 +61,12 @@ struct f2fs_attr {
+ int id;
+ };
+
++struct f2fs_base_attr {
++ struct attribute attr;
++ ssize_t (*show)(struct f2fs_base_attr *a, char *buf);
++ ssize_t (*store)(struct f2fs_base_attr *a, const char *buf, size_t len);
++};
++
+ static ssize_t f2fs_sbi_show(struct f2fs_attr *a,
+ struct f2fs_sb_info *sbi, char *buf);
+
+@@ -862,6 +868,25 @@ static void f2fs_sb_release(struct kobject *kobj)
+ complete(&sbi->s_kobj_unregister);
+ }
+
++static ssize_t f2fs_base_attr_show(struct kobject *kobj,
++ struct attribute *attr, char *buf)
++{
++ struct f2fs_base_attr *a = container_of(attr,
++ struct f2fs_base_attr, attr);
++
++ return a->show ? a->show(a, buf) : 0;
++}
++
++static ssize_t f2fs_base_attr_store(struct kobject *kobj,
++ struct attribute *attr,
++ const char *buf, size_t len)
++{
++ struct f2fs_base_attr *a = container_of(attr,
++ struct f2fs_base_attr, attr);
++
++ return a->store ? a->store(a, buf, len) : 0;
++}
++
+ /*
+ * Note that there are three feature list entries:
+ * 1) /sys/fs/f2fs/features
+@@ -880,14 +905,13 @@ static void f2fs_sb_release(struct kobject *kobj)
+ * please add new on-disk feature in this list only.
+ * - ref. F2FS_SB_FEATURE_RO_ATTR()
+ */
+-static ssize_t f2fs_feature_show(struct f2fs_attr *a,
+- struct f2fs_sb_info *sbi, char *buf)
++static ssize_t f2fs_feature_show(struct f2fs_base_attr *a, char *buf)
+ {
+ return sysfs_emit(buf, "supported\n");
+ }
+
+ #define F2FS_FEATURE_RO_ATTR(_name) \
+-static struct f2fs_attr f2fs_attr_##_name = { \
++static struct f2fs_base_attr f2fs_base_attr_##_name = { \
+ .attr = {.name = __stringify(_name), .mode = 0444 }, \
+ .show = f2fs_feature_show, \
+ }
+@@ -1256,37 +1280,38 @@ static struct attribute *f2fs_attrs[] = {
+ };
+ ATTRIBUTE_GROUPS(f2fs);
+
++#define BASE_ATTR_LIST(name) (&f2fs_base_attr_##name.attr)
+ static struct attribute *f2fs_feat_attrs[] = {
+ #ifdef CONFIG_FS_ENCRYPTION
+- ATTR_LIST(encryption),
+- ATTR_LIST(test_dummy_encryption_v2),
++ BASE_ATTR_LIST(encryption),
++ BASE_ATTR_LIST(test_dummy_encryption_v2),
+ #if IS_ENABLED(CONFIG_UNICODE)
+- ATTR_LIST(encrypted_casefold),
++ BASE_ATTR_LIST(encrypted_casefold),
+ #endif
+ #endif /* CONFIG_FS_ENCRYPTION */
+ #ifdef CONFIG_BLK_DEV_ZONED
+- ATTR_LIST(block_zoned),
++ BASE_ATTR_LIST(block_zoned),
+ #endif
+- ATTR_LIST(atomic_write),
+- ATTR_LIST(extra_attr),
+- ATTR_LIST(project_quota),
+- ATTR_LIST(inode_checksum),
+- ATTR_LIST(flexible_inline_xattr),
+- ATTR_LIST(quota_ino),
+- ATTR_LIST(inode_crtime),
+- ATTR_LIST(lost_found),
++ BASE_ATTR_LIST(atomic_write),
++ BASE_ATTR_LIST(extra_attr),
++ BASE_ATTR_LIST(project_quota),
++ BASE_ATTR_LIST(inode_checksum),
++ BASE_ATTR_LIST(flexible_inline_xattr),
++ BASE_ATTR_LIST(quota_ino),
++ BASE_ATTR_LIST(inode_crtime),
++ BASE_ATTR_LIST(lost_found),
+ #ifdef CONFIG_FS_VERITY
+- ATTR_LIST(verity),
++ BASE_ATTR_LIST(verity),
+ #endif
+- ATTR_LIST(sb_checksum),
++ BASE_ATTR_LIST(sb_checksum),
+ #if IS_ENABLED(CONFIG_UNICODE)
+- ATTR_LIST(casefold),
++ BASE_ATTR_LIST(casefold),
+ #endif
+- ATTR_LIST(readonly),
++ BASE_ATTR_LIST(readonly),
+ #ifdef CONFIG_F2FS_FS_COMPRESSION
+- ATTR_LIST(compression),
++ BASE_ATTR_LIST(compression),
+ #endif
+- ATTR_LIST(pin_file),
++ BASE_ATTR_LIST(pin_file),
+ NULL,
+ };
+ ATTRIBUTE_GROUPS(f2fs_feat);
+@@ -1362,9 +1387,14 @@ static struct kset f2fs_kset = {
+ .kobj = {.ktype = &f2fs_ktype},
+ };
+
++static const struct sysfs_ops f2fs_feat_attr_ops = {
++ .show = f2fs_base_attr_show,
++ .store = f2fs_base_attr_store,
++};
++
+ static const struct kobj_type f2fs_feat_ktype = {
+ .default_groups = f2fs_feat_groups,
+- .sysfs_ops = &f2fs_attr_ops,
++ .sysfs_ops = &f2fs_feat_attr_ops,
+ };
+
+ static struct kobject f2fs_feat = {
+--
+2.39.5
+
--- /dev/null
+From b2d40f00da6ed825af69cded987c1a79c70b0a04 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 2 Feb 2025 21:33:46 +0100
+Subject: fbcon: Use correct erase colour for clearing in fbcon
+
+From: Zsolt Kajtar <soci@c64.rulez.org>
+
+[ Upstream commit 892c788d73fe4a94337ed092cb998c49fa8ecaf4 ]
+
+The erase colour calculation for fbcon clearing should use get_color instead
+of attr_col_ec, like everything else. The latter is similar but is not correct.
+For example it's missing the depth dependent remapping and doesn't care about
+blanking.
+
+The problem can be reproduced by setting up the background colour to grey
+(vt.color=0x70) and having an fbcon console set to 2bpp (4 shades of gray).
+Now the background attribute should be 1 (dark gray) on the console.
+
+If the screen is scrolled when pressing enter in a shell prompt at the bottom
+line then the new line is cleared using colour 7 instead of 1. That's not
+something fillrect likes (at 2bbp it expect 0-3) so the result is interesting.
+
+This patch switches to get_color with vc_video_erase_char to determine the
+erase colour from attr_col_ec. That makes the latter function redundant as
+no other users were left.
+
+Use correct erase colour for clearing in fbcon
+
+Signed-off-by: Zsolt Kajtar <soci@c64.rulez.org>
+Signed-off-by: Helge Deller <deller@gmx.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/video/fbdev/core/bitblit.c | 5 ++--
+ drivers/video/fbdev/core/fbcon.c | 10 +++++---
+ drivers/video/fbdev/core/fbcon.h | 38 +---------------------------
+ drivers/video/fbdev/core/fbcon_ccw.c | 5 ++--
+ drivers/video/fbdev/core/fbcon_cw.c | 5 ++--
+ drivers/video/fbdev/core/fbcon_ud.c | 5 ++--
+ drivers/video/fbdev/core/tileblit.c | 8 +++---
+ 7 files changed, 18 insertions(+), 58 deletions(-)
+
+diff --git a/drivers/video/fbdev/core/bitblit.c b/drivers/video/fbdev/core/bitblit.c
+index 3ff1b2a8659e8..f9475c14f7339 100644
+--- a/drivers/video/fbdev/core/bitblit.c
++++ b/drivers/video/fbdev/core/bitblit.c
+@@ -59,12 +59,11 @@ static void bit_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+ }
+
+ static void bit_clear(struct vc_data *vc, struct fb_info *info, int sy,
+- int sx, int height, int width)
++ int sx, int height, int width, int fg, int bg)
+ {
+- int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
+ struct fb_fillrect region;
+
+- region.color = attr_bgcol_ec(bgshift, vc, info);
++ region.color = bg;
+ region.dx = sx * vc->vc_font.width;
+ region.dy = sy * vc->vc_font.height;
+ region.width = width * vc->vc_font.width;
+diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
+index e8b4e8c119b5c..07d127110ca4c 100644
+--- a/drivers/video/fbdev/core/fbcon.c
++++ b/drivers/video/fbdev/core/fbcon.c
+@@ -1258,7 +1258,7 @@ static void __fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
+ {
+ struct fb_info *info = fbcon_info_from_console(vc->vc_num);
+ struct fbcon_ops *ops = info->fbcon_par;
+-
++ int fg, bg;
+ struct fbcon_display *p = &fb_display[vc->vc_num];
+ u_int y_break;
+
+@@ -1279,16 +1279,18 @@ static void __fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
+ fbcon_clear_margins(vc, 0);
+ }
+
++ fg = get_color(vc, info, vc->vc_video_erase_char, 1);
++ bg = get_color(vc, info, vc->vc_video_erase_char, 0);
+ /* Split blits that cross physical y_wrap boundary */
+
+ 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);
++ 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);
++ width, fg, bg);
+ } else
+- ops->clear(vc, info, real_y(p, sy), sx, height, width);
++ ops->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,
+diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h
+index df70ea5ec5b37..4d97e6d8a16a2 100644
+--- a/drivers/video/fbdev/core/fbcon.h
++++ b/drivers/video/fbdev/core/fbcon.h
+@@ -55,7 +55,7 @@ struct fbcon_ops {
+ 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,
+- int sx, int height, int width);
++ int sx, int height, int width, int fb, int bg);
+ void (*putcs)(struct vc_data *vc, struct fb_info *info,
+ const unsigned short *s, int count, int yy, int xx,
+ int fg, int bg);
+@@ -116,42 +116,6 @@ static inline int mono_col(const struct fb_info *info)
+ return (~(0xfff << max_len)) & 0xff;
+ }
+
+-static inline int attr_col_ec(int shift, struct vc_data *vc,
+- struct fb_info *info, int is_fg)
+-{
+- int is_mono01;
+- int col;
+- int fg;
+- int bg;
+-
+- if (!vc)
+- return 0;
+-
+- if (vc->vc_can_do_color)
+- return is_fg ? attr_fgcol(shift,vc->vc_video_erase_char)
+- : attr_bgcol(shift,vc->vc_video_erase_char);
+-
+- if (!info)
+- return 0;
+-
+- col = mono_col(info);
+- is_mono01 = info->fix.visual == FB_VISUAL_MONO01;
+-
+- if (attr_reverse(vc->vc_video_erase_char)) {
+- fg = is_mono01 ? col : 0;
+- bg = is_mono01 ? 0 : col;
+- }
+- else {
+- fg = is_mono01 ? 0 : col;
+- bg = is_mono01 ? col : 0;
+- }
+-
+- return is_fg ? fg : bg;
+-}
+-
+-#define attr_bgcol_ec(bgshift, vc, info) attr_col_ec(bgshift, vc, info, 0)
+-#define attr_fgcol_ec(fgshift, vc, info) attr_col_ec(fgshift, vc, info, 1)
+-
+ /*
+ * Scroll Method
+ */
+diff --git a/drivers/video/fbdev/core/fbcon_ccw.c b/drivers/video/fbdev/core/fbcon_ccw.c
+index f9b794ff7d396..89ef4ba7e8672 100644
+--- a/drivers/video/fbdev/core/fbcon_ccw.c
++++ b/drivers/video/fbdev/core/fbcon_ccw.c
+@@ -78,14 +78,13 @@ 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 sx, int height, int width, int fg, int bg)
+ {
+ struct fbcon_ops *ops = info->fbcon_par;
+ struct fb_fillrect region;
+- int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
+ u32 vyres = GETVYRES(ops->p, info);
+
+- region.color = attr_bgcol_ec(bgshift,vc,info);
++ region.color = bg;
+ region.dx = sy * vc->vc_font.height;
+ region.dy = vyres - ((sx + width) * vc->vc_font.width);
+ region.height = width * vc->vc_font.width;
+diff --git a/drivers/video/fbdev/core/fbcon_cw.c b/drivers/video/fbdev/core/fbcon_cw.c
+index 903f6fc174e14..b9dac7940fb77 100644
+--- a/drivers/video/fbdev/core/fbcon_cw.c
++++ b/drivers/video/fbdev/core/fbcon_cw.c
+@@ -63,14 +63,13 @@ 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 sx, int height, int width, int fg, int bg)
+ {
+ struct fbcon_ops *ops = info->fbcon_par;
+ struct fb_fillrect region;
+- int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
+ u32 vxres = GETVXRES(ops->p, info);
+
+- region.color = attr_bgcol_ec(bgshift,vc,info);
++ region.color = bg;
+ region.dx = vxres - ((sy + height) * vc->vc_font.height);
+ region.dy = sx * vc->vc_font.width;
+ region.height = width * vc->vc_font.width;
+diff --git a/drivers/video/fbdev/core/fbcon_ud.c b/drivers/video/fbdev/core/fbcon_ud.c
+index 594331936fd3c..0af7913a2abdc 100644
+--- a/drivers/video/fbdev/core/fbcon_ud.c
++++ b/drivers/video/fbdev/core/fbcon_ud.c
+@@ -64,15 +64,14 @@ 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 sx, int height, int width, int fg, int bg)
+ {
+ struct fbcon_ops *ops = info->fbcon_par;
+ struct fb_fillrect region;
+- int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
+ u32 vyres = GETVYRES(ops->p, info);
+ u32 vxres = GETVXRES(ops->p, info);
+
+- region.color = attr_bgcol_ec(bgshift,vc,info);
++ region.color = bg;
+ region.dy = vyres - ((sy + height) * vc->vc_font.height);
+ region.dx = vxres - ((sx + width) * vc->vc_font.width);
+ region.width = width * vc->vc_font.width;
+diff --git a/drivers/video/fbdev/core/tileblit.c b/drivers/video/fbdev/core/tileblit.c
+index eff7ec4da1671..45b0828fad1cf 100644
+--- a/drivers/video/fbdev/core/tileblit.c
++++ b/drivers/video/fbdev/core/tileblit.c
+@@ -32,16 +32,14 @@ static void tile_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+ }
+
+ static void tile_clear(struct vc_data *vc, struct fb_info *info, int sy,
+- int sx, int height, int width)
++ int sx, int height, int width, int fg, int bg)
+ {
+ struct fb_tilerect rect;
+- int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
+- int fgshift = (vc->vc_hi_font_mask) ? 9 : 8;
+
+ rect.index = vc->vc_video_erase_char &
+ ((vc->vc_hi_font_mask) ? 0x1ff : 0xff);
+- rect.fg = attr_fgcol_ec(fgshift, vc, info);
+- rect.bg = attr_bgcol_ec(bgshift, vc, info);
++ rect.fg = fg;
++ rect.bg = bg;
+ rect.sx = sx;
+ rect.sy = sy;
+ rect.width = width;
+--
+2.39.5
+
--- /dev/null
+From ef156cbb38f984b547082e4877e007dda2384fe1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 1 Feb 2025 09:18:09 +0100
+Subject: fbdev: core: tileblit: Implement missing margin clearing for tileblit
+
+From: Zsolt Kajtar <soci@c64.rulez.org>
+
+[ Upstream commit 76d3ca89981354e1f85a3e0ad9ac4217d351cc72 ]
+
+I was wondering why there's garbage at the bottom of the screen when
+tile blitting is used with an odd mode like 1080, 600 or 200. Sure there's
+only space for half a tile but the same area is clean when the buffer
+is bitmap.
+
+Then later I found that it's supposed to be cleaned but that's not
+implemented. So I took what's in bitblit and adapted it for tileblit.
+
+This implementation was tested for both the horizontal and vertical case,
+and now does the same as what's done for bitmap buffers.
+
+If anyone is interested to reproduce the problem then I could bet that'd
+be on a S3 or Ark. Just set up a mode with an odd line count and make
+sure that the virtual size covers the complete tile at the bottom. E.g.
+for 600 lines that's 608 virtual lines for a 16 tall tile. Then the
+bottom area should be cleaned.
+
+For the right side it's more difficult as there the drivers won't let an
+odd size happen, unless the code is modified. But once it reports back a
+few pixel columns short then fbcon won't use the last column. With the
+patch that column is now clean.
+
+Btw. the virtual size should be rounded up by the driver for both axes
+(not only the horizontal) so that it's dividable by the tile size.
+That's a driver bug but correcting it is not in scope for this patch.
+
+Implement missing margin clearing for tileblit
+
+Signed-off-by: Zsolt Kajtar <soci@c64.rulez.org>
+Signed-off-by: Helge Deller <deller@gmx.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/video/fbdev/core/tileblit.c | 37 ++++++++++++++++++++++++++++-
+ 1 file changed, 36 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/video/fbdev/core/tileblit.c b/drivers/video/fbdev/core/tileblit.c
+index 45b0828fad1cf..d342b90c42b7f 100644
+--- a/drivers/video/fbdev/core/tileblit.c
++++ b/drivers/video/fbdev/core/tileblit.c
+@@ -74,7 +74,42 @@ static void tile_putcs(struct vc_data *vc, struct fb_info *info,
+ static void tile_clear_margins(struct vc_data *vc, struct fb_info *info,
+ int color, int bottom_only)
+ {
+- return;
++ unsigned int cw = vc->vc_font.width;
++ unsigned int ch = vc->vc_font.height;
++ unsigned int rw = info->var.xres - (vc->vc_cols*cw);
++ unsigned int bh = info->var.yres - (vc->vc_rows*ch);
++ unsigned int rs = info->var.xres - rw;
++ unsigned int bs = info->var.yres - bh;
++ unsigned int vwt = info->var.xres_virtual / cw;
++ unsigned int vht = info->var.yres_virtual / ch;
++ struct fb_tilerect rect;
++
++ rect.index = vc->vc_video_erase_char &
++ ((vc->vc_hi_font_mask) ? 0x1ff : 0xff);
++ rect.fg = color;
++ rect.bg = color;
++
++ if ((int) rw > 0 && !bottom_only) {
++ rect.sx = (info->var.xoffset + rs + cw - 1) / cw;
++ rect.sy = 0;
++ rect.width = (rw + cw - 1) / cw;
++ rect.height = vht;
++ if (rect.width + rect.sx > vwt)
++ rect.width = vwt - rect.sx;
++ if (rect.sx < vwt)
++ info->tileops->fb_tilefill(info, &rect);
++ }
++
++ if ((int) bh > 0) {
++ rect.sx = info->var.xoffset / cw;
++ rect.sy = (info->var.yoffset + bs) / ch;
++ rect.width = rs / cw;
++ rect.height = (bh + ch - 1) / ch;
++ if (rect.height + rect.sy > vht)
++ rect.height = vht - rect.sy;
++ if (rect.sy < vht)
++ info->tileops->fb_tilefill(info, &rect);
++ }
+ }
+
+ static void tile_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
+--
+2.39.5
+
--- /dev/null
+From 8d014cc14a7390a7e9f2d1a001ef26f46e3cc778 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 10 Mar 2025 09:54:31 +0800
+Subject: fbdev: fsl-diu-fb: add missing device_remove_file()
+
+From: Shixiong Ou <oushixiong@kylinos.cn>
+
+[ Upstream commit 86d16cd12efa547ed43d16ba7a782c1251c80ea8 ]
+
+Call device_remove_file() when driver remove.
+
+Signed-off-by: Shixiong Ou <oushixiong@kylinos.cn>
+Signed-off-by: Helge Deller <deller@gmx.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/video/fbdev/fsl-diu-fb.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/video/fbdev/fsl-diu-fb.c b/drivers/video/fbdev/fsl-diu-fb.c
+index 5ac8201c35337..b71d15794ce8b 100644
+--- a/drivers/video/fbdev/fsl-diu-fb.c
++++ b/drivers/video/fbdev/fsl-diu-fb.c
+@@ -1827,6 +1827,7 @@ static void fsl_diu_remove(struct platform_device *pdev)
+ int i;
+
+ data = dev_get_drvdata(&pdev->dev);
++ device_remove_file(&pdev->dev, &data->dev_attr);
+ disable_lcdc(&data->fsl_diu_info[0]);
+
+ free_irq(data->irq, data->diu_reg);
+--
+2.39.5
+
--- /dev/null
+From e65e4401b43e9eaaa0f528b8b3615ff93f4e1f79 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 17 Feb 2025 15:38:48 +0000
+Subject: firmware: arm_ffa: Handle the presence of host partition in the
+ partition info
+
+From: Sudeep Holla <sudeep.holla@arm.com>
+
+[ Upstream commit 2f622a8b0722d332a2a149794a3add47bc9bdcf3 ]
+
+Currently it is assumed that the firmware doesn't present the host
+partition in the list of partitions presented as part of the response
+to PARTITION_INFO_GET from the firmware. However, there are few
+platforms that prefer to present the same in the list of partitions.
+It is not manadatory but not restricted as well.
+
+So handle the same by making sure to check the presence of the host
+VM ID in the XArray partition information maintained/managed in the
+driver before attempting to add it.
+
+Tested-by: Viresh Kumar <viresh.kumar@linaro.org>
+Message-Id: <20250217-ffa_updates-v3-7-bd1d9de615e7@arm.com>
+Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/firmware/arm_ffa/driver.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c
+index ca9a27fceb1fd..d545d25132051 100644
+--- a/drivers/firmware/arm_ffa/driver.c
++++ b/drivers/firmware/arm_ffa/driver.c
+@@ -1458,6 +1458,10 @@ static int ffa_setup_partitions(void)
+
+ kfree(pbuf);
+
++ /* Check if the host is already added as part of partition info */
++ if (xa_load(&drv_info->partition_info, drv_info->vm_id))
++ return 0;
++
+ /* Allocate for the host */
+ ret = ffa_xa_add_partition_info(drv_info->vm_id);
+ if (ret)
+--
+2.39.5
+
--- /dev/null
+From 68ecbc3b3d270f5c18dd95c85ba5dc31d382f6fe Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 17 Feb 2025 15:38:53 +0000
+Subject: firmware: arm_ffa: Reject higher major version as incompatible
+
+From: Sudeep Holla <sudeep.holla@arm.com>
+
+[ Upstream commit efff6a7f16b34fd902f342b58bd8bafc2d6f2fd1 ]
+
+When the firmware compatibility was handled previously in the commit
+8e3f9da608f1 ("firmware: arm_ffa: Handle compatibility with different firmware versions"),
+we only addressed firmware versions that have higher minor versions
+compared to the driver version which is should be considered compatible
+unless the firmware returns NOT_SUPPORTED.
+
+However, if the firmware reports higher major version than the driver
+supported, we need to reject it. If the firmware can work in a compatible
+mode with the driver requested version, it must return the same major
+version as requested.
+
+Tested-by: Viresh Kumar <viresh.kumar@linaro.org>
+Message-Id: <20250217-ffa_updates-v3-12-bd1d9de615e7@arm.com>
+Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/firmware/arm_ffa/driver.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c
+index 03d22cbb2ad47..ca9a27fceb1fd 100644
+--- a/drivers/firmware/arm_ffa/driver.c
++++ b/drivers/firmware/arm_ffa/driver.c
+@@ -150,6 +150,14 @@ static int ffa_version_check(u32 *version)
+ return -EOPNOTSUPP;
+ }
+
++ if (FFA_MAJOR_VERSION(ver.a0) > FFA_MAJOR_VERSION(FFA_DRIVER_VERSION)) {
++ pr_err("Incompatible v%d.%d! Latest supported v%d.%d\n",
++ FFA_MAJOR_VERSION(ver.a0), FFA_MINOR_VERSION(ver.a0),
++ FFA_MAJOR_VERSION(FFA_DRIVER_VERSION),
++ FFA_MINOR_VERSION(FFA_DRIVER_VERSION));
++ return -EINVAL;
++ }
++
+ if (ver.a0 < FFA_MIN_VERSION) {
+ pr_err("Incompatible v%d.%d! Earliest supported v%d.%d\n",
+ FFA_MAJOR_VERSION(ver.a0), FFA_MINOR_VERSION(ver.a0),
+--
+2.39.5
+
--- /dev/null
+From f5cd34d540dc56cea06664b6a2259cd4b60ef0a4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 17 Jan 2025 15:35:52 +0530
+Subject: firmware: arm_ffa: Set dma_mask for ffa devices
+
+From: Viresh Kumar <viresh.kumar@linaro.org>
+
+[ Upstream commit cc0aac7ca17e0ea3ca84b552fc79f3e86fd07f53 ]
+
+Set dma_mask for FFA devices, otherwise DMA allocation using the device pointer
+lead to following warning:
+
+WARNING: CPU: 1 PID: 1 at kernel/dma/mapping.c:597 dma_alloc_attrs+0xe0/0x124
+
+Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
+Message-Id: <e3dd8042ac680bd74b6580c25df855d092079c18.1737107520.git.viresh.kumar@linaro.org>
+Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/firmware/arm_ffa/bus.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/firmware/arm_ffa/bus.c b/drivers/firmware/arm_ffa/bus.c
+index fa09a82b44921..eacde92802f58 100644
+--- a/drivers/firmware/arm_ffa/bus.c
++++ b/drivers/firmware/arm_ffa/bus.c
+@@ -213,6 +213,7 @@ ffa_device_register(const struct ffa_partition_info *part_info,
+ dev = &ffa_dev->dev;
+ dev->bus = &ffa_bus_type;
+ dev->release = ffa_release_device;
++ dev->dma_mask = &dev->coherent_dma_mask;
+ dev_set_name(&ffa_dev->dev, "arm-ffa-%d", id);
+
+ ffa_dev->id = id;
+--
+2.39.5
+
--- /dev/null
+From 70565a16bac0fca6661a7ba97fe312f986a98ed8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jan 2025 14:18:20 +0000
+Subject: firmware: arm_scmi: Relax duplicate name constraint across protocol
+ ids
+
+From: Sudeep Holla <sudeep.holla@arm.com>
+
+[ Upstream commit 21ee965267bcbdd733be0f35344fa0f0226d7861 ]
+
+Currently in scmi_protocol_device_request(), no duplicate scmi device
+name is allowed across any protocol. However scmi_dev_match_id() first
+matches the protocol id and then the name. So, there is no strict
+requirement to keep this scmi device name unique across all the protocols.
+
+Relax the constraint on the duplicate name across the protocols and
+inhibit only within the same protocol id.
+
+Message-Id: <20250131141822.514342-1-sudeep.holla@arm.com>
+Reviewed-by: Dhruva Gole <d-gole@ti.com>
+Reviewed-by: Peng Fan <peng.fan@nxp.com>
+Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/firmware/arm_scmi/bus.c | 19 ++++++-------------
+ 1 file changed, 6 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/firmware/arm_scmi/bus.c b/drivers/firmware/arm_scmi/bus.c
+index 7d7af2262c013..5d799f6626963 100644
+--- a/drivers/firmware/arm_scmi/bus.c
++++ b/drivers/firmware/arm_scmi/bus.c
+@@ -42,7 +42,7 @@ static atomic_t scmi_syspower_registered = ATOMIC_INIT(0);
+ * This helper let an SCMI driver request specific devices identified by the
+ * @id_table to be created for each active SCMI instance.
+ *
+- * The requested device name MUST NOT be already existent for any protocol;
++ * The requested device name MUST NOT be already existent for this protocol;
+ * at first the freshly requested @id_table is annotated in the IDR table
+ * @scmi_requested_devices and then the requested device is advertised to any
+ * registered party via the @scmi_requested_devices_nh notification chain.
+@@ -52,7 +52,6 @@ static atomic_t scmi_syspower_registered = ATOMIC_INIT(0);
+ static int scmi_protocol_device_request(const struct scmi_device_id *id_table)
+ {
+ int ret = 0;
+- unsigned int id = 0;
+ struct list_head *head, *phead = NULL;
+ struct scmi_requested_dev *rdev;
+
+@@ -67,19 +66,13 @@ static int scmi_protocol_device_request(const struct scmi_device_id *id_table)
+ }
+
+ /*
+- * Search for the matching protocol rdev list and then search
+- * of any existent equally named device...fails if any duplicate found.
++ * Find the matching protocol rdev list and then search of any
++ * existent equally named device...fails if any duplicate found.
+ */
+ mutex_lock(&scmi_requested_devices_mtx);
+- idr_for_each_entry(&scmi_requested_devices, head, id) {
+- if (!phead) {
+- /* A list found registered in the IDR is never empty */
+- rdev = list_first_entry(head, struct scmi_requested_dev,
+- node);
+- if (rdev->id_table->protocol_id ==
+- id_table->protocol_id)
+- phead = head;
+- }
++ phead = idr_find(&scmi_requested_devices, id_table->protocol_id);
++ if (phead) {
++ head = phead;
+ list_for_each_entry(rdev, head, node) {
+ if (!strcmp(rdev->id_table->name, id_table->name)) {
+ pr_err("Ignoring duplicate request [%d] %s\n",
+--
+2.39.5
+
--- /dev/null
+From 4c207afab71ea04998a6332dbd781963a5e2b84c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 7 Feb 2025 11:19:51 +0530
+Subject: firmware: xilinx: Dont send linux address to get fpga config get
+ status
+
+From: Siva Durga Prasad Paladugu <siva.durga.prasad.paladugu@amd.com>
+
+[ Upstream commit 5abc174016052caff1bcf4cedb159bd388411e98 ]
+
+Fpga get config status just returns status through ret_payload and there
+is no need to allocate local buf and send its address through SMC args.
+Moreover, the address that is being passed till now is linux virtual
+address and is incorrect.
+Corresponding modification has been done in the firmware to avoid using the
+address sent by linux.
+
+Signed-off-by: Siva Durga Prasad Paladugu <siva.durga.prasad.paladugu@amd.com>
+Signed-off-by: Nava kishore Manne <nava.kishore.manne@amd.com>
+Link: https://lore.kernel.org/r/20250207054951.1650534-1-nava.kishore.manne@amd.com
+Signed-off-by: Michal Simek <michal.simek@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/firmware/xilinx/zynqmp.c | 6 +-----
+ 1 file changed, 1 insertion(+), 5 deletions(-)
+
+diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c
+index 720fa8b5d8e95..7356e860e65ce 100644
+--- a/drivers/firmware/xilinx/zynqmp.c
++++ b/drivers/firmware/xilinx/zynqmp.c
+@@ -1139,17 +1139,13 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_fpga_get_status);
+ int zynqmp_pm_fpga_get_config_status(u32 *value)
+ {
+ u32 ret_payload[PAYLOAD_ARG_CNT];
+- u32 buf, lower_addr, upper_addr;
+ int ret;
+
+ if (!value)
+ return -EINVAL;
+
+- lower_addr = lower_32_bits((u64)&buf);
+- upper_addr = upper_32_bits((u64)&buf);
+-
+ ret = zynqmp_pm_invoke_fn(PM_FPGA_READ, ret_payload, 4,
+- XILINX_ZYNQMP_PM_FPGA_CONFIG_STAT_OFFSET, lower_addr, upper_addr,
++ XILINX_ZYNQMP_PM_FPGA_CONFIG_STAT_OFFSET, 0, 0,
+ XILINX_ZYNQMP_PM_FPGA_READ_CONFIG_REG);
+
+ *value = ret_payload[1];
+--
+2.39.5
+
--- /dev/null
+From 849b5ce250695189443c7c028584537794fec6af Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 13 Feb 2025 06:12:49 +0800
+Subject: fpga: altera-cvp: Increase credit timeout
+
+From: Kuhanh Murugasen Krishnan <kuhanh.murugasen.krishnan@intel.com>
+
+[ Upstream commit 0f05886a40fdc55016ba4d9ae0a9c41f8312f15b ]
+
+Increase the timeout for SDM (Secure device manager) data credits from
+20ms to 40ms. Internal stress tests running at 500 loops failed with the
+current timeout of 20ms. At the start of a FPGA configuration, the CVP
+host driver reads the transmit credits from SDM. It then sends bitstream
+FPGA data to SDM based on the total credits. Each credit allows the
+CVP host driver to send 4kBytes of data. There are situations whereby,
+the SDM did not respond in time during testing.
+
+Signed-off-by: Ang Tien Sung <tien.sung.ang@intel.com>
+Signed-off-by: Kuhanh Murugasen Krishnan <kuhanh.murugasen.krishnan@intel.com>
+Acked-by: Xu Yilun <yilun.xu@intel.com>
+Link: https://lore.kernel.org/r/20250212221249.2715929-1-tien.sung.ang@intel.com
+Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/fpga/altera-cvp.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/fpga/altera-cvp.c b/drivers/fpga/altera-cvp.c
+index 6b09144324453..5af0bd33890c0 100644
+--- a/drivers/fpga/altera-cvp.c
++++ b/drivers/fpga/altera-cvp.c
+@@ -52,7 +52,7 @@
+ /* V2 Defines */
+ #define VSE_CVP_TX_CREDITS 0x49 /* 8bit */
+
+-#define V2_CREDIT_TIMEOUT_US 20000
++#define V2_CREDIT_TIMEOUT_US 40000
+ #define V2_CHECK_CREDIT_US 10
+ #define V2_POLL_TIMEOUT_US 1000000
+ #define V2_USER_TIMEOUT_US 500000
+--
+2.39.5
+
--- /dev/null
+From dd2741b79e22a0234b43815164f349e22e10047d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 17 Apr 2025 18:59:16 -0700
+Subject: fs/buffer: introduce sleeping flavors for pagecache lookups
+
+From: Davidlohr Bueso <dave@stgolabs.net>
+
+[ Upstream commit 2814a7d3d2ff5d2cdd22936f641f758fdb971fa0 ]
+
+Add __find_get_block_nonatomic() and sb_find_get_block_nonatomic()
+calls for which users will be converted where safe. These versions
+will take the folio lock instead of the mapping's private_lock.
+
+Reviewed-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
+Link: https://kdevops.org/ext4/v6.15-rc2.html # [0]
+Link: https://lore.kernel.org/all/aAAEvcrmREWa1SKF@bombadil.infradead.org/ # [1]
+Link: https://lore.kernel.org/20250418015921.132400-3-dave@stgolabs.net
+Tested-by: kdevops@lists.linux.dev
+Reviewed-by: Luis Chamberlain <mcgrof@kernel.org>
+Signed-off-by: Christian Brauner <brauner@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/buffer.c | 9 +++++++++
+ include/linux/buffer_head.h | 8 ++++++++
+ 2 files changed, 17 insertions(+)
+
+diff --git a/fs/buffer.c b/fs/buffer.c
+index a03c245022dcf..7981097c846d4 100644
+--- a/fs/buffer.c
++++ b/fs/buffer.c
+@@ -1414,6 +1414,15 @@ __find_get_block(struct block_device *bdev, sector_t block, unsigned size)
+ }
+ EXPORT_SYMBOL(__find_get_block);
+
++/* same as __find_get_block() but allows sleeping contexts */
++struct buffer_head *
++__find_get_block_nonatomic(struct block_device *bdev, sector_t block,
++ unsigned size)
++{
++ return find_get_block_common(bdev, block, size, false);
++}
++EXPORT_SYMBOL(__find_get_block_nonatomic);
++
+ /**
+ * bdev_getblk - Get a buffer_head in a block device's buffer cache.
+ * @bdev: The block device.
+diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h
+index 932139c5d46f5..ffcd76d977703 100644
+--- a/include/linux/buffer_head.h
++++ b/include/linux/buffer_head.h
+@@ -223,6 +223,8 @@ void __wait_on_buffer(struct buffer_head *);
+ wait_queue_head_t *bh_waitq_head(struct buffer_head *bh);
+ struct buffer_head *__find_get_block(struct block_device *bdev, sector_t block,
+ unsigned size);
++struct buffer_head *__find_get_block_nonatomic(struct block_device *bdev,
++ sector_t block, unsigned size);
+ struct buffer_head *bdev_getblk(struct block_device *bdev, sector_t block,
+ unsigned size, gfp_t gfp);
+ void __brelse(struct buffer_head *);
+@@ -398,6 +400,12 @@ sb_find_get_block(struct super_block *sb, sector_t block)
+ return __find_get_block(sb->s_bdev, block, sb->s_blocksize);
+ }
+
++static inline struct buffer_head *
++sb_find_get_block_nonatomic(struct super_block *sb, sector_t block)
++{
++ return __find_get_block_nonatomic(sb->s_bdev, block, sb->s_blocksize);
++}
++
+ static inline void
+ map_bh(struct buffer_head *bh, struct super_block *sb, sector_t block)
+ {
+--
+2.39.5
+
--- /dev/null
+From 40d9fb45714023c40abd52504abdde92504efafc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 17 Apr 2025 18:59:15 -0700
+Subject: fs/buffer: split locking for pagecache lookups
+
+From: Davidlohr Bueso <dave@stgolabs.net>
+
+[ Upstream commit 7ffe3de53a885dbb5836541c2178bd07d1bad7df ]
+
+Callers of __find_get_block() may or may not allow for blocking
+semantics, and is currently assumed that it will not. Layout
+two paths based on this. The the private_lock scheme will
+continued to be used for atomic contexts. Otherwise take the
+folio lock instead, which protects the buffers, such as
+vs migration and try_to_free_buffers().
+
+Per the "hack idea", the latter can alleviate contention on
+the private_lock for bdev mappings. For reasons of determinism
+and avoid making bugs hard to reproduce, the trylocking is not
+attempted.
+
+No change in semantics. All lookup users still take the spinlock.
+
+Reviewed-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
+Link: https://kdevops.org/ext4/v6.15-rc2.html # [0]
+Link: https://lore.kernel.org/all/aAAEvcrmREWa1SKF@bombadil.infradead.org/ # [1]
+Link: https://lore.kernel.org/20250418015921.132400-2-dave@stgolabs.net
+Tested-by: kdevops@lists.linux.dev
+Reviewed-by: Luis Chamberlain <mcgrof@kernel.org>
+Signed-off-by: Christian Brauner <brauner@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/buffer.c | 41 +++++++++++++++++++++++++----------------
+ 1 file changed, 25 insertions(+), 16 deletions(-)
+
+diff --git a/fs/buffer.c b/fs/buffer.c
+index cc8452f602516..a03c245022dcf 100644
+--- a/fs/buffer.c
++++ b/fs/buffer.c
+@@ -176,18 +176,8 @@ void end_buffer_write_sync(struct buffer_head *bh, int uptodate)
+ }
+ EXPORT_SYMBOL(end_buffer_write_sync);
+
+-/*
+- * Various filesystems appear to want __find_get_block to be non-blocking.
+- * But it's the page lock which protects the buffers. To get around this,
+- * we get exclusion from try_to_free_buffers with the blockdev mapping's
+- * i_private_lock.
+- *
+- * Hack idea: for the blockdev mapping, i_private_lock contention
+- * may be quite high. This code could TryLock the page, and if that
+- * succeeds, there is no need to take i_private_lock.
+- */
+ static struct buffer_head *
+-__find_get_block_slow(struct block_device *bdev, sector_t block)
++__find_get_block_slow(struct block_device *bdev, sector_t block, bool atomic)
+ {
+ struct address_space *bd_mapping = bdev->bd_mapping;
+ const int blkbits = bd_mapping->host->i_blkbits;
+@@ -204,7 +194,16 @@ __find_get_block_slow(struct block_device *bdev, sector_t block)
+ if (IS_ERR(folio))
+ goto out;
+
+- spin_lock(&bd_mapping->i_private_lock);
++ /*
++ * Folio lock protects the buffers. Callers that cannot block
++ * will fallback to serializing vs try_to_free_buffers() via
++ * the i_private_lock.
++ */
++ if (atomic)
++ spin_lock(&bd_mapping->i_private_lock);
++ else
++ folio_lock(folio);
++
+ head = folio_buffers(folio);
+ if (!head)
+ goto out_unlock;
+@@ -236,7 +235,10 @@ __find_get_block_slow(struct block_device *bdev, sector_t block)
+ 1 << blkbits);
+ }
+ out_unlock:
+- spin_unlock(&bd_mapping->i_private_lock);
++ if (atomic)
++ spin_unlock(&bd_mapping->i_private_lock);
++ else
++ folio_unlock(folio);
+ folio_put(folio);
+ out:
+ return ret;
+@@ -1388,14 +1390,15 @@ lookup_bh_lru(struct block_device *bdev, sector_t block, unsigned size)
+ * it in the LRU and mark it as accessed. If it is not present then return
+ * NULL
+ */
+-struct buffer_head *
+-__find_get_block(struct block_device *bdev, sector_t block, unsigned size)
++static struct buffer_head *
++find_get_block_common(struct block_device *bdev, sector_t block,
++ unsigned size, bool atomic)
+ {
+ struct buffer_head *bh = lookup_bh_lru(bdev, block, size);
+
+ if (bh == NULL) {
+ /* __find_get_block_slow will mark the page accessed */
+- bh = __find_get_block_slow(bdev, block);
++ bh = __find_get_block_slow(bdev, block, atomic);
+ if (bh)
+ bh_lru_install(bh);
+ } else
+@@ -1403,6 +1406,12 @@ __find_get_block(struct block_device *bdev, sector_t block, unsigned size)
+
+ return bh;
+ }
++
++struct buffer_head *
++__find_get_block(struct block_device *bdev, sector_t block, unsigned size)
++{
++ return find_get_block_common(bdev, block, size, true);
++}
+ EXPORT_SYMBOL(__find_get_block);
+
+ /**
+--
+2.39.5
+
--- /dev/null
+From 37f9964fde8f8071d4c5cd7d0e7012eb5c3f75a7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 17 Apr 2025 18:59:17 -0700
+Subject: fs/buffer: use sleeping version of __find_get_block()
+
+From: Davidlohr Bueso <dave@stgolabs.net>
+
+[ Upstream commit 5b67d43976828dea2394eae2556b369bb7a61f64 ]
+
+Convert to the new nonatomic flavor to benefit from potential performance
+benefits and adapt in the future vs migration such that semantics
+are kept.
+
+Convert write_boundary_block() which already takes the buffer
+lock as well as bdev_getblk() depending on the respective gpf flags.
+There are no changes in semantics.
+
+Suggested-by: Jan Kara <jack@suse.cz>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
+Link: https://kdevops.org/ext4/v6.15-rc2.html # [0]
+Link: https://lore.kernel.org/all/aAAEvcrmREWa1SKF@bombadil.infradead.org/ # [1]
+Link: https://lore.kernel.org/20250418015921.132400-4-dave@stgolabs.net
+Tested-by: kdevops@lists.linux.dev # [0] [1]
+Reviewed-by: Luis Chamberlain <mcgrof@kernel.org>
+Signed-off-by: Christian Brauner <brauner@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/buffer.c | 11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+diff --git a/fs/buffer.c b/fs/buffer.c
+index 7981097c846d4..2494fe3a5e69e 100644
+--- a/fs/buffer.c
++++ b/fs/buffer.c
+@@ -658,7 +658,9 @@ EXPORT_SYMBOL(generic_buffers_fsync);
+ void write_boundary_block(struct block_device *bdev,
+ sector_t bblock, unsigned blocksize)
+ {
+- struct buffer_head *bh = __find_get_block(bdev, bblock + 1, blocksize);
++ struct buffer_head *bh;
++
++ bh = __find_get_block_nonatomic(bdev, bblock + 1, blocksize);
+ if (bh) {
+ if (buffer_dirty(bh))
+ write_dirty_buffer(bh, 0);
+@@ -1440,7 +1442,12 @@ EXPORT_SYMBOL(__find_get_block_nonatomic);
+ struct buffer_head *bdev_getblk(struct block_device *bdev, sector_t block,
+ unsigned size, gfp_t gfp)
+ {
+- struct buffer_head *bh = __find_get_block(bdev, block, size);
++ struct buffer_head *bh;
++
++ if (gfpflags_allow_blocking(gfp))
++ bh = __find_get_block_nonatomic(bdev, block, size);
++ else
++ bh = __find_get_block(bdev, block, size);
+
+ might_alloc(gfp);
+ if (bh)
+--
+2.39.5
+
--- /dev/null
+From 67d1eaa9309f8392416edb8cb6029df7d45a7112 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 17 Apr 2025 18:59:20 -0700
+Subject: fs/ext4: use sleeping version of sb_find_get_block()
+
+From: Davidlohr Bueso <dave@stgolabs.net>
+
+[ Upstream commit 6e8f57fd09c9fb569d10b2ccc3878155b702591a ]
+
+Enable ext4_free_blocks() to use it, which has a cond_resched to begin
+with. Convert to the new nonatomic flavor to benefit from potential
+performance benefits and adapt in the future vs migration such that
+semantics are kept.
+
+Suggested-by: Jan Kara <jack@suse.cz>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
+Link: https://kdevops.org/ext4/v6.15-rc2.html # [0]
+Link: https://lore.kernel.org/all/aAAEvcrmREWa1SKF@bombadil.infradead.org/ # [1]
+Link: https://lore.kernel.org/20250418015921.132400-7-dave@stgolabs.net
+Tested-by: kdevops@lists.linux.dev
+Reviewed-by: Luis Chamberlain <mcgrof@kernel.org>
+Signed-off-by: Christian Brauner <brauner@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/mballoc.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
+index b25a27c866969..d6f1e61c6dc82 100644
+--- a/fs/ext4/mballoc.c
++++ b/fs/ext4/mballoc.c
+@@ -6644,7 +6644,8 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
+ for (i = 0; i < count; i++) {
+ cond_resched();
+ if (is_metadata)
+- bh = sb_find_get_block(inode->i_sb, block + i);
++ bh = sb_find_get_block_nonatomic(inode->i_sb,
++ block + i);
+ ext4_forget(handle, is_metadata, inode, bh, block + i);
+ }
+ }
+--
+2.39.5
+
--- /dev/null
+From a4061c347536738f97a53ba0227fb0c2cb193e3c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 17 Apr 2025 18:59:19 -0700
+Subject: fs/jbd2: use sleeping version of __find_get_block()
+
+From: Davidlohr Bueso <dave@stgolabs.net>
+
+[ Upstream commit f76d4c28a46a9260d85e00dafc8f46d369365d33 ]
+
+Convert to the new nonatomic flavor to benefit from potential
+performance benefits and adapt in the future vs migration such
+that semantics are kept.
+
+- jbd2_journal_revoke(): can sleep (has might_sleep() in the beginning)
+
+- jbd2_journal_cancel_revoke(): only used from do_get_write_access() and
+ do_get_create_access() which do sleep. So can sleep.
+
+- jbd2_clear_buffer_revoked_flags() - only called from journal commit code
+ which sleeps. So can sleep.
+
+Suggested-by: Jan Kara <jack@suse.cz>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
+Link: https://kdevops.org/ext4/v6.15-rc2.html # [0]
+Link: https://lore.kernel.org/all/aAAEvcrmREWa1SKF@bombadil.infradead.org/ # [1]
+Link: https://lore.kernel.org/20250418015921.132400-6-dave@stgolabs.net
+Tested-by: kdevops@lists.linux.dev
+Reviewed-by: Luis Chamberlain <mcgrof@kernel.org>
+Signed-off-by: Christian Brauner <brauner@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/jbd2/revoke.c | 15 +++++++++------
+ 1 file changed, 9 insertions(+), 6 deletions(-)
+
+diff --git a/fs/jbd2/revoke.c b/fs/jbd2/revoke.c
+index ce63d5fde9c3a..f68fc8c255f00 100644
+--- a/fs/jbd2/revoke.c
++++ b/fs/jbd2/revoke.c
+@@ -345,7 +345,8 @@ int jbd2_journal_revoke(handle_t *handle, unsigned long long blocknr,
+ bh = bh_in;
+
+ if (!bh) {
+- bh = __find_get_block(bdev, blocknr, journal->j_blocksize);
++ bh = __find_get_block_nonatomic(bdev, blocknr,
++ journal->j_blocksize);
+ if (bh)
+ BUFFER_TRACE(bh, "found on hash");
+ }
+@@ -355,7 +356,8 @@ int jbd2_journal_revoke(handle_t *handle, unsigned long long blocknr,
+
+ /* If there is a different buffer_head lying around in
+ * memory anywhere... */
+- bh2 = __find_get_block(bdev, blocknr, journal->j_blocksize);
++ bh2 = __find_get_block_nonatomic(bdev, blocknr,
++ journal->j_blocksize);
+ if (bh2) {
+ /* ... and it has RevokeValid status... */
+ if (bh2 != bh && buffer_revokevalid(bh2))
+@@ -466,7 +468,8 @@ int jbd2_journal_cancel_revoke(handle_t *handle, struct journal_head *jh)
+ * state machine will get very upset later on. */
+ if (need_cancel) {
+ struct buffer_head *bh2;
+- bh2 = __find_get_block(bh->b_bdev, bh->b_blocknr, bh->b_size);
++ bh2 = __find_get_block_nonatomic(bh->b_bdev, bh->b_blocknr,
++ bh->b_size);
+ if (bh2) {
+ if (bh2 != bh)
+ clear_buffer_revoked(bh2);
+@@ -495,9 +498,9 @@ void jbd2_clear_buffer_revoked_flags(journal_t *journal)
+ struct jbd2_revoke_record_s *record;
+ struct buffer_head *bh;
+ record = (struct jbd2_revoke_record_s *)list_entry;
+- bh = __find_get_block(journal->j_fs_dev,
+- record->blocknr,
+- journal->j_blocksize);
++ bh = __find_get_block_nonatomic(journal->j_fs_dev,
++ record->blocknr,
++ journal->j_blocksize);
+ if (bh) {
+ clear_buffer_revoked(bh);
+ __brelse(bh);
+--
+2.39.5
+
--- /dev/null
+From 937e1cfc23766b242d46fb08e8b736ddd499d0a6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 21 Feb 2025 14:38:18 -0800
+Subject: fs/mpage: avoid negative shift for large blocksize
+
+From: Hannes Reinecke <hare@kernel.org>
+
+[ Upstream commit 86c60efd7c0ede43bd677f2eee1d84200528df1e ]
+
+For large blocksizes the number of block bits is larger than PAGE_SHIFT,
+so calculate the sector number from the byte offset instead. This is
+required to enable large folios with buffer-heads.
+
+Reviewed-by: "Matthew Wilcox (Oracle)" <willy@infradead.org>
+Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
+Signed-off-by: Hannes Reinecke <hare@kernel.org>
+Link: https://lore.kernel.org/r/20250221223823.1680616-4-mcgrof@kernel.org
+Reviewed-by: Hannes Reinecke <hare@suse.de>
+Signed-off-by: Christian Brauner <brauner@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/mpage.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/fs/mpage.c b/fs/mpage.c
+index 82aecf3727437..a3c82206977f6 100644
+--- a/fs/mpage.c
++++ b/fs/mpage.c
+@@ -181,7 +181,7 @@ static struct bio *do_mpage_readpage(struct mpage_readpage_args *args)
+ if (folio_buffers(folio))
+ goto confused;
+
+- block_in_file = (sector_t)folio->index << (PAGE_SHIFT - blkbits);
++ block_in_file = folio_pos(folio) >> blkbits;
+ last_block = block_in_file + args->nr_pages * blocks_per_page;
+ last_block_in_file = (i_size_read(inode) + blocksize - 1) >> blkbits;
+ if (last_block > last_block_in_file)
+@@ -527,7 +527,7 @@ static int __mpage_writepage(struct folio *folio, struct writeback_control *wbc,
+ * The page has no buffers: map it to disk
+ */
+ BUG_ON(!folio_test_uptodate(folio));
+- block_in_file = (sector_t)folio->index << (PAGE_SHIFT - blkbits);
++ block_in_file = folio_pos(folio) >> blkbits;
+ /*
+ * Whole page beyond EOF? Skip allocating blocks to avoid leaking
+ * space.
+--
+2.39.5
+
--- /dev/null
+From a3852ebdb8e968832e9aeb479865bb5869600cff Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 17 Apr 2025 18:59:18 -0700
+Subject: fs/ocfs2: use sleeping version of __find_get_block()
+
+From: Davidlohr Bueso <dave@stgolabs.net>
+
+[ Upstream commit a0b5ff07491010789fcb012bc8f9dad9d26f9a8b ]
+
+This is a path that allows for blocking as it does IO. Convert
+to the new nonatomic flavor to benefit from potential performance
+benefits and adapt in the future vs migration such that semantics
+are kept.
+
+Suggested-by: Jan Kara <jack@suse.cz>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
+Link: https://kdevops.org/ext4/v6.15-rc2.html # [0]
+Link: https://lore.kernel.org/all/aAAEvcrmREWa1SKF@bombadil.infradead.org/ # [1]
+Link: https://lore.kernel.org/20250418015921.132400-5-dave@stgolabs.net
+Tested-by: kdevops@lists.linux.dev
+Reviewed-by: Luis Chamberlain <mcgrof@kernel.org>
+Signed-off-by: Christian Brauner <brauner@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ocfs2/journal.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c
+index f37831d5f95a1..e5f58ff2175f4 100644
+--- a/fs/ocfs2/journal.c
++++ b/fs/ocfs2/journal.c
+@@ -1271,7 +1271,7 @@ static int ocfs2_force_read_journal(struct inode *inode)
+ }
+
+ for (i = 0; i < p_blocks; i++, p_blkno++) {
+- bh = __find_get_block(osb->sb->s_bdev, p_blkno,
++ bh = __find_get_block_nonatomic(osb->sb->s_bdev, p_blkno,
+ osb->sb->s_blocksize);
+ /* block not cached. */
+ if (!bh)
+--
+2.39.5
+
--- /dev/null
+From 291eda3996e7006d851c35c2ec71d5ef2fba5239 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 7 Mar 2025 05:29:16 +0000
+Subject: fs/pipe: Limit the slots in pipe_resize_ring()
+
+From: K Prateek Nayak <kprateek.nayak@amd.com>
+
+[ Upstream commit cf3d0c54b21c4a351d4f94cf188e9715dbd1ef5b ]
+
+Limit the number of slots in pipe_resize_ring() to the maximum value
+representable by pipe->{head,tail}. Values beyond the max limit can
+lead to incorrect pipe occupancy related calculations where the pipe
+will never appear full.
+
+Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: K Prateek Nayak <kprateek.nayak@amd.com>
+Link: https://lore.kernel.org/r/20250307052919.34542-2-kprateek.nayak@amd.com
+Reviewed-by: Oleg Nesterov <oleg@redhat.com>
+Signed-off-by: Christian Brauner <brauner@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/pipe.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/fs/pipe.c b/fs/pipe.c
+index 4d0799e4e7196..88e81f84e3eaf 100644
+--- a/fs/pipe.c
++++ b/fs/pipe.c
+@@ -1271,6 +1271,10 @@ int pipe_resize_ring(struct pipe_inode_info *pipe, unsigned int nr_slots)
+ struct pipe_buffer *bufs;
+ unsigned int head, tail, mask, n;
+
++ /* nr_slots larger than limits of pipe->{head,tail} */
++ if (unlikely(nr_slots > (pipe_index_t)-1u))
++ return -EINVAL;
++
+ bufs = kcalloc(nr_slots, sizeof(*bufs),
+ GFP_KERNEL_ACCOUNT | __GFP_NOWARN);
+ if (unlikely(!bufs))
+--
+2.39.5
+
--- /dev/null
+From 6c17944fdf2d4e756ff2d38c94df7400ed7f5b65 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 14 Feb 2025 09:17:53 +0800
+Subject: fuse: Return EPERM rather than ENOSYS from link()
+
+From: Matt Johnston <matt@codeconstruct.com.au>
+
+[ Upstream commit 8344213571b2ac8caf013cfd3b37bc3467c3a893 ]
+
+link() is documented to return EPERM when a filesystem doesn't support
+the operation, return that instead.
+
+Link: https://github.com/libfuse/libfuse/issues/925
+Signed-off-by: Matt Johnston <matt@codeconstruct.com.au>
+Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/fuse/dir.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
+index 3b031d24d3691..8f699c67561fa 100644
+--- a/fs/fuse/dir.c
++++ b/fs/fuse/dir.c
+@@ -1137,6 +1137,8 @@ static int fuse_link(struct dentry *entry, struct inode *newdir,
+ else if (err == -EINTR)
+ fuse_invalidate_attr(inode);
+
++ if (err == -ENOSYS)
++ err = -EPERM;
+ return err;
+ }
+
+--
+2.39.5
+
--- /dev/null
+From d26e9c8a5bcc241f84ce588eed332fa6059425f3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 19 Feb 2025 17:31:36 -0800
+Subject: genirq/msi: Store the IOMMU IOVA directly in msi_desc instead of
+ iommu_cookie
+
+From: Jason Gunthorpe <jgg@nvidia.com>
+
+[ Upstream commit 1f7df3a691740a7736bbc99dc4ed536120eb4746 ]
+
+The IOMMU translation for MSI message addresses has been a 2-step process,
+separated in time:
+
+ 1) iommu_dma_prepare_msi(): A cookie pointer containing the IOVA address
+ is stored in the MSI descriptor when an MSI interrupt is allocated.
+
+ 2) iommu_dma_compose_msi_msg(): this cookie pointer is used to compute a
+ translated message address.
+
+This has an inherent lifetime problem for the pointer stored in the cookie
+that must remain valid between the two steps. However, there is no locking
+at the irq layer that helps protect the lifetime. Today, this works under
+the assumption that the iommu domain is not changed while MSI interrupts
+being programmed. This is true for normal DMA API users within the kernel,
+as the iommu domain is attached before the driver is probed and cannot be
+changed while a driver is attached.
+
+Classic VFIO type1 also prevented changing the iommu domain while VFIO was
+running as it does not support changing the "container" after starting up.
+
+However, iommufd has improved this so that the iommu domain can be changed
+during VFIO operation. This potentially allows userspace to directly race
+VFIO_DEVICE_ATTACH_IOMMUFD_PT (which calls iommu_attach_group()) and
+VFIO_DEVICE_SET_IRQS (which calls into iommu_dma_compose_msi_msg()).
+
+This potentially causes both the cookie pointer and the unlocked call to
+iommu_get_domain_for_dev() on the MSI translation path to become UAFs.
+
+Fix the MSI cookie UAF by removing the cookie pointer. The translated IOVA
+address is already known during iommu_dma_prepare_msi() and cannot change.
+Thus, it can simply be stored as an integer in the MSI descriptor.
+
+The other UAF related to iommu_get_domain_for_dev() will be addressed in
+patch "iommu: Make iommu_dma_prepare_msi() into a generic operation" by
+using the IOMMU group mutex.
+
+Link: https://patch.msgid.link/r/a4f2cd76b9dc1833ee6c1cf325cba57def22231c.1740014950.git.nicolinc@nvidia.com
+Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
+Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iommu/dma-iommu.c | 28 +++++++++++++---------------
+ include/linux/msi.h | 33 ++++++++++++---------------------
+ 2 files changed, 25 insertions(+), 36 deletions(-)
+
+diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
+index 2a9fa0c8cc00f..0f0caf59023c7 100644
+--- a/drivers/iommu/dma-iommu.c
++++ b/drivers/iommu/dma-iommu.c
+@@ -1815,7 +1815,7 @@ int iommu_dma_prepare_msi(struct msi_desc *desc, phys_addr_t msi_addr)
+ static DEFINE_MUTEX(msi_prepare_lock); /* see below */
+
+ if (!domain || !domain->iova_cookie) {
+- desc->iommu_cookie = NULL;
++ msi_desc_set_iommu_msi_iova(desc, 0, 0);
+ return 0;
+ }
+
+@@ -1827,11 +1827,12 @@ int iommu_dma_prepare_msi(struct msi_desc *desc, phys_addr_t msi_addr)
+ mutex_lock(&msi_prepare_lock);
+ msi_page = iommu_dma_get_msi_page(dev, msi_addr, domain);
+ mutex_unlock(&msi_prepare_lock);
+-
+- msi_desc_set_iommu_cookie(desc, msi_page);
+-
+ if (!msi_page)
+ return -ENOMEM;
++
++ msi_desc_set_iommu_msi_iova(
++ desc, msi_page->iova,
++ ilog2(cookie_msi_granule(domain->iova_cookie)));
+ return 0;
+ }
+
+@@ -1842,18 +1843,15 @@ int iommu_dma_prepare_msi(struct msi_desc *desc, phys_addr_t msi_addr)
+ */
+ void iommu_dma_compose_msi_msg(struct msi_desc *desc, struct msi_msg *msg)
+ {
+- struct device *dev = msi_desc_to_dev(desc);
+- const struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
+- const struct iommu_dma_msi_page *msi_page;
++#ifdef CONFIG_IRQ_MSI_IOMMU
++ if (desc->iommu_msi_shift) {
++ u64 msi_iova = desc->iommu_msi_iova << desc->iommu_msi_shift;
+
+- msi_page = msi_desc_get_iommu_cookie(desc);
+-
+- if (!domain || !domain->iova_cookie || WARN_ON(!msi_page))
+- return;
+-
+- msg->address_hi = upper_32_bits(msi_page->iova);
+- msg->address_lo &= cookie_msi_granule(domain->iova_cookie) - 1;
+- msg->address_lo += lower_32_bits(msi_page->iova);
++ msg->address_hi = upper_32_bits(msi_iova);
++ msg->address_lo = lower_32_bits(msi_iova) |
++ (msg->address_lo & ((1 << desc->iommu_msi_shift) - 1));
++ }
++#endif
+ }
+
+ static int iommu_dma_init(void)
+diff --git a/include/linux/msi.h b/include/linux/msi.h
+index 59a421fc42bf0..63d0e51f7a801 100644
+--- a/include/linux/msi.h
++++ b/include/linux/msi.h
+@@ -165,6 +165,10 @@ struct msi_desc_data {
+ * @dev: Pointer to the device which uses this descriptor
+ * @msg: The last set MSI message cached for reuse
+ * @affinity: Optional pointer to a cpu affinity mask for this descriptor
++ * @iommu_msi_iova: Optional shifted IOVA from the IOMMU to override the msi_addr.
++ * Only used if iommu_msi_shift != 0
++ * @iommu_msi_shift: Indicates how many bits of the original address should be
++ * preserved when using iommu_msi_iova.
+ * @sysfs_attr: Pointer to sysfs device attribute
+ *
+ * @write_msi_msg: Callback that may be called when the MSI message
+@@ -183,7 +187,8 @@ struct msi_desc {
+ struct msi_msg msg;
+ struct irq_affinity_desc *affinity;
+ #ifdef CONFIG_IRQ_MSI_IOMMU
+- const void *iommu_cookie;
++ u64 iommu_msi_iova : 58;
++ u64 iommu_msi_shift : 6;
+ #endif
+ #ifdef CONFIG_SYSFS
+ struct device_attribute *sysfs_attrs;
+@@ -284,28 +289,14 @@ struct msi_desc *msi_next_desc(struct device *dev, unsigned int domid,
+
+ #define msi_desc_to_dev(desc) ((desc)->dev)
+
+-#ifdef CONFIG_IRQ_MSI_IOMMU
+-static inline const void *msi_desc_get_iommu_cookie(struct msi_desc *desc)
+-{
+- return desc->iommu_cookie;
+-}
+-
+-static inline void msi_desc_set_iommu_cookie(struct msi_desc *desc,
+- const void *iommu_cookie)
+-{
+- desc->iommu_cookie = iommu_cookie;
+-}
+-#else
+-static inline const void *msi_desc_get_iommu_cookie(struct msi_desc *desc)
++static inline void msi_desc_set_iommu_msi_iova(struct msi_desc *desc, u64 msi_iova,
++ unsigned int msi_shift)
+ {
+- return NULL;
+-}
+-
+-static inline void msi_desc_set_iommu_cookie(struct msi_desc *desc,
+- const void *iommu_cookie)
+-{
+-}
++#ifdef CONFIG_IRQ_MSI_IOMMU
++ desc->iommu_msi_iova = msi_iova >> msi_shift;
++ desc->iommu_msi_shift = msi_shift;
+ #endif
++}
+
+ int msi_domain_insert_msi_desc(struct device *dev, unsigned int domid,
+ struct msi_desc *init_desc);
+--
+2.39.5
+
--- /dev/null
+From c491e26fc1178764776e620ddf7355104eedda75 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Feb 2025 14:58:39 +0100
+Subject: gfs2: Check for empty queue in run_queue
+
+From: Andreas Gruenbacher <agruenba@redhat.com>
+
+[ Upstream commit d838605fea6eabae3746a276fd448f6719eb3926 ]
+
+In run_queue(), check if the queue of pending requests is empty instead
+of blindly assuming that it won't be.
+
+Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/gfs2/glock.c | 11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
+index 65c07aa957184..7f9cc7872214e 100644
+--- a/fs/gfs2/glock.c
++++ b/fs/gfs2/glock.c
+@@ -843,12 +843,13 @@ static void run_queue(struct gfs2_glock *gl, const int nonblock)
+ __releases(&gl->gl_lockref.lock)
+ __acquires(&gl->gl_lockref.lock)
+ {
+- struct gfs2_holder *gh = NULL;
++ struct gfs2_holder *gh;
+
+ if (test_bit(GLF_LOCK, &gl->gl_flags))
+ return;
+ set_bit(GLF_LOCK, &gl->gl_flags);
+
++ /* While a demote is in progress, the GLF_LOCK flag must be set. */
+ GLOCK_BUG_ON(gl, test_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags));
+
+ if (test_bit(GLF_DEMOTE, &gl->gl_flags) &&
+@@ -860,18 +861,22 @@ __acquires(&gl->gl_lockref.lock)
+ set_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags);
+ GLOCK_BUG_ON(gl, gl->gl_demote_state == LM_ST_EXCLUSIVE);
+ gl->gl_target = gl->gl_demote_state;
++ do_xmote(gl, NULL, gl->gl_target);
++ return;
+ } else {
+ if (test_bit(GLF_DEMOTE, &gl->gl_flags))
+ gfs2_demote_wake(gl);
+ if (do_promote(gl))
+ goto out_unlock;
+ gh = find_first_waiter(gl);
++ if (!gh)
++ goto out_unlock;
+ gl->gl_target = gh->gh_state;
+ if (!(gh->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB)))
+ do_error(gl, 0); /* Fail queued try locks */
++ do_xmote(gl, gh, gl->gl_target);
++ return;
+ }
+- do_xmote(gl, gh, gl->gl_target);
+- return;
+
+ out_sched:
+ clear_bit(GLF_LOCK, &gl->gl_flags);
+--
+2.39.5
+
--- /dev/null
+From af03790585ce16bcf4f8c4e7526ee8fd935042e2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 10 Feb 2025 11:51:57 +0100
+Subject: gpiolib: sanitize the return value of gpio_chip::set_config()
+
+From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+
+[ Upstream commit dcf8f3bffa2de2c7f3b5771b63605194ccd2286f ]
+
+The return value of the set_config() callback may be propagated to
+user-space. If a bad driver returns a positive number, it may confuse
+user programs. Tighten the API contract and check for positive numbers
+returned by GPIO controllers.
+
+Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
+Link: https://lore.kernel.org/r/20250210-gpio-sanitize-retvals-v1-3-12ea88506cb2@linaro.org
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpio/gpiolib.c | 3 +++
+ include/linux/gpio/driver.h | 3 ++-
+ 2 files changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
+index 0c00ed2ab4315..960ca0ad45fc8 100644
+--- a/drivers/gpio/gpiolib.c
++++ b/drivers/gpio/gpiolib.c
+@@ -2577,6 +2577,9 @@ int gpio_do_set_config(struct gpio_desc *desc, unsigned long config)
+ return -ENOTSUPP;
+
+ ret = guard.gc->set_config(guard.gc, gpio_chip_hwgpio(desc), config);
++ if (ret > 0)
++ ret = -EBADE;
++
+ #ifdef CONFIG_GPIO_CDEV
+ /*
+ * Special case - if we're setting debounce period, we need to store
+diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
+index 2dd7cb9cc270a..5ce6b2167f808 100644
+--- a/include/linux/gpio/driver.h
++++ b/include/linux/gpio/driver.h
+@@ -347,7 +347,8 @@ struct gpio_irq_chip {
+ * @set: assigns output value for signal "offset"
+ * @set_multiple: assigns output values for multiple signals defined by "mask"
+ * @set_config: optional hook for all kinds of settings. Uses the same
+- * packed config format as generic pinconf.
++ * packed config format as generic pinconf. Must return 0 on success and
++ * a negative error number on failure.
+ * @to_irq: optional hook supporting non-static gpiod_to_irq() mappings;
+ * implementation may not sleep
+ * @dbg_show: optional routine to show contents in debugfs; default code
+--
+2.39.5
+
--- /dev/null
+From 501a0f03d5711376812ce0312fd50e73c82d8b23 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Feb 2025 13:02:40 +0800
+Subject: HID: Kconfig: Add LEDS_CLASS_MULTICOLOR dependency to HID_LOGITECH
+
+From: Kate Hsuan <hpa@redhat.com>
+
+[ Upstream commit 4465f4fa21e0e54c10896db3ed49dbd5a9aad3fd ]
+
+The test bot found an issue with building hid-lg-g15.
+
+All errors (new ones prefixed by >>):
+
+ powerpc-linux-ld: drivers/hid/hid-lg-g15.o: in function `lg_g510_kbd_led_write':
+>> drivers/hid/hid-lg-g15.c:241:(.text+0x768): undefined reference to `led_mc_calc_color_components'
+ powerpc-linux-ld: drivers/hid/hid-lg-g15.o: in function `lg_g15_register_led':
+>> drivers/hid/hid-lg-g15.c:686:(.text+0xa9c): undefined reference to `devm_led_classdev_multicolor_register_ext'
+
+Since multicolor LED APIs manage the keyboard backlight settings of
+hid-lg-g15, the LEDS_CLASS_MULTICOLOR dependency was added to
+HID_LOGITECH.
+
+Reported-by: kernel test robot <lkp@intel.com>
+Closes: https://lore.kernel.org/oe-kbuild-all/202502110032.VZ0J024X-lkp@intel.com/
+Fixes: a3a064146c50 ("HID: hid-lg-g15: Use standard multicolor LED API")
+Signed-off-by: Kate Hsuan <hpa@redhat.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hid/Kconfig | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
+index 4cfea399ebab2..76be97c5fc2ff 100644
+--- a/drivers/hid/Kconfig
++++ b/drivers/hid/Kconfig
+@@ -603,6 +603,7 @@ config HID_LOGITECH
+ tristate "Logitech devices"
+ depends on USB_HID
+ depends on LEDS_CLASS
++ depends on LEDS_CLASS_MULTICOLOR
+ default !EXPERT
+ help
+ Support for Logitech devices that are not fully compliant with HID standard.
+--
+2.39.5
+
--- /dev/null
+From 72164a0dc90f927fdaf693703fea47a3758b2f76 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 28 Nov 2024 10:35:18 +0800
+Subject: HID: usbkbd: Fix the bit shift number for LED_KANA
+
+From: junan <junan76@163.com>
+
+[ Upstream commit d73a4bfa2881a6859b384b75a414c33d4898b055 ]
+
+Since "LED_KANA" was defined as "0x04", the shift number should be "4".
+
+Signed-off-by: junan <junan76@163.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hid/usbhid/usbkbd.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/hid/usbhid/usbkbd.c b/drivers/hid/usbhid/usbkbd.c
+index c439ed2f16dbc..af6bc76dbf649 100644
+--- a/drivers/hid/usbhid/usbkbd.c
++++ b/drivers/hid/usbhid/usbkbd.c
+@@ -160,7 +160,7 @@ static int usb_kbd_event(struct input_dev *dev, unsigned int type,
+ return -1;
+
+ spin_lock_irqsave(&kbd->leds_lock, flags);
+- kbd->newleds = (!!test_bit(LED_KANA, dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) |
++ kbd->newleds = (!!test_bit(LED_KANA, dev->led) << 4) | (!!test_bit(LED_COMPOSE, dev->led) << 3) |
+ (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) |
+ (!!test_bit(LED_NUML, dev->led));
+
+--
+2.39.5
+
--- /dev/null
+From 0fd65f3a3f2676a3714497a7ffad1dd6dcbd3c2a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 14 Feb 2025 15:43:33 +0200
+Subject: hrtimers: Replace hrtimer_clock_to_base_table with switch-case
+
+From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+
+[ Upstream commit 4441b976dfeff0d3579e8da3c0283300c618a553 ]
+
+Clang and GCC complain about overlapped initialisers in the
+hrtimer_clock_to_base_table definition. With `make W=1` and CONFIG_WERROR=y
+(which is default nowadays) this breaks the build:
+
+ CC kernel/time/hrtimer.o
+kernel/time/hrtimer.c:124:21: error: initializer overrides prior initialization of this subobject [-Werror,-Winitializer-overrides]
+ 124 | [CLOCK_REALTIME] = HRTIMER_BASE_REALTIME,
+
+kernel/time/hrtimer.c:122:27: note: previous initialization is here
+ 122 | [0 ... MAX_CLOCKS - 1] = HRTIMER_MAX_CLOCK_BASES,
+
+(and similar for CLOCK_MONOTONIC, CLOCK_BOOTTIME, and CLOCK_TAI).
+
+hrtimer_clockid_to_base(), which uses the table, is only used in
+__hrtimer_init(), which is not a hotpath.
+
+Therefore replace the table lookup with a switch case in
+hrtimer_clockid_to_base() to avoid this warning.
+
+Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Link: https://lore.kernel.org/all/20250214134424.3367619-1-andriy.shevchenko@linux.intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/time/hrtimer.c | 29 ++++++++++++-----------------
+ 1 file changed, 12 insertions(+), 17 deletions(-)
+
+diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
+index deb1aa32814e3..453dc76c93484 100644
+--- a/kernel/time/hrtimer.c
++++ b/kernel/time/hrtimer.c
+@@ -117,16 +117,6 @@ DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) =
+ .csd = CSD_INIT(retrigger_next_event, NULL)
+ };
+
+-static const int hrtimer_clock_to_base_table[MAX_CLOCKS] = {
+- /* Make sure we catch unsupported clockids */
+- [0 ... MAX_CLOCKS - 1] = HRTIMER_MAX_CLOCK_BASES,
+-
+- [CLOCK_REALTIME] = HRTIMER_BASE_REALTIME,
+- [CLOCK_MONOTONIC] = HRTIMER_BASE_MONOTONIC,
+- [CLOCK_BOOTTIME] = HRTIMER_BASE_BOOTTIME,
+- [CLOCK_TAI] = HRTIMER_BASE_TAI,
+-};
+-
+ static inline bool hrtimer_base_is_online(struct hrtimer_cpu_base *base)
+ {
+ if (!IS_ENABLED(CONFIG_HOTPLUG_CPU))
+@@ -1587,14 +1577,19 @@ u64 hrtimer_next_event_without(const struct hrtimer *exclude)
+
+ static inline int hrtimer_clockid_to_base(clockid_t clock_id)
+ {
+- if (likely(clock_id < MAX_CLOCKS)) {
+- int base = hrtimer_clock_to_base_table[clock_id];
+-
+- if (likely(base != HRTIMER_MAX_CLOCK_BASES))
+- return base;
++ switch (clock_id) {
++ case CLOCK_REALTIME:
++ return HRTIMER_BASE_REALTIME;
++ case CLOCK_MONOTONIC:
++ return HRTIMER_BASE_MONOTONIC;
++ case CLOCK_BOOTTIME:
++ return HRTIMER_BASE_BOOTTIME;
++ case CLOCK_TAI:
++ return HRTIMER_BASE_TAI;
++ default:
++ WARN(1, "Invalid clockid %d. Using MONOTONIC\n", clock_id);
++ return HRTIMER_BASE_MONOTONIC;
+ }
+- WARN(1, "Invalid clockid %d. Using MONOTONIC\n", clock_id);
+- return HRTIMER_BASE_MONOTONIC;
+ }
+
+ static enum hrtimer_restart hrtimer_dummy_timeout(struct hrtimer *unused)
+--
+2.39.5
+
--- /dev/null
+From 850a3519bd043a4d8ace6e69901955941212e680 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 20 Feb 2025 11:08:32 +0800
+Subject: hwmon: (acpi_power_meter) Fix the fake power alarm reporting
+
+From: Huisong Li <lihuisong@huawei.com>
+
+[ Upstream commit 0ea627381eb527a0ebd262c690c3992085b87ff4 ]
+
+We encountered a problem that a fake power alarm is reported to
+user on the platform unsupported notifications at the second step
+below:
+1> Query 'power1_alarm' attribute when the power capping occurs.
+2> Query 'power1_alarm' attribute when the power capping is over
+ and the current average power is less then power cap value.
+
+The root cause is that the resource->power_alarm is set to true
+at the first step. And power meter use this old value to show
+the power alarm state instead of the current the comparison value.
+
+Signed-off-by: Huisong Li <lihuisong@huawei.com>
+Link: https://lore.kernel.org/r/20250220030832.2976-1-lihuisong@huawei.com
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/acpi_power_meter.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c
+index 44afb07409a46..f05986e4f3792 100644
+--- a/drivers/hwmon/acpi_power_meter.c
++++ b/drivers/hwmon/acpi_power_meter.c
+@@ -437,9 +437,13 @@ static ssize_t show_val(struct device *dev,
+ ret = update_cap(resource);
+ if (ret)
+ return ret;
++ resource->power_alarm = resource->power > resource->cap;
++ val = resource->power_alarm;
++ } else {
++ val = resource->power_alarm ||
++ resource->power > resource->cap;
++ resource->power_alarm = resource->power > resource->cap;
+ }
+- val = resource->power_alarm || resource->power > resource->cap;
+- resource->power_alarm = resource->power > resource->cap;
+ break;
+ case 7:
+ case 8:
+--
+2.39.5
+
--- /dev/null
+From 808bf9be5bf2abd483c7fda1aacfd43866cc3891 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Mar 2025 00:52:50 -0500
+Subject: hwmon: (dell-smm) Increment the number of fans
+
+From: Kurt Borja <kuurtb@gmail.com>
+
+[ Upstream commit dbcfcb239b3b452ef8782842c36fb17dd1b9092f ]
+
+Some Alienware laptops that support the SMM interface, may have up to 4
+fans.
+
+Tested on an Alienware x15 r1.
+
+Signed-off-by: Kurt Borja <kuurtb@gmail.com>
+Link: https://lore.kernel.org/r/20250304055249.51940-2-kuurtb@gmail.com
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ Documentation/hwmon/dell-smm-hwmon.rst | 14 +++++++-------
+ drivers/hwmon/dell-smm-hwmon.c | 5 ++++-
+ 2 files changed, 11 insertions(+), 8 deletions(-)
+
+diff --git a/Documentation/hwmon/dell-smm-hwmon.rst b/Documentation/hwmon/dell-smm-hwmon.rst
+index 74905675d71f9..5a4edb6565cf9 100644
+--- a/Documentation/hwmon/dell-smm-hwmon.rst
++++ b/Documentation/hwmon/dell-smm-hwmon.rst
+@@ -32,12 +32,12 @@ Temperature sensors and fans can be queried and set via the standard
+ =============================== ======= =======================================
+ Name Perm Description
+ =============================== ======= =======================================
+-fan[1-3]_input RO Fan speed in RPM.
+-fan[1-3]_label RO Fan label.
+-fan[1-3]_min RO Minimal Fan speed in RPM
+-fan[1-3]_max RO Maximal Fan speed in RPM
+-fan[1-3]_target RO Expected Fan speed in RPM
+-pwm[1-3] RW Control the fan PWM duty-cycle.
++fan[1-4]_input RO Fan speed in RPM.
++fan[1-4]_label RO Fan label.
++fan[1-4]_min RO Minimal Fan speed in RPM
++fan[1-4]_max RO Maximal Fan speed in RPM
++fan[1-4]_target RO Expected Fan speed in RPM
++pwm[1-4] RW Control the fan PWM duty-cycle.
+ pwm1_enable WO Enable or disable automatic BIOS fan
+ control (not supported on all laptops,
+ see below for details).
+@@ -93,7 +93,7 @@ Again, when you find new codes, we'd be happy to have your patches!
+ ---------------------------
+
+ The driver also exports the fans as thermal cooling devices with
+-``type`` set to ``dell-smm-fan[1-3]``. This allows for easy fan control
++``type`` set to ``dell-smm-fan[1-4]``. This allows for easy fan control
+ using one of the thermal governors.
+
+ Module parameters
+diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c
+index cd00adaad1b41..79e5606e6d2f8 100644
+--- a/drivers/hwmon/dell-smm-hwmon.c
++++ b/drivers/hwmon/dell-smm-hwmon.c
+@@ -73,7 +73,7 @@
+ #define DELL_SMM_LEGACY_EXECUTE 0x1
+
+ #define DELL_SMM_NO_TEMP 10
+-#define DELL_SMM_NO_FANS 3
++#define DELL_SMM_NO_FANS 4
+
+ struct smm_regs {
+ unsigned int eax;
+@@ -1074,11 +1074,14 @@ static const struct hwmon_channel_info * const dell_smm_info[] = {
+ HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MIN | HWMON_F_MAX |
+ HWMON_F_TARGET,
+ HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MIN | HWMON_F_MAX |
++ HWMON_F_TARGET,
++ HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MIN | HWMON_F_MAX |
+ HWMON_F_TARGET
+ ),
+ HWMON_CHANNEL_INFO(pwm,
+ HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
+ HWMON_PWM_INPUT,
++ HWMON_PWM_INPUT,
+ HWMON_PWM_INPUT
+ ),
+ NULL
+--
+2.39.5
+
--- /dev/null
+From 9a9a19893cb7a9921d8292a2f8ece75d809b9ce7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 10 Feb 2025 15:59:30 +0100
+Subject: hwmon: (gpio-fan) Add missing mutex locks
+
+From: Alexander Stein <alexander.stein@ew.tq-group.com>
+
+[ Upstream commit 9fee7d19bab635f89223cc40dfd2c8797fdc4988 ]
+
+set_fan_speed() is expected to be called with fan_data->lock being locked.
+Add locking for proper synchronization.
+
+Signed-off-by: Alexander Stein <alexander.stein@ew.tq-group.com>
+Link: https://lore.kernel.org/r/20250210145934.761280-3-alexander.stein@ew.tq-group.com
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/gpio-fan.c | 16 +++++++++++++++-
+ 1 file changed, 15 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c
+index d92c536be9af7..b779240328d59 100644
+--- a/drivers/hwmon/gpio-fan.c
++++ b/drivers/hwmon/gpio-fan.c
+@@ -393,7 +393,12 @@ static int gpio_fan_set_cur_state(struct thermal_cooling_device *cdev,
+ if (state >= fan_data->num_speed)
+ return -EINVAL;
+
++ mutex_lock(&fan_data->lock);
++
+ set_fan_speed(fan_data, state);
++
++ mutex_unlock(&fan_data->lock);
++
+ return 0;
+ }
+
+@@ -489,7 +494,11 @@ MODULE_DEVICE_TABLE(of, of_gpio_fan_match);
+
+ static void gpio_fan_stop(void *data)
+ {
++ struct gpio_fan_data *fan_data = data;
++
++ mutex_lock(&fan_data->lock);
+ set_fan_speed(data, 0);
++ mutex_unlock(&fan_data->lock);
+ }
+
+ static int gpio_fan_probe(struct platform_device *pdev)
+@@ -562,7 +571,9 @@ static int gpio_fan_suspend(struct device *dev)
+
+ if (fan_data->gpios) {
+ fan_data->resume_speed = fan_data->speed_index;
++ mutex_lock(&fan_data->lock);
+ set_fan_speed(fan_data, 0);
++ mutex_unlock(&fan_data->lock);
+ }
+
+ return 0;
+@@ -572,8 +583,11 @@ static int gpio_fan_resume(struct device *dev)
+ {
+ struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+
+- if (fan_data->gpios)
++ if (fan_data->gpios) {
++ mutex_lock(&fan_data->lock);
+ set_fan_speed(fan_data, fan_data->resume_speed);
++ mutex_unlock(&fan_data->lock);
++ }
+
+ return 0;
+ }
+--
+2.39.5
+
--- /dev/null
+From 9ba25745c1d8571e570d5395c96e0e998afc88e6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Feb 2025 09:54:08 +0000
+Subject: hwmon: (xgene-hwmon) use appropriate type for the latency value
+
+From: Andrey Vatoropin <a.vatoropin@crpt.ru>
+
+[ Upstream commit 8df0f002827e18632dcd986f7546c1abf1953a6f ]
+
+The expression PCC_NUM_RETRIES * pcc_chan->latency is currently being
+evaluated using 32-bit arithmetic.
+
+Since a value of type 'u64' is used to store the eventual result,
+and this result is later sent to the function usecs_to_jiffies with
+input parameter unsigned int, the current data type is too wide to
+store the value of ctx->usecs_lat.
+
+Change the data type of "usecs_lat" to a more suitable (narrower) type.
+
+Found by Linux Verification Center (linuxtesting.org) with SVACE.
+
+Signed-off-by: Andrey Vatoropin <a.vatoropin@crpt.ru>
+Link: https://lore.kernel.org/r/20250204095400.95013-1-a.vatoropin@crpt.ru
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/xgene-hwmon.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/hwmon/xgene-hwmon.c b/drivers/hwmon/xgene-hwmon.c
+index 7087197383c96..2cdbd5f107a2c 100644
+--- a/drivers/hwmon/xgene-hwmon.c
++++ b/drivers/hwmon/xgene-hwmon.c
+@@ -105,7 +105,7 @@ struct xgene_hwmon_dev {
+
+ phys_addr_t comm_base_addr;
+ void *pcc_comm_addr;
+- u64 usecs_lat;
++ unsigned int usecs_lat;
+ };
+
+ /*
+--
+2.39.5
+
--- /dev/null
+From 62eddd9f0a2c82e0ecb718438c6b89029767955c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 17 Mar 2025 22:06:04 -0400
+Subject: hypfs_create_cpu_files(): add missing check for hypfs_mkdir() failure
+
+From: Al Viro <viro@zeniv.linux.org.uk>
+
+[ Upstream commit 00cdfdcfa0806202aea56b02cedbf87ef1e75df8 ]
+
+Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/s390/hypfs/hypfs_diag_fs.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/arch/s390/hypfs/hypfs_diag_fs.c b/arch/s390/hypfs/hypfs_diag_fs.c
+index 00a6d370a2803..280266a74f378 100644
+--- a/arch/s390/hypfs/hypfs_diag_fs.c
++++ b/arch/s390/hypfs/hypfs_diag_fs.c
+@@ -208,6 +208,8 @@ static int hypfs_create_cpu_files(struct dentry *cpus_dir, void *cpu_info)
+ snprintf(buffer, TMP_SIZE, "%d", cpu_info__cpu_addr(diag204_get_info_type(),
+ cpu_info));
+ cpu_dir = hypfs_mkdir(cpus_dir, buffer);
++ if (IS_ERR(cpu_dir))
++ return PTR_ERR(cpu_dir);
+ rc = hypfs_create_u64(cpu_dir, "mgmtime",
+ cpu_info__acc_time(diag204_get_info_type(), cpu_info) -
+ cpu_info__lp_time(diag204_get_info_type(), cpu_info));
+--
+2.39.5
+
--- /dev/null
+From 0fb89140e764eb7fdde3584e5274958693b370f3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 17 Feb 2025 14:32:57 +0530
+Subject: i2c: amd-asf: Set cmd variable when encountering an error
+
+From: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
+
+[ Upstream commit b719afaa1e5d88a1b51d76adf344ff4a48efdb45 ]
+
+In the event of ASF error during the transfer, update the cmd and exit
+the process, as data processing is not performed when a command fails.
+
+Co-developed-by: Sanket Goswami <Sanket.Goswami@amd.com>
+Signed-off-by: Sanket Goswami <Sanket.Goswami@amd.com>
+Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
+Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
+Link: https://lore.kernel.org/r/20250217090258.398540-2-Shyam-sundar.S-k@amd.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i2c/busses/i2c-amd-asf-plat.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/i2c/busses/i2c-amd-asf-plat.c b/drivers/i2c/busses/i2c-amd-asf-plat.c
+index 93ebec162c6dd..61bc714c28d70 100644
+--- a/drivers/i2c/busses/i2c-amd-asf-plat.c
++++ b/drivers/i2c/busses/i2c-amd-asf-plat.c
+@@ -69,7 +69,7 @@ static void amd_asf_process_target(struct work_struct *work)
+ /* Check if no error bits are set in target status register */
+ if (reg & ASF_ERROR_STATUS) {
+ /* Set bank as full */
+- cmd = 0;
++ cmd = 1;
+ reg |= GENMASK(3, 2);
+ outb_p(reg, ASFDATABNKSEL);
+ } else {
+--
+2.39.5
+
--- /dev/null
+From e708d12e9eb63ed204f014e6d76668e400cd409b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 12 Feb 2025 20:28:03 +0300
+Subject: i2c: pxa: fix call balance of i2c->clk handling routines
+
+From: Vitalii Mordan <mordan@ispras.ru>
+
+[ Upstream commit be7113d2e2a6f20cbee99c98d261a1fd6fd7b549 ]
+
+If the clock i2c->clk was not enabled in i2c_pxa_probe(), it should not be
+disabled in any path.
+
+Found by Linux Verification Center (linuxtesting.org) with Klever.
+
+Signed-off-by: Vitalii Mordan <mordan@ispras.ru>
+Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
+Link: https://lore.kernel.org/r/20250212172803.1422136-1-mordan@ispras.ru
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i2c/busses/i2c-pxa.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
+index cb69884826739..4415a29f749b9 100644
+--- a/drivers/i2c/busses/i2c-pxa.c
++++ b/drivers/i2c/busses/i2c-pxa.c
+@@ -1503,7 +1503,10 @@ static int i2c_pxa_probe(struct platform_device *dev)
+ i2c->adap.name);
+ }
+
+- clk_prepare_enable(i2c->clk);
++ ret = clk_prepare_enable(i2c->clk);
++ if (ret)
++ return dev_err_probe(&dev->dev, ret,
++ "failed to enable clock\n");
+
+ if (i2c->use_pio) {
+ i2c->adap.algo = &i2c_pxa_pio_algorithm;
+--
+2.39.5
+
--- /dev/null
+From ce11ee0a0670ba6bdd498ca59a79bb5e8462b96e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 22 Jan 2025 12:16:34 +0530
+Subject: i2c: qcom-geni: Update i2c frequency table to match hardware guidance
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Mukesh Kumar Savaliya <quic_msavaliy@quicinc.com>
+
+[ Upstream commit a815975cbaeb4ab29f45312ef23be2871b2e8b82 ]
+
+With the current settings, the I2C buses are achieving around 370KHz
+instead of the expected 400KHz. For 100KHz and 1MHz, the settings are
+now more compliant and adhere to the Qualcomm’s internal programming
+guide.
+
+Update the I2C frequency table to align with the recommended values
+outlined in the I2C hardware programming guide, ensuring proper
+communication and performance.
+
+Signed-off-by: Mukesh Kumar Savaliya <quic_msavaliy@quicinc.com>
+Reviewed-by: Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
+Link: https://lore.kernel.org/r/20250122064634.2864432-1-quic_msavaliy@quicinc.com
+Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i2c/busses/i2c-qcom-geni.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
+index 7bbd478171e02..515a784c951ca 100644
+--- a/drivers/i2c/busses/i2c-qcom-geni.c
++++ b/drivers/i2c/busses/i2c-qcom-geni.c
+@@ -148,9 +148,9 @@ struct geni_i2c_clk_fld {
+ * source_clock = 19.2 MHz
+ */
+ static const struct geni_i2c_clk_fld geni_i2c_clk_map_19p2mhz[] = {
+- {KHZ(100), 7, 10, 11, 26},
+- {KHZ(400), 2, 5, 12, 24},
+- {KHZ(1000), 1, 3, 9, 18},
++ {KHZ(100), 7, 10, 12, 26},
++ {KHZ(400), 2, 5, 11, 22},
++ {KHZ(1000), 1, 2, 8, 18},
+ {},
+ };
+
+--
+2.39.5
+
--- /dev/null
+From 35ae2ae7dc117137a347be96cc8685285d98301b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Nov 2023 10:48:37 +0100
+Subject: i2c: qup: Vote for interconnect bandwidth to DRAM
+
+From: Stephan Gerhold <stephan.gerhold@kernkonzept.com>
+
+[ Upstream commit d4f35233a6345f62637463ef6e0708f44ffaa583 ]
+
+When the I2C QUP controller is used together with a DMA engine it needs
+to vote for the interconnect path to the DRAM. Otherwise it may be
+unable to access the memory quickly enough.
+
+The requested peak bandwidth is dependent on the I2C core clock.
+
+To avoid sending votes too often the bandwidth is always requested when
+a DMA transfer starts, but dropped only on runtime suspend. Runtime
+suspend should only happen if no transfer is active. After resumption we
+can defer the next vote until the first DMA transfer actually happens.
+
+The implementation is largely identical to the one introduced for
+spi-qup in commit ecdaa9473019 ("spi: qup: Vote for interconnect
+bandwidth to DRAM") since both drivers represent the same hardware
+block.
+
+Signed-off-by: Stephan Gerhold <stephan.gerhold@kernkonzept.com>
+Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
+Link: https://lore.kernel.org/r/20231128-i2c-qup-dvfs-v1-3-59a0e3039111@kernkonzept.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i2c/busses/i2c-qup.c | 36 ++++++++++++++++++++++++++++++++++++
+ 1 file changed, 36 insertions(+)
+
+diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
+index da20b4487c9a5..3a36d682ed572 100644
+--- a/drivers/i2c/busses/i2c-qup.c
++++ b/drivers/i2c/busses/i2c-qup.c
+@@ -14,6 +14,7 @@
+ #include <linux/dma-mapping.h>
+ #include <linux/err.h>
+ #include <linux/i2c.h>
++#include <linux/interconnect.h>
+ #include <linux/interrupt.h>
+ #include <linux/io.h>
+ #include <linux/module.h>
+@@ -150,6 +151,8 @@
+ /* TAG length for DATA READ in RX FIFO */
+ #define READ_RX_TAGS_LEN 2
+
++#define QUP_BUS_WIDTH 8
++
+ static unsigned int scl_freq;
+ module_param_named(scl_freq, scl_freq, uint, 0444);
+ MODULE_PARM_DESC(scl_freq, "SCL frequency override");
+@@ -227,6 +230,7 @@ struct qup_i2c_dev {
+ int irq;
+ struct clk *clk;
+ struct clk *pclk;
++ struct icc_path *icc_path;
+ struct i2c_adapter adap;
+
+ int clk_ctl;
+@@ -255,6 +259,10 @@ struct qup_i2c_dev {
+ /* To configure when bus is in run state */
+ u32 config_run;
+
++ /* bandwidth votes */
++ u32 src_clk_freq;
++ u32 cur_bw_clk_freq;
++
+ /* dma parameters */
+ bool is_dma;
+ /* To check if the current transfer is using DMA */
+@@ -453,6 +461,23 @@ static int qup_i2c_bus_active(struct qup_i2c_dev *qup, int len)
+ return ret;
+ }
+
++static int qup_i2c_vote_bw(struct qup_i2c_dev *qup, u32 clk_freq)
++{
++ u32 needed_peak_bw;
++ int ret;
++
++ if (qup->cur_bw_clk_freq == clk_freq)
++ return 0;
++
++ needed_peak_bw = Bps_to_icc(clk_freq * QUP_BUS_WIDTH);
++ ret = icc_set_bw(qup->icc_path, 0, needed_peak_bw);
++ if (ret)
++ return ret;
++
++ qup->cur_bw_clk_freq = clk_freq;
++ return 0;
++}
++
+ static void qup_i2c_write_tx_fifo_v1(struct qup_i2c_dev *qup)
+ {
+ struct qup_i2c_block *blk = &qup->blk;
+@@ -838,6 +863,10 @@ static int qup_i2c_bam_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
+ int ret = 0;
+ int idx = 0;
+
++ ret = qup_i2c_vote_bw(qup, qup->src_clk_freq);
++ if (ret)
++ return ret;
++
+ enable_irq(qup->irq);
+ ret = qup_i2c_req_dma(qup);
+
+@@ -1643,6 +1672,7 @@ static void qup_i2c_disable_clocks(struct qup_i2c_dev *qup)
+ config = readl(qup->base + QUP_CONFIG);
+ config |= QUP_CLOCK_AUTO_GATE;
+ writel(config, qup->base + QUP_CONFIG);
++ qup_i2c_vote_bw(qup, 0);
+ clk_disable_unprepare(qup->pclk);
+ }
+
+@@ -1743,6 +1773,11 @@ static int qup_i2c_probe(struct platform_device *pdev)
+ goto fail_dma;
+ }
+ qup->is_dma = true;
++
++ qup->icc_path = devm_of_icc_get(&pdev->dev, NULL);
++ if (IS_ERR(qup->icc_path))
++ return dev_err_probe(&pdev->dev, PTR_ERR(qup->icc_path),
++ "failed to get interconnect path\n");
+ }
+
+ nodma:
+@@ -1791,6 +1826,7 @@ static int qup_i2c_probe(struct platform_device *pdev)
+ qup_i2c_enable_clocks(qup);
+ src_clk_freq = clk_get_rate(qup->clk);
+ }
++ qup->src_clk_freq = src_clk_freq;
+
+ /*
+ * Bootloaders might leave a pending interrupt on certain QUP's,
+--
+2.39.5
+
--- /dev/null
+From dd36322433813f734aeac301b3fd122d9c7a8e9c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 19 Mar 2025 09:08:01 -0700
+Subject: i3c: master: svc: Fix implicit fallthrough in
+ svc_i3c_master_ibi_work()
+
+From: Nathan Chancellor <nathan@kernel.org>
+
+[ Upstream commit e8d2d287e26d9bd9114cf258a123a6b70812442e ]
+
+Clang warns (or errors with CONFIG_WERROR=y):
+
+ drivers/i3c/master/svc-i3c-master.c:596:2: error: unannotated fall-through between switch labels [-Werror,-Wimplicit-fallthrough]
+ 596 | default:
+ | ^
+ drivers/i3c/master/svc-i3c-master.c:596:2: note: insert 'break;' to avoid fall-through
+ 596 | default:
+ | ^
+ | break;
+ 1 error generated.
+
+Clang is a little more pedantic than GCC, which does not warn when
+falling through to a case that is just break or return. Clang's version
+is more in line with the kernel's own stance in deprecated.rst, which
+states that all switch/case blocks must end in either break,
+fallthrough, continue, goto, or return. Add the missing break to silence
+the warning.
+
+Fixes: 0430bf9bc1ac ("i3c: master: svc: Fix missing STOP for master request")
+Signed-off-by: Nathan Chancellor <nathan@kernel.org>
+Link: https://lore.kernel.org/r/20250319-i3c-fix-clang-fallthrough-v1-1-d8e02be1ef5c@kernel.org
+Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i3c/master/svc-i3c-master.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c
+index 2cf2c567f8931..75127b6c161f0 100644
+--- a/drivers/i3c/master/svc-i3c-master.c
++++ b/drivers/i3c/master/svc-i3c-master.c
+@@ -552,6 +552,7 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
+ break;
+ case SVC_I3C_MSTATUS_IBITYPE_MASTER_REQUEST:
+ svc_i3c_master_emit_stop(master);
++ break;
+ default:
+ break;
+ }
+--
+2.39.5
+
--- /dev/null
+From 88e82d9963cbcadd297ace4e540115f2de30d874 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Mar 2025 13:36:06 +0800
+Subject: i3c: master: svc: Fix missing STOP for master request
+
+From: Stanley Chu <yschu@nuvoton.com>
+
+[ Upstream commit 0430bf9bc1ac068c8b8c540eb93e5751872efc51 ]
+
+The controller driver nacked the master request but didn't emit a
+STOP to end the transaction. The driver shall refuse the unsupported
+requests and return the controller state to IDLE by emitting a STOP.
+
+Signed-off-by: Stanley Chu <yschu@nuvoton.com>
+Reviewed-by: Frank Li <Frank.Li@nxp.com>
+Link: https://lore.kernel.org/r/20250318053606.3087121-4-yschu@nuvoton.com
+Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i3c/master/svc-i3c-master.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c
+index 0fc03bb5d0a6e..a18fe62962b0c 100644
+--- a/drivers/i3c/master/svc-i3c-master.c
++++ b/drivers/i3c/master/svc-i3c-master.c
+@@ -551,6 +551,7 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
+ queue_work(master->base.wq, &master->hj_work);
+ break;
+ case SVC_I3C_MSTATUS_IBITYPE_MASTER_REQUEST:
++ svc_i3c_master_emit_stop(master);
+ default:
+ break;
+ }
+--
+2.39.5
+
--- /dev/null
+From 4de38cc5cdeead059cb8cf1e4113af22143cc851 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jan 2025 11:22:50 -0500
+Subject: i3c: master: svc: Flush FIFO before sending Dynamic Address
+ Assignment(DAA)
+
+From: Frank Li <Frank.Li@nxp.com>
+
+[ Upstream commit a892ee4cf22a50e1d6988d0464a9a421f3e5db2f ]
+
+Ensure the FIFO is empty before issuing the DAA command to prevent
+incorrect command data from being sent. Align with other data transfers,
+such as svc_i3c_master_start_xfer_locked(), which flushes the FIFO before
+sending a command.
+
+Signed-off-by: Frank Li <Frank.Li@nxp.com>
+Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Link: https://lore.kernel.org/r/20250129162250.3629189-1-Frank.Li@nxp.com
+Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i3c/master/svc-i3c-master.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c
+index a18fe62962b0c..2cf2c567f8931 100644
+--- a/drivers/i3c/master/svc-i3c-master.c
++++ b/drivers/i3c/master/svc-i3c-master.c
+@@ -899,6 +899,8 @@ static int svc_i3c_master_do_daa_locked(struct svc_i3c_master *master,
+ u32 reg;
+ int ret, i;
+
++ svc_i3c_master_flush_fifo(master);
++
+ while (true) {
+ /* clean SVC_I3C_MINT_IBIWON w1c bits */
+ writel(SVC_I3C_MINT_IBIWON, master->regs + SVC_I3C_MSTATUS);
+--
+2.39.5
+
--- /dev/null
+From 48d0ae0535e344e5acb5453ec428ec5871d36d9f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Dec 2024 07:58:09 +0100
+Subject: ice: count combined queues using Rx/Tx count
+
+From: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
+
+[ Upstream commit c3a392bdd31adc474f1009ee85c13fdd01fe800d ]
+
+Previous implementation assumes that there is 1:1 matching between
+vectors and queues. It isn't always true.
+
+Get minimum value from Rx/Tx queues to determine combined queues number.
+
+Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
+Tested-by: Pucha Himasekhar Reddy <himasekharx.reddy.pucha@intel.com>
+Signed-off-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
+Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/intel/ice/ice_ethtool.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c
+index f241493a6ac88..6bbb304ad9ab7 100644
+--- a/drivers/net/ethernet/intel/ice/ice_ethtool.c
++++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c
+@@ -3817,8 +3817,7 @@ static u32 ice_get_combined_cnt(struct ice_vsi *vsi)
+ ice_for_each_q_vector(vsi, q_idx) {
+ struct ice_q_vector *q_vector = vsi->q_vectors[q_idx];
+
+- if (q_vector->rx.rx_ring && q_vector->tx.tx_ring)
+- combined++;
++ combined += min(q_vector->num_ring_tx, q_vector->num_ring_rx);
+ }
+
+ return combined;
+--
+2.39.5
+
--- /dev/null
+From 0c9110861c24e6c1488c42c21006fe6dccaf926b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Dec 2024 07:58:17 +0100
+Subject: ice: init flow director before RDMA
+
+From: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
+
+[ Upstream commit d67627e7b53203ca150e54723abbed81a0716286 ]
+
+Flow director needs only one MSI-X. Load it before RDMA to save MSI-X
+for it.
+
+Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
+Tested-by: Pucha Himasekhar Reddy <himasekharx.reddy.pucha@intel.com>
+Signed-off-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
+Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/intel/ice/ice_main.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
+index e13bd5a6cb6c4..d24d46b24e371 100644
+--- a/drivers/net/ethernet/intel/ice/ice_main.c
++++ b/drivers/net/ethernet/intel/ice/ice_main.c
+@@ -5186,11 +5186,12 @@ int ice_load(struct ice_pf *pf)
+
+ ice_napi_add(vsi);
+
++ ice_init_features(pf);
++
+ err = ice_init_rdma(pf);
+ if (err)
+ goto err_init_rdma;
+
+- ice_init_features(pf);
+ ice_service_task_restart(pf);
+
+ clear_bit(ICE_DOWN, pf->state);
+@@ -5198,6 +5199,7 @@ int ice_load(struct ice_pf *pf)
+ return 0;
+
+ err_init_rdma:
++ ice_deinit_features(pf);
+ ice_tc_indir_block_unregister(vsi);
+ err_tc_indir_block_register:
+ ice_unregister_netdev(vsi);
+@@ -5221,8 +5223,8 @@ void ice_unload(struct ice_pf *pf)
+
+ devl_assert_locked(priv_to_devlink(pf));
+
+- ice_deinit_features(pf);
+ ice_deinit_rdma(pf);
++ ice_deinit_features(pf);
+ ice_tc_indir_block_unregister(vsi);
+ ice_unregister_netdev(vsi);
+ ice_devlink_destroy_pf_port(pf);
+--
+2.39.5
+
--- /dev/null
+From 80dd118b04fa3f6752ec77106942c9b78cfc7b70 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Dec 2024 07:58:14 +0100
+Subject: ice: treat dyn_allowed only as suggestion
+
+From: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
+
+[ Upstream commit a8c2d3932c1106af2764cc6869b29bcf3cb5bc47 ]
+
+It can be needed to have some MSI-X allocated as static and rest as
+dynamic. For example on PF VSI. We want to always have minimum one MSI-X
+on it, because of that it is allocated as a static one, rest can be
+dynamic if it is supported.
+
+Change the ice_get_irq_res() to allow using static entries if they are
+free even if caller wants dynamic one.
+
+Adjust limit values to the new approach. Min and max in limit means the
+values that are valid, so decrease max and num_static by one.
+
+Set vsi::irq_dyn_alloc if dynamic allocation is supported.
+
+Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
+Reviewed-by: Wojciech Drewek <wojciech.drewek@intel.com>
+Tested-by: Pucha Himasekhar Reddy <himasekharx.reddy.pucha@intel.com>
+Signed-off-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
+Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/intel/ice/ice_irq.c | 25 ++++++++++++------------
+ drivers/net/ethernet/intel/ice/ice_lib.c | 2 ++
+ 2 files changed, 15 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/net/ethernet/intel/ice/ice_irq.c b/drivers/net/ethernet/intel/ice/ice_irq.c
+index ad82ff7d19957..09f9c7ba52795 100644
+--- a/drivers/net/ethernet/intel/ice/ice_irq.c
++++ b/drivers/net/ethernet/intel/ice/ice_irq.c
+@@ -45,7 +45,7 @@ static void ice_free_irq_res(struct ice_pf *pf, u16 index)
+ /**
+ * ice_get_irq_res - get an interrupt resource
+ * @pf: board private structure
+- * @dyn_only: force entry to be dynamically allocated
++ * @dyn_allowed: allow entry to be dynamically allocated
+ *
+ * Allocate new irq entry in the free slot of the tracker. Since xarray
+ * is used, always allocate new entry at the lowest possible index. Set
+@@ -53,11 +53,12 @@ static void ice_free_irq_res(struct ice_pf *pf, u16 index)
+ *
+ * Returns allocated irq entry or NULL on failure.
+ */
+-static struct ice_irq_entry *ice_get_irq_res(struct ice_pf *pf, bool dyn_only)
++static struct ice_irq_entry *ice_get_irq_res(struct ice_pf *pf,
++ bool dyn_allowed)
+ {
+- struct xa_limit limit = { .max = pf->irq_tracker.num_entries,
++ struct xa_limit limit = { .max = pf->irq_tracker.num_entries - 1,
+ .min = 0 };
+- unsigned int num_static = pf->irq_tracker.num_static;
++ unsigned int num_static = pf->irq_tracker.num_static - 1;
+ struct ice_irq_entry *entry;
+ unsigned int index;
+ int ret;
+@@ -66,9 +67,9 @@ static struct ice_irq_entry *ice_get_irq_res(struct ice_pf *pf, bool dyn_only)
+ if (!entry)
+ return NULL;
+
+- /* skip preallocated entries if the caller says so */
+- if (dyn_only)
+- limit.min = num_static;
++ /* only already allocated if the caller says so */
++ if (!dyn_allowed)
++ limit.max = num_static;
+
+ ret = xa_alloc(&pf->irq_tracker.entries, &index, entry, limit,
+ GFP_KERNEL);
+@@ -78,7 +79,7 @@ static struct ice_irq_entry *ice_get_irq_res(struct ice_pf *pf, bool dyn_only)
+ entry = NULL;
+ } else {
+ entry->index = index;
+- entry->dynamic = index >= num_static;
++ entry->dynamic = index > num_static;
+ }
+
+ return entry;
+@@ -272,7 +273,7 @@ int ice_init_interrupt_scheme(struct ice_pf *pf)
+ /**
+ * ice_alloc_irq - Allocate new interrupt vector
+ * @pf: board private structure
+- * @dyn_only: force dynamic allocation of the interrupt
++ * @dyn_allowed: allow dynamic allocation of the interrupt
+ *
+ * Allocate new interrupt vector for a given owner id.
+ * return struct msi_map with interrupt details and track
+@@ -285,20 +286,20 @@ int ice_init_interrupt_scheme(struct ice_pf *pf)
+ * interrupt will be allocated with pci_msix_alloc_irq_at.
+ *
+ * Some callers may only support dynamically allocated interrupts.
+- * This is indicated with dyn_only flag.
++ * This is indicated with dyn_allowed flag.
+ *
+ * On failure, return map with negative .index. The caller
+ * is expected to check returned map index.
+ *
+ */
+-struct msi_map ice_alloc_irq(struct ice_pf *pf, bool dyn_only)
++struct msi_map ice_alloc_irq(struct ice_pf *pf, bool dyn_allowed)
+ {
+ int sriov_base_vector = pf->sriov_base_vector;
+ struct msi_map map = { .index = -ENOENT };
+ struct device *dev = ice_pf_to_dev(pf);
+ struct ice_irq_entry *entry;
+
+- entry = ice_get_irq_res(pf, dyn_only);
++ entry = ice_get_irq_res(pf, dyn_allowed);
+ if (!entry)
+ return map;
+
+diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
+index e0785e820d601..021ed7451bb9f 100644
+--- a/drivers/net/ethernet/intel/ice/ice_lib.c
++++ b/drivers/net/ethernet/intel/ice/ice_lib.c
+@@ -567,6 +567,8 @@ ice_vsi_alloc_def(struct ice_vsi *vsi, struct ice_channel *ch)
+ return -ENOMEM;
+ }
+
++ vsi->irq_dyn_alloc = pci_msix_can_alloc_dyn(vsi->back->pdev);
++
+ switch (vsi->type) {
+ case ICE_VSI_PF:
+ case ICE_VSI_SF:
+--
+2.39.5
+
--- /dev/null
+From 473395e621aa116566f6b499c2cf7d31b6317490 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Mar 2025 12:55:34 +0200
+Subject: ieee802154: ca8210: Use proper setters and getters for bitwise types
+
+From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+
+[ Upstream commit 169b2262205836a5d1213ff44dca2962276bece1 ]
+
+Sparse complains that the driver doesn't respect the bitwise types:
+
+drivers/net/ieee802154/ca8210.c:1796:27: warning: incorrect type in assignment (different base types)
+drivers/net/ieee802154/ca8210.c:1796:27: expected restricted __le16 [addressable] [assigned] [usertype] pan_id
+drivers/net/ieee802154/ca8210.c:1796:27: got unsigned short [usertype]
+drivers/net/ieee802154/ca8210.c:1801:25: warning: incorrect type in assignment (different base types)
+drivers/net/ieee802154/ca8210.c:1801:25: expected restricted __le16 [addressable] [assigned] [usertype] pan_id
+drivers/net/ieee802154/ca8210.c:1801:25: got unsigned short [usertype]
+drivers/net/ieee802154/ca8210.c:1928:28: warning: incorrect type in argument 3 (different base types)
+drivers/net/ieee802154/ca8210.c:1928:28: expected unsigned short [usertype] dst_pan_id
+drivers/net/ieee802154/ca8210.c:1928:28: got restricted __le16 [addressable] [usertype] pan_id
+
+Use proper setters and getters for bitwise types.
+
+Note, in accordance with [1] the protocol is little endian.
+
+Link: https://www.cascoda.com/wp-content/uploads/2018/11/CA-8210_datasheet_0418.pdf [1]
+Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Link: https://lore.kernel.org/20250305105656.2133487-2-andriy.shevchenko@linux.intel.com
+Signed-off-by: Stefan Schmidt <stefan@datenfreihafen.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ieee802154/ca8210.c | 9 ++++-----
+ 1 file changed, 4 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c
+index 753215ebc67c7..a036910f60828 100644
+--- a/drivers/net/ieee802154/ca8210.c
++++ b/drivers/net/ieee802154/ca8210.c
+@@ -1446,8 +1446,7 @@ static u8 mcps_data_request(
+ command.pdata.data_req.src_addr_mode = src_addr_mode;
+ command.pdata.data_req.dst.mode = dst_address_mode;
+ if (dst_address_mode != MAC_MODE_NO_ADDR) {
+- command.pdata.data_req.dst.pan_id[0] = LS_BYTE(dst_pan_id);
+- command.pdata.data_req.dst.pan_id[1] = MS_BYTE(dst_pan_id);
++ put_unaligned_le16(dst_pan_id, command.pdata.data_req.dst.pan_id);
+ if (dst_address_mode == MAC_MODE_SHORT_ADDR) {
+ command.pdata.data_req.dst.address[0] = LS_BYTE(
+ dst_addr->short_address
+@@ -1795,12 +1794,12 @@ static int ca8210_skb_rx(
+ }
+ hdr.source.mode = data_ind[0];
+ dev_dbg(&priv->spi->dev, "srcAddrMode: %#03x\n", hdr.source.mode);
+- hdr.source.pan_id = *(u16 *)&data_ind[1];
++ hdr.source.pan_id = cpu_to_le16(get_unaligned_le16(&data_ind[1]));
+ dev_dbg(&priv->spi->dev, "srcPanId: %#06x\n", hdr.source.pan_id);
+ memcpy(&hdr.source.extended_addr, &data_ind[3], 8);
+ hdr.dest.mode = data_ind[11];
+ dev_dbg(&priv->spi->dev, "dstAddrMode: %#03x\n", hdr.dest.mode);
+- hdr.dest.pan_id = *(u16 *)&data_ind[12];
++ hdr.dest.pan_id = cpu_to_le16(get_unaligned_le16(&data_ind[12]));
+ dev_dbg(&priv->spi->dev, "dstPanId: %#06x\n", hdr.dest.pan_id);
+ memcpy(&hdr.dest.extended_addr, &data_ind[14], 8);
+
+@@ -1927,7 +1926,7 @@ static int ca8210_skb_tx(
+ status = mcps_data_request(
+ header.source.mode,
+ header.dest.mode,
+- header.dest.pan_id,
++ le16_to_cpu(header.dest.pan_id),
+ (union macaddr *)&header.dest.extended_addr,
+ skb->len - mac_len,
+ &skb->data[mac_len],
+--
+2.39.5
+
--- /dev/null
+From 7e73b3d356fea2e75bf5bd79b3a59c788e551137 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 16 Dec 2024 15:38:49 +0800
+Subject: igc: Avoid unnecessary link down event in XDP_SETUP_PROG process
+
+From: Song Yoong Siang <yoong.siang.song@intel.com>
+
+[ Upstream commit be324b790368c1522f07c6bb5654122e07b5e588 ]
+
+The igc_close()/igc_open() functions are too drastic for installing a new
+XDP prog because they cause undesirable link down event and device reset.
+
+To avoid delays in Ethernet traffic, improve the XDP_SETUP_PROG process by
+using the same sequence as igc_xdp_setup_pool(), which performs only the
+necessary steps, as follows:
+ 1. stop the traffic and clean buffer
+ 2. stop NAPI
+ 3. install the XDP program
+ 4. resume NAPI
+ 5. allocate buffer and resume the traffic
+
+This patch has been tested using the 'ip link set xdpdrv' command to attach
+a simple XDP prog that always returns XDP_PASS.
+
+Before this patch, attaching xdp program will cause ptp4l to lose sync for
+few seconds, as shown in ptp4l log below:
+ ptp4l[198.082]: rms 4 max 8 freq +906 +/- 2 delay 12 +/- 0
+ ptp4l[199.082]: rms 3 max 4 freq +906 +/- 3 delay 12 +/- 0
+ ptp4l[199.536]: port 1 (enp2s0): link down
+ ptp4l[199.536]: port 1 (enp2s0): SLAVE to FAULTY on FAULT_DETECTED (FT_UNSPECIFIED)
+ ptp4l[199.600]: selected local clock 22abbc.fffe.bb1234 as best master
+ ptp4l[199.600]: port 1 (enp2s0): assuming the grand master role
+ ptp4l[199.600]: port 1 (enp2s0): master state recommended in slave only mode
+ ptp4l[199.600]: port 1 (enp2s0): defaultDS.priority1 probably misconfigured
+ ptp4l[202.266]: port 1 (enp2s0): link up
+ ptp4l[202.300]: port 1 (enp2s0): FAULTY to LISTENING on INIT_COMPLETE
+ ptp4l[205.558]: port 1 (enp2s0): new foreign master 44abbc.fffe.bb2144-1
+ ptp4l[207.558]: selected best master clock 44abbc.fffe.bb2144
+ ptp4l[207.559]: port 1 (enp2s0): LISTENING to UNCALIBRATED on RS_SLAVE
+ ptp4l[208.308]: port 1 (enp2s0): UNCALIBRATED to SLAVE on MASTER_CLOCK_SELECTED
+ ptp4l[208.933]: rms 742 max 1303 freq -195 +/- 682 delay 12 +/- 0
+ ptp4l[209.933]: rms 178 max 274 freq +387 +/- 243 delay 12 +/- 0
+
+After this patch, attaching xdp program no longer cause ptp4l to lose sync,
+as shown in ptp4l log below:
+ ptp4l[201.183]: rms 1 max 3 freq +959 +/- 1 delay 8 +/- 0
+ ptp4l[202.183]: rms 1 max 3 freq +961 +/- 2 delay 8 +/- 0
+ ptp4l[203.183]: rms 2 max 3 freq +958 +/- 2 delay 8 +/- 0
+ ptp4l[204.183]: rms 3 max 5 freq +961 +/- 3 delay 8 +/- 0
+ ptp4l[205.183]: rms 2 max 4 freq +964 +/- 3 delay 8 +/- 0
+
+Besides, before this patch, attaching xdp program will causes flood ping to
+lose 10 packets, as shown in ping statistics below:
+ --- 169.254.1.2 ping statistics ---
+ 100000 packets transmitted, 99990 received, +6 errors, 0.01% packet loss, time 34001ms
+ rtt min/avg/max/mdev = 0.028/0.301/3104.360/13.838 ms, pipe 10, ipg/ewma 0.340/0.243 ms
+
+After this patch, attaching xdp program no longer cause flood ping to loss
+any packets, as shown in ping statistics below:
+ --- 169.254.1.2 ping statistics ---
+ 100000 packets transmitted, 100000 received, 0% packet loss, time 32326ms
+ rtt min/avg/max/mdev = 0.027/0.231/19.589/0.155 ms, pipe 2, ipg/ewma 0.323/0.322 ms
+
+On the other hand, this patch has been tested with tools/testing/selftests/
+bpf/xdp_hw_metadata app to make sure AF_XDP zero-copy is working fine with
+XDP Tx and Rx metadata. Below is the result of last packet after received
+10000 UDP packets with interval 1 ms:
+ poll: 1 (0) skip=0 fail=0 redir=10000
+ xsk_ring_cons__peek: 1
+ 0x55881c7ef7a8: rx_desc[9999]->addr=8f110 addr=8f110 comp_addr=8f110 EoP
+ rx_hash: 0xFB9BB6A3 with RSS type:0x1
+ HW RX-time: 1733923136269470866 (sec:1733923136.2695) delta to User RX-time sec:0.0000 (43.280 usec)
+ XDP RX-time: 1733923136269482482 (sec:1733923136.2695) delta to User RX-time sec:0.0000 (31.664 usec)
+ No rx_vlan_tci or rx_vlan_proto, err=-95
+ 0x55881c7ef7a8: ping-pong with csum=ab19 (want 315b) csum_start=34 csum_offset=6
+ 0x55881c7ef7a8: complete tx idx=9999 addr=f010
+ HW TX-complete-time: 1733923136269591637 (sec:1733923136.2696) delta to User TX-complete-time sec:0.0001 (108.571 usec)
+ XDP RX-time: 1733923136269482482 (sec:1733923136.2695) delta to User TX-complete-time sec:0.0002 (217.726 usec)
+ HW RX-time: 1733923136269470866 (sec:1733923136.2695) delta to HW TX-complete-time sec:0.0001 (120.771 usec)
+ 0x55881c7ef7a8: complete rx idx=10127 addr=8f110
+
+Signed-off-by: Song Yoong Siang <yoong.siang.song@intel.com>
+Tested-by: Avigail Dahan <avigailx.dahan@intel.com>
+Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/intel/igc/igc_xdp.c | 19 +++++++++++++++----
+ 1 file changed, 15 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/ethernet/intel/igc/igc_xdp.c b/drivers/net/ethernet/intel/igc/igc_xdp.c
+index 869815f48ac1d..9eb47b4beb062 100644
+--- a/drivers/net/ethernet/intel/igc/igc_xdp.c
++++ b/drivers/net/ethernet/intel/igc/igc_xdp.c
+@@ -14,6 +14,7 @@ int igc_xdp_set_prog(struct igc_adapter *adapter, struct bpf_prog *prog,
+ bool if_running = netif_running(dev);
+ struct bpf_prog *old_prog;
+ bool need_update;
++ unsigned int i;
+
+ if (dev->mtu > ETH_DATA_LEN) {
+ /* For now, the driver doesn't support XDP functionality with
+@@ -24,8 +25,13 @@ int igc_xdp_set_prog(struct igc_adapter *adapter, struct bpf_prog *prog,
+ }
+
+ need_update = !!adapter->xdp_prog != !!prog;
+- if (if_running && need_update)
+- igc_close(dev);
++ if (if_running && need_update) {
++ for (i = 0; i < adapter->num_rx_queues; i++) {
++ igc_disable_rx_ring(adapter->rx_ring[i]);
++ igc_disable_tx_ring(adapter->tx_ring[i]);
++ napi_disable(&adapter->rx_ring[i]->q_vector->napi);
++ }
++ }
+
+ old_prog = xchg(&adapter->xdp_prog, prog);
+ if (old_prog)
+@@ -36,8 +42,13 @@ int igc_xdp_set_prog(struct igc_adapter *adapter, struct bpf_prog *prog,
+ else
+ xdp_features_clear_redirect_target(dev);
+
+- if (if_running && need_update)
+- igc_open(dev);
++ if (if_running && need_update) {
++ for (i = 0; i < adapter->num_rx_queues; i++) {
++ napi_enable(&adapter->rx_ring[i]->q_vector->napi);
++ igc_enable_tx_ring(adapter->tx_ring[i]);
++ igc_enable_rx_ring(adapter->rx_ring[i]);
++ }
++ }
+
+ return 0;
+ }
+--
+2.39.5
+
--- /dev/null
+From 546c915b2d8a13f8fd17079552c0e5480dd05b99 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 6 Apr 2025 22:01:42 +0200
+Subject: iio: accel: fxls8962af: Fix wakeup source leaks on device unbind
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+[ Upstream commit 0cd34d98dfd4f2b596415b8f12faf7b946613458 ]
+
+Device can be unbound, so driver must also release memory for the wakeup
+source.
+
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Link: https://patch.msgid.link/20250406-b4-device-wakeup-leak-iio-v1-1-2d7d322a4a93@linaro.org
+Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iio/accel/fxls8962af-core.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/iio/accel/fxls8962af-core.c b/drivers/iio/accel/fxls8962af-core.c
+index 987212a7c038e..a0ae30c86687a 100644
+--- a/drivers/iio/accel/fxls8962af-core.c
++++ b/drivers/iio/accel/fxls8962af-core.c
+@@ -1229,8 +1229,11 @@ int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq)
+ if (ret)
+ return ret;
+
+- if (device_property_read_bool(dev, "wakeup-source"))
+- device_init_wakeup(dev, true);
++ if (device_property_read_bool(dev, "wakeup-source")) {
++ ret = devm_device_init_wakeup(dev);
++ if (ret)
++ return dev_err_probe(dev, ret, "Failed to init wakeup\n");
++ }
+
+ return devm_iio_device_register(dev, indio_dev);
+ }
+--
+2.39.5
+
--- /dev/null
+From 36672aa9f3a4f7d1b64110974b22b78dffcbfc41 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 10 Feb 2025 17:10:57 +0100
+Subject: iio: adc: ad7606: protect register access
+
+From: Angelo Dureghello <adureghello@baylibre.com>
+
+[ Upstream commit 0f65f59e632d942cccffd12c36036c24eb7037eb ]
+
+Protect register (and bus) access from concurrent
+read / write. Needed in the backend operating mode.
+
+Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
+Link: https://patch.msgid.link/20250210-wip-bl-ad7606_add_backend_sw_mode-v4-7-160df18b1da7@baylibre.com
+Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iio/adc/ad7606.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c
+index 0339e27f92c32..1c547e8d52ac0 100644
+--- a/drivers/iio/adc/ad7606.c
++++ b/drivers/iio/adc/ad7606.c
+@@ -862,7 +862,12 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
+ }
+ val = (val * MICRO) + val2;
+ i = find_closest(val, scale_avail_uv, cs->num_scales);
++
++ ret = iio_device_claim_direct_mode(indio_dev);
++ if (ret < 0)
++ return ret;
+ ret = st->write_scale(indio_dev, ch, i + cs->reg_offset);
++ iio_device_release_direct_mode(indio_dev);
+ if (ret < 0)
+ return ret;
+ cs->range = i;
+@@ -873,7 +878,12 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
+ return -EINVAL;
+ i = find_closest(val, st->oversampling_avail,
+ st->num_os_ratios);
++
++ ret = iio_device_claim_direct_mode(indio_dev);
++ if (ret < 0)
++ return ret;
+ ret = st->write_os(indio_dev, i);
++ iio_device_release_direct_mode(indio_dev);
+ if (ret < 0)
+ return ret;
+ st->oversampling = st->oversampling_avail[i];
+--
+2.39.5
+
--- /dev/null
+From 8b7f684ac437bf98fe437ac6ba387c4fc1f7b3bf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 7 Feb 2025 14:09:07 -0600
+Subject: iio: adc: ad7944: don't use storagebits for sizing
+
+From: David Lechner <dlechner@baylibre.com>
+
+[ Upstream commit 503d20ed8cf7c7b40ec0bd94f53c490c1d91c31b ]
+
+Replace use of storagebits with realbits for determining the number of
+bytes needed for SPI transfers.
+
+When adding SPI offload support, storagebits will always be 32 rather
+than 16 for 16-bit 16-bit chips so we can no longer rely on storagebits
+being the correct size expected by the SPI framework (it always uses
+4 bytes for > 16-bit xfers and 2 bytes for > 8-bit xfers). Instead,
+derive the correct size from realbits since it will always be correct
+even when SPI offloading is used.
+
+Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
+Reviewed-vy: Nuno Sa <nuno.sa@analog.com>
+Signed-off-by: David Lechner <dlechner@baylibre.com>
+Link: https://patch.msgid.link/20250207-dlech-mainline-spi-engine-offload-2-v8-10-e48a489be48c@baylibre.com
+Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iio/adc/ad7944.c | 16 +++++++++-------
+ 1 file changed, 9 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/iio/adc/ad7944.c b/drivers/iio/adc/ad7944.c
+index 0ec9cda10f5f8..abfababcea101 100644
+--- a/drivers/iio/adc/ad7944.c
++++ b/drivers/iio/adc/ad7944.c
+@@ -98,6 +98,9 @@ struct ad7944_chip_info {
+ const struct iio_chan_spec channels[2];
+ };
+
++/* get number of bytes for SPI xfer */
++#define AD7944_SPI_BYTES(scan_type) ((scan_type).realbits > 16 ? 4 : 2)
++
+ /*
+ * AD7944_DEFINE_CHIP_INFO - Define a chip info structure for a specific chip
+ * @_name: The name of the chip
+@@ -164,7 +167,7 @@ static int ad7944_3wire_cs_mode_init_msg(struct device *dev, struct ad7944_adc *
+
+ /* Then we can read the data during the acquisition phase */
+ xfers[2].rx_buf = &adc->sample.raw;
+- xfers[2].len = BITS_TO_BYTES(chan->scan_type.storagebits);
++ xfers[2].len = AD7944_SPI_BYTES(chan->scan_type);
+ xfers[2].bits_per_word = chan->scan_type.realbits;
+
+ spi_message_init_with_transfers(&adc->msg, xfers, 3);
+@@ -193,7 +196,7 @@ static int ad7944_4wire_mode_init_msg(struct device *dev, struct ad7944_adc *adc
+ xfers[0].delay.unit = SPI_DELAY_UNIT_NSECS;
+
+ xfers[1].rx_buf = &adc->sample.raw;
+- xfers[1].len = BITS_TO_BYTES(chan->scan_type.storagebits);
++ xfers[1].len = AD7944_SPI_BYTES(chan->scan_type);
+ xfers[1].bits_per_word = chan->scan_type.realbits;
+
+ spi_message_init_with_transfers(&adc->msg, xfers, 2);
+@@ -228,7 +231,7 @@ static int ad7944_chain_mode_init_msg(struct device *dev, struct ad7944_adc *adc
+ xfers[0].delay.unit = SPI_DELAY_UNIT_NSECS;
+
+ xfers[1].rx_buf = adc->chain_mode_buf;
+- xfers[1].len = BITS_TO_BYTES(chan->scan_type.storagebits) * n_chain_dev;
++ xfers[1].len = AD7944_SPI_BYTES(chan->scan_type) * n_chain_dev;
+ xfers[1].bits_per_word = chan->scan_type.realbits;
+
+ spi_message_init_with_transfers(&adc->msg, xfers, 2);
+@@ -274,12 +277,12 @@ static int ad7944_single_conversion(struct ad7944_adc *adc,
+ return ret;
+
+ if (adc->spi_mode == AD7944_SPI_MODE_CHAIN) {
+- if (chan->scan_type.storagebits > 16)
++ if (chan->scan_type.realbits > 16)
+ *val = ((u32 *)adc->chain_mode_buf)[chan->scan_index];
+ else
+ *val = ((u16 *)adc->chain_mode_buf)[chan->scan_index];
+ } else {
+- if (chan->scan_type.storagebits > 16)
++ if (chan->scan_type.realbits > 16)
+ *val = adc->sample.raw.u32;
+ else
+ *val = adc->sample.raw.u16;
+@@ -409,8 +412,7 @@ static int ad7944_chain_mode_alloc(struct device *dev,
+ /* 1 word for each voltage channel + aligned u64 for timestamp */
+
+ chain_mode_buf_size = ALIGN(n_chain_dev *
+- BITS_TO_BYTES(chan[0].scan_type.storagebits), sizeof(u64))
+- + sizeof(u64);
++ AD7944_SPI_BYTES(chan[0].scan_type), sizeof(u64)) + sizeof(u64);
+ buf = devm_kzalloc(dev, chain_mode_buf_size, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+--
+2.39.5
+
--- /dev/null
+From eb9fee854d85c10126a9b82ba59ca0a1567cf274 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 6 Apr 2025 22:01:43 +0200
+Subject: iio: adc: qcom-spmi-iadc: Fix wakeup source leaks on device unbind
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+[ Upstream commit ad3764b45c1524872b621d5667a56f6a574501bd ]
+
+Device can be unbound, so driver must also release memory for the wakeup
+source.
+
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Link: https://patch.msgid.link/20250406-b4-device-wakeup-leak-iio-v1-2-2d7d322a4a93@linaro.org
+Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iio/adc/qcom-spmi-iadc.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/iio/adc/qcom-spmi-iadc.c b/drivers/iio/adc/qcom-spmi-iadc.c
+index 7fb8b2499a1d0..b64a8a407168b 100644
+--- a/drivers/iio/adc/qcom-spmi-iadc.c
++++ b/drivers/iio/adc/qcom-spmi-iadc.c
+@@ -543,7 +543,9 @@ static int iadc_probe(struct platform_device *pdev)
+ else
+ return ret;
+ } else {
+- device_init_wakeup(iadc->dev, 1);
++ ret = devm_device_init_wakeup(iadc->dev);
++ if (ret)
++ return dev_err_probe(iadc->dev, ret, "Failed to init wakeup\n");
+ }
+
+ ret = iadc_update_offset(iadc);
+--
+2.39.5
+
--- /dev/null
+From ccf0494eb91ba1e31fae5cc3538f3d89ae78dc3b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 14 Jan 2025 16:30:15 +0100
+Subject: iio: dac: ad3552r-hs: use instruction mode for configuration
+
+From: Angelo Dureghello <adureghello@baylibre.com>
+
+[ Upstream commit 21889245fb538123ac9968eea0018f878b44c8c8 ]
+
+Use "instruction" mode over initial configuration and all other
+non-streaming operations.
+
+DAC boots in streaming mode as default, and the driver is not
+changing this mode.
+
+Instruction r/w is still working because instruction is processed
+from the DAC after chip select is deasserted, this works until
+loop mode is 0 or greater than the instruction size.
+
+All initial operations should be more safely done in instruction
+mode, a mode provided for this.
+
+Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
+Link: https://patch.msgid.link/20250114-wip-bl-ad3552r-axi-v0-iio-testing-carlos-v4-6-979402e33545@baylibre.com
+Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iio/dac/ad3552r-hs.c | 29 ++++++++++++++++++++++++++++-
+ 1 file changed, 28 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/iio/dac/ad3552r-hs.c b/drivers/iio/dac/ad3552r-hs.c
+index 8974df6256708..67957fc21696a 100644
+--- a/drivers/iio/dac/ad3552r-hs.c
++++ b/drivers/iio/dac/ad3552r-hs.c
+@@ -137,13 +137,20 @@ static int ad3552r_hs_buffer_postenable(struct iio_dev *indio_dev)
+ if (ret)
+ return ret;
+
++ /* Primary region access, set streaming mode (now in SPI + SDR). */
++ ret = ad3552r_qspi_update_reg_bits(st,
++ AD3552R_REG_ADDR_INTERFACE_CONFIG_B,
++ AD3552R_MASK_SINGLE_INST, 0, 1);
++ if (ret)
++ return ret;
++
+ /* Inform DAC chip to switch into DDR mode */
+ ret = ad3552r_qspi_update_reg_bits(st,
+ AD3552R_REG_ADDR_INTERFACE_CONFIG_D,
+ AD3552R_MASK_SPI_CONFIG_DDR,
+ AD3552R_MASK_SPI_CONFIG_DDR, 1);
+ if (ret)
+- return ret;
++ goto exit_err_ddr;
+
+ /* Inform DAC IP to go for DDR mode from now on */
+ ret = iio_backend_ddr_enable(st->back);
+@@ -174,6 +181,11 @@ static int ad3552r_hs_buffer_postenable(struct iio_dev *indio_dev)
+
+ iio_backend_ddr_disable(st->back);
+
++exit_err_ddr:
++ ad3552r_qspi_update_reg_bits(st, AD3552R_REG_ADDR_INTERFACE_CONFIG_B,
++ AD3552R_MASK_SINGLE_INST,
++ AD3552R_MASK_SINGLE_INST, 1);
++
+ return ret;
+ }
+
+@@ -198,6 +210,14 @@ static int ad3552r_hs_buffer_predisable(struct iio_dev *indio_dev)
+ if (ret)
+ return ret;
+
++ /* Back to single instruction mode, disabling loop. */
++ ret = ad3552r_qspi_update_reg_bits(st,
++ AD3552R_REG_ADDR_INTERFACE_CONFIG_B,
++ AD3552R_MASK_SINGLE_INST,
++ AD3552R_MASK_SINGLE_INST, 1);
++ if (ret)
++ return ret;
++
+ return 0;
+ }
+
+@@ -308,6 +328,13 @@ static int ad3552r_hs_setup(struct ad3552r_hs_state *st)
+ if (ret)
+ return ret;
+
++ ret = st->data->bus_reg_write(st->back,
++ AD3552R_REG_ADDR_INTERFACE_CONFIG_B,
++ AD3552R_MASK_SINGLE_INST |
++ AD3552R_MASK_SHORT_INSTRUCTION, 1);
++ if (ret)
++ return ret;
++
+ ret = ad3552r_hs_scratch_pad_test(st);
+ if (ret)
+ return ret;
+--
+2.39.5
+
--- /dev/null
+From efe6d7110da8b3a7d436dca5b3c58020b0812cc1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 14 Jan 2025 16:30:13 +0100
+Subject: iio: dac: adi-axi-dac: add bus mode setup
+
+From: Angelo Dureghello <adureghello@baylibre.com>
+
+[ Upstream commit 8ab67b37b81dfaa00a25e95a5f5a020f374848bb ]
+
+The ad354xr requires DSPI mode (2 data lanes) to work in buffering
+mode, so, depending on the DAC type, target TRANSFER_REGISTER
+"MULTI_IO_MODE" bitfield can be set between:
+ SPI (configuration, entire ad35xxr family),
+ DSPI (ad354xr),
+ QSPI (ad355xr).
+Also bus IO_MODE must be set accordingly.
+
+About removal of AXI_DAC_CUSTOM_CTRL_SYNCED_TRANSFER, according to
+the HDL history the flag has never been used. So looks like the driver
+was including it by mistake or in anticipation for something that was
+never implemented on HDL side.
+
+Current HDL updated documentation confirm it is actually not in use
+anymore and replaced by the IO_MODE bits.
+
+Reviewed-by: Nuno Sa <nuno.sa@analog.com>
+Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
+Link: https://patch.msgid.link/20250114-wip-bl-ad3552r-axi-v0-iio-testing-carlos-v4-4-979402e33545@baylibre.com
+Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iio/dac/ad3552r-hs.h | 8 ++++++++
+ drivers/iio/dac/adi-axi-dac.c | 22 +++++++++++++++++++++-
+ 2 files changed, 29 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/iio/dac/ad3552r-hs.h b/drivers/iio/dac/ad3552r-hs.h
+index 724261d38dea3..4a9e352341244 100644
+--- a/drivers/iio/dac/ad3552r-hs.h
++++ b/drivers/iio/dac/ad3552r-hs.h
+@@ -8,11 +8,19 @@
+
+ struct iio_backend;
+
++enum ad3552r_io_mode {
++ AD3552R_IO_MODE_SPI,
++ AD3552R_IO_MODE_DSPI,
++ AD3552R_IO_MODE_QSPI,
++};
++
+ struct ad3552r_hs_platform_data {
+ int (*bus_reg_read)(struct iio_backend *back, u32 reg, u32 *val,
+ size_t data_size);
+ int (*bus_reg_write)(struct iio_backend *back, u32 reg, u32 val,
+ size_t data_size);
++ int (*bus_set_io_mode)(struct iio_backend *back,
++ enum ad3552r_io_mode mode);
+ u32 bus_sample_data_clock_hz;
+ };
+
+diff --git a/drivers/iio/dac/adi-axi-dac.c b/drivers/iio/dac/adi-axi-dac.c
+index ac871deb8063c..bcaf365feef42 100644
+--- a/drivers/iio/dac/adi-axi-dac.c
++++ b/drivers/iio/dac/adi-axi-dac.c
+@@ -64,7 +64,7 @@
+ #define AXI_DAC_UI_STATUS_IF_BUSY BIT(4)
+ #define AXI_DAC_CUSTOM_CTRL_REG 0x008C
+ #define AXI_DAC_CUSTOM_CTRL_ADDRESS GENMASK(31, 24)
+-#define AXI_DAC_CUSTOM_CTRL_SYNCED_TRANSFER BIT(2)
++#define AXI_DAC_CUSTOM_CTRL_MULTI_IO_MODE GENMASK(3, 2)
+ #define AXI_DAC_CUSTOM_CTRL_STREAM BIT(1)
+ #define AXI_DAC_CUSTOM_CTRL_TRANSFER_DATA BIT(0)
+
+@@ -722,6 +722,25 @@ static int axi_dac_bus_reg_read(struct iio_backend *back, u32 reg, u32 *val,
+ return regmap_read(st->regmap, AXI_DAC_CUSTOM_RD_REG, val);
+ }
+
++static int axi_dac_bus_set_io_mode(struct iio_backend *back,
++ enum ad3552r_io_mode mode)
++{
++ struct axi_dac_state *st = iio_backend_get_priv(back);
++ int ival, ret;
++
++ guard(mutex)(&st->lock);
++
++ ret = regmap_update_bits(st->regmap, AXI_DAC_CUSTOM_CTRL_REG,
++ AXI_DAC_CUSTOM_CTRL_MULTI_IO_MODE,
++ FIELD_PREP(AXI_DAC_CUSTOM_CTRL_MULTI_IO_MODE, mode));
++ if (ret)
++ return ret;
++
++ return regmap_read_poll_timeout(st->regmap, AXI_DAC_UI_STATUS_REG, ival,
++ FIELD_GET(AXI_DAC_UI_STATUS_IF_BUSY, ival) == 0, 10,
++ 100 * KILO);
++}
++
+ static void axi_dac_child_remove(void *data)
+ {
+ platform_device_unregister(data);
+@@ -733,6 +752,7 @@ static int axi_dac_create_platform_device(struct axi_dac_state *st,
+ struct ad3552r_hs_platform_data pdata = {
+ .bus_reg_read = axi_dac_bus_reg_read,
+ .bus_reg_write = axi_dac_bus_reg_write,
++ .bus_set_io_mode = axi_dac_bus_set_io_mode,
+ .bus_sample_data_clock_hz = st->dac_clk_rate,
+ };
+ struct platform_device_info pi = {
+--
+2.39.5
+
--- /dev/null
+From deae26664c4513427f1b49498292946c879f0cbb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 6 Apr 2025 22:01:44 +0200
+Subject: iio: imu: st_lsm6dsx: Fix wakeup source leaks on device unbind
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+[ Upstream commit 4551383e78d59b34eea3f4ed28ad22df99e25d59 ]
+
+Device can be unbound, so driver must also release memory for the wakeup
+source.
+
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Acked-by: Lorenzo Bianconi <lorenzo@kernel.org>
+Link: https://patch.msgid.link/20250406-b4-device-wakeup-leak-iio-v1-3-2d7d322a4a93@linaro.org
+Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
+index 4fdcc2acc94ed..96c6106b95eef 100644
+--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
++++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
+@@ -2719,8 +2719,11 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,
+ }
+
+ if (device_property_read_bool(dev, "wakeup-source") ||
+- (pdata && pdata->wakeup_source))
+- device_init_wakeup(dev, true);
++ (pdata && pdata->wakeup_source)) {
++ err = devm_device_init_wakeup(dev);
++ if (err)
++ return dev_err_probe(dev, err, "Failed to init wakeup\n");
++ }
+
+ return 0;
+ }
+--
+2.39.5
+
--- /dev/null
+From ddb28b4a931fda69cb118d64a04906e00607f394 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Mar 2025 11:09:11 -0500
+Subject: ima: process_measurement() needlessly takes inode_lock() on MAY_READ
+
+From: Frederick Lawler <fred@cloudflare.com>
+
+[ Upstream commit 30d68cb0c37ebe2dc63aa1d46a28b9163e61caa2 ]
+
+On IMA policy update, if a measure rule exists in the policy,
+IMA_MEASURE is set for ima_policy_flags which makes the violation_check
+variable always true. Coupled with a no-action on MAY_READ for a
+FILE_CHECK call, we're always taking the inode_lock().
+
+This becomes a performance problem for extremely heavy read-only workloads.
+Therefore, prevent this only in the case there's no action to be taken.
+
+Signed-off-by: Frederick Lawler <fred@cloudflare.com>
+Acked-by: Roberto Sassu <roberto.sassu@huawei.com>
+Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ security/integrity/ima/ima_main.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
+index f3e7ac513db3f..f99ab1a3b0f09 100644
+--- a/security/integrity/ima/ima_main.c
++++ b/security/integrity/ima/ima_main.c
+@@ -245,7 +245,9 @@ static int process_measurement(struct file *file, const struct cred *cred,
+ &allowed_algos);
+ violation_check = ((func == FILE_CHECK || func == MMAP_CHECK ||
+ func == MMAP_CHECK_REQPROT) &&
+- (ima_policy_flag & IMA_MEASURE));
++ (ima_policy_flag & IMA_MEASURE) &&
++ ((action & IMA_MEASURE) ||
++ (file->f_mode & FMODE_WRITE)));
+ if (!action && !violation_check)
+ return 0;
+
+--
+2.39.5
+
--- /dev/null
+From e676d0fbc28bcbf9345cc2861dba49d9b421f6b0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 31 Mar 2025 13:56:08 +0100
+Subject: intel_th: avoid using deprecated page->mapping, index fields
+
+From: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
+
+[ Upstream commit 8e553520596bbd5ce832e26e9d721e6a0c797b8b ]
+
+The struct page->mapping, index fields are deprecated and soon to be only
+available as part of a folio.
+
+It is likely the intel_th code which sets page->mapping, index is was
+implemented out of concern that some aspect of the page fault logic may
+encounter unexpected problems should they not.
+
+However, the appropriate interface for inserting kernel-allocated memory is
+vm_insert_page() in a VM_MIXEDMAP. By using the helper function
+vmf_insert_mixed() we can do this with minimal churn in the existing fault
+handler.
+
+By doing so, we bypass the remainder of the faulting logic. The pages are
+still pinned so there is no possibility of anything unexpected being done
+with the pages once established.
+
+It would also be reasonable to pre-map everything on fault, however to
+minimise churn we retain the fault handler.
+
+We also eliminate all code which clears page->mapping on teardown as this
+has now become unnecessary.
+
+The MSU code relies on faulting to function correctly, so is by definition
+dependent on CONFIG_MMU. We avoid spurious reports about compilation
+failure for unsupported platforms by making this requirement explicit in
+Kconfig as part of this change too.
+
+Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
+Acked-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
+Link: https://lore.kernel.org/r/20250331125608.60300-1-lorenzo.stoakes@oracle.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwtracing/intel_th/Kconfig | 1 +
+ drivers/hwtracing/intel_th/msu.c | 31 +++++++-----------------------
+ 2 files changed, 8 insertions(+), 24 deletions(-)
+
+diff --git a/drivers/hwtracing/intel_th/Kconfig b/drivers/hwtracing/intel_th/Kconfig
+index 4b6359326ede9..4f7d2b6d79e29 100644
+--- a/drivers/hwtracing/intel_th/Kconfig
++++ b/drivers/hwtracing/intel_th/Kconfig
+@@ -60,6 +60,7 @@ config INTEL_TH_STH
+
+ config INTEL_TH_MSU
+ tristate "Intel(R) Trace Hub Memory Storage Unit"
++ depends on MMU
+ help
+ Memory Storage Unit (MSU) trace output device enables
+ storing STP traces to system memory. It supports single
+diff --git a/drivers/hwtracing/intel_th/msu.c b/drivers/hwtracing/intel_th/msu.c
+index bf99d79a41920..7163950eb3719 100644
+--- a/drivers/hwtracing/intel_th/msu.c
++++ b/drivers/hwtracing/intel_th/msu.c
+@@ -19,6 +19,7 @@
+ #include <linux/io.h>
+ #include <linux/workqueue.h>
+ #include <linux/dma-mapping.h>
++#include <linux/pfn_t.h>
+
+ #ifdef CONFIG_X86
+ #include <asm/set_memory.h>
+@@ -976,7 +977,6 @@ static void msc_buffer_contig_free(struct msc *msc)
+ for (off = 0; off < msc->nr_pages << PAGE_SHIFT; off += PAGE_SIZE) {
+ struct page *page = virt_to_page(msc->base + off);
+
+- page->mapping = NULL;
+ __free_page(page);
+ }
+
+@@ -1158,9 +1158,6 @@ static void __msc_buffer_win_free(struct msc *msc, struct msc_window *win)
+ int i;
+
+ for_each_sg(win->sgt->sgl, sg, win->nr_segs, i) {
+- struct page *page = msc_sg_page(sg);
+-
+- page->mapping = NULL;
+ dma_free_coherent(msc_dev(win->msc)->parent->parent, PAGE_SIZE,
+ sg_virt(sg), sg_dma_address(sg));
+ }
+@@ -1601,22 +1598,10 @@ static void msc_mmap_close(struct vm_area_struct *vma)
+ {
+ struct msc_iter *iter = vma->vm_file->private_data;
+ struct msc *msc = iter->msc;
+- unsigned long pg;
+
+ if (!atomic_dec_and_mutex_lock(&msc->mmap_count, &msc->buf_mutex))
+ return;
+
+- /* drop page _refcounts */
+- for (pg = 0; pg < msc->nr_pages; pg++) {
+- struct page *page = msc_buffer_get_page(msc, pg);
+-
+- if (WARN_ON_ONCE(!page))
+- continue;
+-
+- if (page->mapping)
+- page->mapping = NULL;
+- }
+-
+ /* last mapping -- drop user_count */
+ atomic_dec(&msc->user_count);
+ mutex_unlock(&msc->buf_mutex);
+@@ -1626,16 +1611,14 @@ static vm_fault_t msc_mmap_fault(struct vm_fault *vmf)
+ {
+ struct msc_iter *iter = vmf->vma->vm_file->private_data;
+ struct msc *msc = iter->msc;
++ struct page *page;
+
+- vmf->page = msc_buffer_get_page(msc, vmf->pgoff);
+- if (!vmf->page)
++ page = msc_buffer_get_page(msc, vmf->pgoff);
++ if (!page)
+ return VM_FAULT_SIGBUS;
+
+- get_page(vmf->page);
+- vmf->page->mapping = vmf->vma->vm_file->f_mapping;
+- vmf->page->index = vmf->pgoff;
+-
+- return 0;
++ get_page(page);
++ return vmf_insert_mixed(vmf->vma, vmf->address, page_to_pfn_t(page));
+ }
+
+ static const struct vm_operations_struct msc_mmap_ops = {
+@@ -1676,7 +1659,7 @@ static int intel_th_msc_mmap(struct file *file, struct vm_area_struct *vma)
+ atomic_dec(&msc->user_count);
+
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+- vm_flags_set(vma, VM_DONTEXPAND | VM_DONTCOPY);
++ vm_flags_set(vma, VM_DONTEXPAND | VM_DONTCOPY | VM_MIXEDMAP);
+ vma->vm_ops = &msc_mmap_ops;
+ return ret;
+ }
+--
+2.39.5
+
--- /dev/null
+From 90d0369ec220ea01b91615470def997e9bd7365d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 24 Apr 2025 12:28:39 +0100
+Subject: io_uring: don't duplicate flushing in io_req_post_cqe
+
+From: Pavel Begunkov <asml.silence@gmail.com>
+
+[ Upstream commit 5e16f1a68d28965c12b6fa227a306fef8a680f84 ]
+
+io_req_post_cqe() sets submit_state.cq_flush so that
+*flush_completions() can take care of batch commiting CQEs. Don't commit
+it twice by using __io_cq_unlock_post().
+
+Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
+Link: https://lore.kernel.org/r/41c416660c509cee676b6cad96081274bcb459f3.1745493861.git.asml.silence@gmail.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ io_uring/io_uring.c | 11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c
+index a60cb9d30cc0d..f1c09e2b53022 100644
+--- a/io_uring/io_uring.c
++++ b/io_uring/io_uring.c
+@@ -864,10 +864,15 @@ bool io_req_post_cqe(struct io_kiocb *req, s32 res, u32 cflags)
+ lockdep_assert(!io_wq_current_is_worker());
+ lockdep_assert_held(&ctx->uring_lock);
+
+- __io_cq_lock(ctx);
+- posted = io_fill_cqe_aux(ctx, req->cqe.user_data, res, cflags);
++ if (!ctx->lockless_cq) {
++ spin_lock(&ctx->completion_lock);
++ posted = io_fill_cqe_aux(ctx, req->cqe.user_data, res, cflags);
++ spin_unlock(&ctx->completion_lock);
++ } else {
++ posted = io_fill_cqe_aux(ctx, req->cqe.user_data, res, cflags);
++ }
++
+ ctx->submit_state.cq_flush = true;
+- __io_cq_unlock_post(ctx);
+ return posted;
+ }
+
+--
+2.39.5
+
--- /dev/null
+From a75e5e6e30dd8aedd05fceab66537f8f61188c27 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 30 Apr 2025 07:17:17 -0600
+Subject: io_uring/fdinfo: annotate racy sq/cq head/tail reads
+
+From: Jens Axboe <axboe@kernel.dk>
+
+[ Upstream commit f024d3a8ded0d8d2129ae123d7a5305c29ca44ce ]
+
+syzbot complains about the cached sq head read, and it's totally right.
+But we don't need to care, it's just reading fdinfo, and reading the
+CQ or SQ tail/head entries are known racy in that they are just a view
+into that very instant and may of course be outdated by the time they
+are reported.
+
+Annotate both the SQ head and CQ tail read with data_race() to avoid
+this syzbot complaint.
+
+Link: https://lore.kernel.org/io-uring/6811f6dc.050a0220.39e3a1.0d0e.GAE@google.com/
+Reported-by: syzbot+3e77fd302e99f5af9394@syzkaller.appspotmail.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ io_uring/fdinfo.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/io_uring/fdinfo.c b/io_uring/fdinfo.c
+index 336aec7ea8c29..e0d6a59a89fa1 100644
+--- a/io_uring/fdinfo.c
++++ b/io_uring/fdinfo.c
+@@ -117,11 +117,11 @@ static void __io_uring_show_fdinfo(struct io_ring_ctx *ctx, struct seq_file *m)
+ seq_printf(m, "SqMask:\t0x%x\n", sq_mask);
+ seq_printf(m, "SqHead:\t%u\n", sq_head);
+ seq_printf(m, "SqTail:\t%u\n", sq_tail);
+- seq_printf(m, "CachedSqHead:\t%u\n", ctx->cached_sq_head);
++ seq_printf(m, "CachedSqHead:\t%u\n", data_race(ctx->cached_sq_head));
+ seq_printf(m, "CqMask:\t0x%x\n", cq_mask);
+ seq_printf(m, "CqHead:\t%u\n", cq_head);
+ seq_printf(m, "CqTail:\t%u\n", cq_tail);
+- seq_printf(m, "CachedCqTail:\t%u\n", ctx->cached_cq_tail);
++ seq_printf(m, "CachedCqTail:\t%u\n", data_race(ctx->cached_cq_tail));
+ seq_printf(m, "SQEs:\t%u\n", sq_tail - sq_head);
+ sq_entries = min(sq_tail - sq_head, ctx->sq_entries);
+ for (i = 0; i < sq_entries; i++) {
+--
+2.39.5
+
--- /dev/null
+From 036b5f25ab2930091c39768a5c19dda0cbc63a50 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 28 Mar 2025 23:11:50 +0000
+Subject: io_uring/msg: initialise msg request opcode
+
+From: Pavel Begunkov <asml.silence@gmail.com>
+
+[ Upstream commit 9cc0bbdaba2a66ad90bc6ce45163b7745baffe98 ]
+
+It's risky to have msg request opcode set to garbage, so at least
+initialise it to nop. Later we might want to add a user inaccessible
+opcode for such cases.
+
+Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
+Link: https://lore.kernel.org/r/9afe650fcb348414a4529d89f52eb8969ba06efd.1743190078.git.asml.silence@gmail.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ io_uring/msg_ring.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/io_uring/msg_ring.c b/io_uring/msg_ring.c
+index 7e6f68e911f10..f844ab24cda42 100644
+--- a/io_uring/msg_ring.c
++++ b/io_uring/msg_ring.c
+@@ -93,6 +93,7 @@ static int io_msg_remote_post(struct io_ring_ctx *ctx, struct io_kiocb *req,
+ kmem_cache_free(req_cachep, req);
+ return -EOWNERDEAD;
+ }
++ req->opcode = IORING_OP_NOP;
+ req->cqe.user_data = user_data;
+ io_req_set_res(req, res, cflags);
+ percpu_ref_get(&ctx->refs);
+--
+2.39.5
+
--- /dev/null
+From cf671bbaae9d5538cbc2ec16637900218e31bf46 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jan 2025 17:31:03 +0000
+Subject: io_uring: sanitise ring params earlier
+
+From: Pavel Begunkov <asml.silence@gmail.com>
+
+[ Upstream commit 92a3bac9a57c39728226ab191859c85f5e2829c0 ]
+
+Do all struct io_uring_params validation early on before allocating the
+context. That makes initialisation easier, especially by having fewer
+places where we need to care about partial de-initialisation.
+
+Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
+Link: https://lore.kernel.org/r/363ba90b83ff78eefdc88b60e1b2c4a39d182247.1738344646.git.asml.silence@gmail.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ io_uring/io_uring.c | 77 ++++++++++++++++++++++++++-------------------
+ 1 file changed, 44 insertions(+), 33 deletions(-)
+
+diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c
+index 56f10cce8f009..52c9fa6c06450 100644
+--- a/io_uring/io_uring.c
++++ b/io_uring/io_uring.c
+@@ -3532,6 +3532,44 @@ static struct file *io_uring_get_file(struct io_ring_ctx *ctx)
+ O_RDWR | O_CLOEXEC, NULL);
+ }
+
++static int io_uring_sanitise_params(struct io_uring_params *p)
++{
++ unsigned flags = p->flags;
++
++ /* There is no way to mmap rings without a real fd */
++ if ((flags & IORING_SETUP_REGISTERED_FD_ONLY) &&
++ !(flags & IORING_SETUP_NO_MMAP))
++ return -EINVAL;
++
++ if (flags & IORING_SETUP_SQPOLL) {
++ /* IPI related flags don't make sense with SQPOLL */
++ if (flags & (IORING_SETUP_COOP_TASKRUN |
++ IORING_SETUP_TASKRUN_FLAG |
++ IORING_SETUP_DEFER_TASKRUN))
++ return -EINVAL;
++ }
++
++ if (flags & IORING_SETUP_TASKRUN_FLAG) {
++ if (!(flags & (IORING_SETUP_COOP_TASKRUN |
++ IORING_SETUP_DEFER_TASKRUN)))
++ return -EINVAL;
++ }
++
++ /* HYBRID_IOPOLL only valid with IOPOLL */
++ if ((flags & IORING_SETUP_HYBRID_IOPOLL) && !(flags & IORING_SETUP_IOPOLL))
++ return -EINVAL;
++
++ /*
++ * For DEFER_TASKRUN we require the completion task to be the same as
++ * the submission task. This implies that there is only one submitter.
++ */
++ if ((flags & IORING_SETUP_DEFER_TASKRUN) &&
++ !(flags & IORING_SETUP_SINGLE_ISSUER))
++ return -EINVAL;
++
++ return 0;
++}
++
+ int io_uring_fill_params(unsigned entries, struct io_uring_params *p)
+ {
+ if (!entries)
+@@ -3542,10 +3580,6 @@ int io_uring_fill_params(unsigned entries, struct io_uring_params *p)
+ entries = IORING_MAX_ENTRIES;
+ }
+
+- if ((p->flags & IORING_SETUP_REGISTERED_FD_ONLY)
+- && !(p->flags & IORING_SETUP_NO_MMAP))
+- return -EINVAL;
+-
+ /*
+ * Use twice as many entries for the CQ ring. It's possible for the
+ * application to drive a higher depth than the size of the SQ ring,
+@@ -3607,6 +3641,10 @@ static __cold int io_uring_create(unsigned entries, struct io_uring_params *p,
+ struct file *file;
+ int ret;
+
++ ret = io_uring_sanitise_params(p);
++ if (ret)
++ return ret;
++
+ ret = io_uring_fill_params(entries, p);
+ if (unlikely(ret))
+ return ret;
+@@ -3654,37 +3692,10 @@ static __cold int io_uring_create(unsigned entries, struct io_uring_params *p,
+ * For SQPOLL, we just need a wakeup, always. For !SQPOLL, if
+ * COOP_TASKRUN is set, then IPIs are never needed by the app.
+ */
+- ret = -EINVAL;
+- if (ctx->flags & IORING_SETUP_SQPOLL) {
+- /* IPI related flags don't make sense with SQPOLL */
+- if (ctx->flags & (IORING_SETUP_COOP_TASKRUN |
+- IORING_SETUP_TASKRUN_FLAG |
+- IORING_SETUP_DEFER_TASKRUN))
+- goto err;
++ if (ctx->flags & (IORING_SETUP_SQPOLL|IORING_SETUP_COOP_TASKRUN))
+ ctx->notify_method = TWA_SIGNAL_NO_IPI;
+- } else if (ctx->flags & IORING_SETUP_COOP_TASKRUN) {
+- ctx->notify_method = TWA_SIGNAL_NO_IPI;
+- } else {
+- if (ctx->flags & IORING_SETUP_TASKRUN_FLAG &&
+- !(ctx->flags & IORING_SETUP_DEFER_TASKRUN))
+- goto err;
++ else
+ ctx->notify_method = TWA_SIGNAL;
+- }
+-
+- /* HYBRID_IOPOLL only valid with IOPOLL */
+- if ((ctx->flags & (IORING_SETUP_IOPOLL|IORING_SETUP_HYBRID_IOPOLL)) ==
+- IORING_SETUP_HYBRID_IOPOLL)
+- goto err;
+-
+- /*
+- * For DEFER_TASKRUN we require the completion task to be the same as the
+- * submission task. This implies that there is only one submitter, so enforce
+- * that.
+- */
+- if (ctx->flags & IORING_SETUP_DEFER_TASKRUN &&
+- !(ctx->flags & IORING_SETUP_SINGLE_ISSUER)) {
+- goto err;
+- }
+
+ /*
+ * This is just grabbed for accounting purposes. When a process exits,
+--
+2.39.5
+
--- /dev/null
+From 6b3a204289e84403d44c8f401cd97522f6f18040 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Feb 2025 13:19:56 -0700
+Subject: io_uring: use IO_REQ_LINK_FLAGS more
+
+From: Caleb Sander Mateos <csander@purestorage.com>
+
+[ Upstream commit 0e8934724f78602635d6e11c97ef48caa693cb65 ]
+
+Replace the 2 instances of REQ_F_LINK | REQ_F_HARDLINK with
+the more commonly used IO_REQ_LINK_FLAGS.
+
+Signed-off-by: Caleb Sander Mateos <csander@purestorage.com>
+Link: https://lore.kernel.org/r/20250211202002.3316324-1-csander@purestorage.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ io_uring/io_uring.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c
+index f1c09e2b53022..56f10cce8f009 100644
+--- a/io_uring/io_uring.c
++++ b/io_uring/io_uring.c
+@@ -110,11 +110,13 @@
+ #define SQE_VALID_FLAGS (SQE_COMMON_FLAGS | IOSQE_BUFFER_SELECT | \
+ IOSQE_IO_DRAIN | IOSQE_CQE_SKIP_SUCCESS)
+
++#define IO_REQ_LINK_FLAGS (REQ_F_LINK | REQ_F_HARDLINK)
++
+ #define IO_REQ_CLEAN_FLAGS (REQ_F_BUFFER_SELECTED | REQ_F_NEED_CLEANUP | \
+ REQ_F_POLLED | REQ_F_INFLIGHT | REQ_F_CREDS | \
+ REQ_F_ASYNC_DATA)
+
+-#define IO_REQ_CLEAN_SLOW_FLAGS (REQ_F_REFCOUNT | REQ_F_LINK | REQ_F_HARDLINK |\
++#define IO_REQ_CLEAN_SLOW_FLAGS (REQ_F_REFCOUNT | IO_REQ_LINK_FLAGS | \
+ REQ_F_REISSUE | IO_REQ_CLEAN_FLAGS)
+
+ #define IO_TCTX_REFS_CACHE_NR (1U << 10)
+@@ -131,7 +133,6 @@ struct io_defer_entry {
+
+ /* requests with any of those set should undergo io_disarm_next() */
+ #define IO_DISARM_MASK (REQ_F_ARM_LTIMEOUT | REQ_F_LINK_TIMEOUT | REQ_F_FAIL)
+-#define IO_REQ_LINK_FLAGS (REQ_F_LINK | REQ_F_HARDLINK)
+
+ /*
+ * No waiters. It's larger than any valid value of the tw counter
+@@ -1150,7 +1151,7 @@ static inline void io_req_local_work_add(struct io_kiocb *req,
+ * We don't know how many reuqests is there in the link and whether
+ * they can even be queued lazily, fall back to non-lazy.
+ */
+- if (req->flags & (REQ_F_LINK | REQ_F_HARDLINK))
++ if (req->flags & IO_REQ_LINK_FLAGS)
+ flags &= ~IOU_F_TWQ_LAZY_WAKE;
+
+ guard(rcu)();
+--
+2.39.5
+
--- /dev/null
+From ebbd348df2c360fc757dc11d03001105666baa73 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Feb 2025 16:23:16 +0000
+Subject: iommu/amd/pgtbl_v2: Improve error handling
+
+From: Vasant Hegde <vasant.hegde@amd.com>
+
+[ Upstream commit 36a1cfd497435ba5e37572fe9463bb62a7b1b984 ]
+
+Return -ENOMEM if v2_alloc_pte() fails to allocate memory.
+
+Signed-off-by: Vasant Hegde <vasant.hegde@amd.com>
+Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
+Link: https://lore.kernel.org/r/20250227162320.5805-4-vasant.hegde@amd.com
+Signed-off-by: Joerg Roedel <jroedel@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iommu/amd/io_pgtable_v2.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/iommu/amd/io_pgtable_v2.c b/drivers/iommu/amd/io_pgtable_v2.c
+index c616de2c5926e..a56a273963059 100644
+--- a/drivers/iommu/amd/io_pgtable_v2.c
++++ b/drivers/iommu/amd/io_pgtable_v2.c
+@@ -254,7 +254,7 @@ static int iommu_v2_map_pages(struct io_pgtable_ops *ops, unsigned long iova,
+ pte = v2_alloc_pte(cfg->amd.nid, pgtable->pgd,
+ iova, map_size, gfp, &updated);
+ if (!pte) {
+- ret = -EINVAL;
++ ret = -ENOMEM;
+ goto out;
+ }
+
+--
+2.39.5
+
--- /dev/null
+From 20596372b0be4b954fd3c272d0575b84e588ad52 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 28 Feb 2025 15:46:32 +0000
+Subject: iommu: Keep dev->iommu state consistent
+
+From: Robin Murphy <robin.murphy@arm.com>
+
+[ Upstream commit 3832862eb9c4dfa0e80b2522bfaedbc8a43de97d ]
+
+At the moment, if of_iommu_configure() allocates dev->iommu itself via
+iommu_fwspec_init(), then suffers a DT parsing failure, it cleans up the
+fwspec but leaves the empty dev_iommu hanging around. So far this is
+benign (if a tiny bit wasteful), but we'd like to be able to reason
+about dev->iommu having a consistent and unambiguous lifecycle. Thus
+make sure that the of_iommu cleanup undoes precisely whatever it did.
+
+Signed-off-by: Robin Murphy <robin.murphy@arm.com>
+Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
+Link: https://lore.kernel.org/r/d219663a3f23001f23d520a883ac622d70b4e642.1740753261.git.robin.murphy@arm.com
+Signed-off-by: Joerg Roedel <jroedel@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iommu/iommu-priv.h | 2 ++
+ drivers/iommu/iommu.c | 2 +-
+ drivers/iommu/of_iommu.c | 6 +++++-
+ 3 files changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/iommu/iommu-priv.h b/drivers/iommu/iommu-priv.h
+index de5b54eaa8bf1..a5913c0b02a0a 100644
+--- a/drivers/iommu/iommu-priv.h
++++ b/drivers/iommu/iommu-priv.h
+@@ -17,6 +17,8 @@ static inline const struct iommu_ops *dev_iommu_ops(struct device *dev)
+ return dev->iommu->iommu_dev->ops;
+ }
+
++void dev_iommu_free(struct device *dev);
++
+ const struct iommu_ops *iommu_ops_from_fwnode(const struct fwnode_handle *fwnode);
+
+ static inline const struct iommu_ops *iommu_fwspec_ops(struct iommu_fwspec *fwspec)
+diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
+index 1efe7cddb4fe3..3a2804a98203b 100644
+--- a/drivers/iommu/iommu.c
++++ b/drivers/iommu/iommu.c
+@@ -352,7 +352,7 @@ static struct dev_iommu *dev_iommu_get(struct device *dev)
+ return param;
+ }
+
+-static void dev_iommu_free(struct device *dev)
++void dev_iommu_free(struct device *dev)
+ {
+ struct dev_iommu *param = dev->iommu;
+
+diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
+index 97987cd78da93..e10a68b5ffde1 100644
+--- a/drivers/iommu/of_iommu.c
++++ b/drivers/iommu/of_iommu.c
+@@ -116,6 +116,7 @@ static void of_pci_check_device_ats(struct device *dev, struct device_node *np)
+ int of_iommu_configure(struct device *dev, struct device_node *master_np,
+ const u32 *id)
+ {
++ bool dev_iommu_present;
+ int err;
+
+ if (!master_np)
+@@ -127,6 +128,7 @@ int of_iommu_configure(struct device *dev, struct device_node *master_np,
+ mutex_unlock(&iommu_probe_device_lock);
+ return 0;
+ }
++ dev_iommu_present = dev->iommu;
+
+ /*
+ * We don't currently walk up the tree looking for a parent IOMMU.
+@@ -147,8 +149,10 @@ int of_iommu_configure(struct device *dev, struct device_node *master_np,
+ err = of_iommu_configure_device(master_np, dev, id);
+ }
+
+- if (err)
++ if (err && dev_iommu_present)
+ iommu_fwspec_free(dev);
++ else if (err && dev->iommu)
++ dev_iommu_free(dev);
+ mutex_unlock(&iommu_probe_device_lock);
+
+ if (!err && dev->bus)
+--
+2.39.5
+
--- /dev/null
+From 5004c54191c5fa7cae8938d9e8b04e18c32c22b5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 10 Mar 2025 10:47:46 +0800
+Subject: iommu/vt-d: Check if SVA is supported when attaching the SVA domain
+
+From: Jason Gunthorpe <jgg@nvidia.com>
+
+[ Upstream commit 607ba1bb096110751f6aa4b46666e0ba024ab3c2 ]
+
+Attach of a SVA domain should fail if SVA is not supported, move the check
+for SVA support out of IOMMU_DEV_FEAT_SVA and into attach.
+
+Also check when allocating a SVA domain to match other drivers.
+
+Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
+Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
+Reviewed-by: Kevin Tian <kevin.tian@intel.com>
+Reviewed-by: Yi Liu <yi.l.liu@intel.com>
+Tested-by: Zhangfei Gao <zhangfei.gao@linaro.org>
+Link: https://lore.kernel.org/r/20250228092631.3425464-3-baolu.lu@linux.intel.com
+Signed-off-by: Joerg Roedel <jroedel@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iommu/intel/iommu.c | 37 +------------------------------
+ drivers/iommu/intel/svm.c | 43 +++++++++++++++++++++++++++++++++++++
+ 2 files changed, 44 insertions(+), 36 deletions(-)
+
+diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
+index 7c863c41c8645..6da09345398d9 100644
+--- a/drivers/iommu/intel/iommu.c
++++ b/drivers/iommu/intel/iommu.c
+@@ -3869,41 +3869,6 @@ static struct iommu_group *intel_iommu_device_group(struct device *dev)
+ return generic_device_group(dev);
+ }
+
+-static int intel_iommu_enable_sva(struct device *dev)
+-{
+- struct device_domain_info *info = dev_iommu_priv_get(dev);
+- struct intel_iommu *iommu;
+-
+- if (!info || dmar_disabled)
+- return -EINVAL;
+-
+- iommu = info->iommu;
+- if (!iommu)
+- return -EINVAL;
+-
+- if (!(iommu->flags & VTD_FLAG_SVM_CAPABLE))
+- return -ENODEV;
+-
+- if (!info->pasid_enabled || !info->ats_enabled)
+- return -EINVAL;
+-
+- /*
+- * Devices having device-specific I/O fault handling should not
+- * support PCI/PRI. The IOMMU side has no means to check the
+- * capability of device-specific IOPF. Therefore, IOMMU can only
+- * default that if the device driver enables SVA on a non-PRI
+- * device, it will handle IOPF in its own way.
+- */
+- if (!info->pri_supported)
+- return 0;
+-
+- /* Devices supporting PRI should have it enabled. */
+- if (!info->pri_enabled)
+- return -EINVAL;
+-
+- return 0;
+-}
+-
+ static int context_flip_pri(struct device_domain_info *info, bool enable)
+ {
+ struct intel_iommu *iommu = info->iommu;
+@@ -4024,7 +3989,7 @@ intel_iommu_dev_enable_feat(struct device *dev, enum iommu_dev_features feat)
+ return intel_iommu_enable_iopf(dev);
+
+ case IOMMU_DEV_FEAT_SVA:
+- return intel_iommu_enable_sva(dev);
++ return 0;
+
+ default:
+ return -ENODEV;
+diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
+index f5569347591f2..ba93123cb4eba 100644
+--- a/drivers/iommu/intel/svm.c
++++ b/drivers/iommu/intel/svm.c
+@@ -110,6 +110,41 @@ static const struct mmu_notifier_ops intel_mmuops = {
+ .free_notifier = intel_mm_free_notifier,
+ };
+
++static int intel_iommu_sva_supported(struct device *dev)
++{
++ struct device_domain_info *info = dev_iommu_priv_get(dev);
++ struct intel_iommu *iommu;
++
++ if (!info || dmar_disabled)
++ return -EINVAL;
++
++ iommu = info->iommu;
++ if (!iommu)
++ return -EINVAL;
++
++ if (!(iommu->flags & VTD_FLAG_SVM_CAPABLE))
++ return -ENODEV;
++
++ if (!info->pasid_enabled || !info->ats_enabled)
++ return -EINVAL;
++
++ /*
++ * Devices having device-specific I/O fault handling should not
++ * support PCI/PRI. The IOMMU side has no means to check the
++ * capability of device-specific IOPF. Therefore, IOMMU can only
++ * default that if the device driver enables SVA on a non-PRI
++ * device, it will handle IOPF in its own way.
++ */
++ if (!info->pri_supported)
++ return 0;
++
++ /* Devices supporting PRI should have it enabled. */
++ if (!info->pri_enabled)
++ return -EINVAL;
++
++ return 0;
++}
++
+ static int intel_svm_set_dev_pasid(struct iommu_domain *domain,
+ struct device *dev, ioasid_t pasid,
+ struct iommu_domain *old)
+@@ -121,6 +156,10 @@ static int intel_svm_set_dev_pasid(struct iommu_domain *domain,
+ unsigned long sflags;
+ int ret = 0;
+
++ ret = intel_iommu_sva_supported(dev);
++ if (ret)
++ return ret;
++
+ dev_pasid = domain_add_dev_pasid(domain, dev, pasid);
+ if (IS_ERR(dev_pasid))
+ return PTR_ERR(dev_pasid);
+@@ -161,6 +200,10 @@ struct iommu_domain *intel_svm_domain_alloc(struct device *dev,
+ struct dmar_domain *domain;
+ int ret;
+
++ ret = intel_iommu_sva_supported(dev);
++ if (ret)
++ return ERR_PTR(ret);
++
+ domain = kzalloc(sizeof(*domain), GFP_KERNEL);
+ if (!domain)
+ return ERR_PTR(-ENOMEM);
+--
+2.39.5
+
--- /dev/null
+From d228a5cb0c72d3ffbf8da4fe02b063992afa0f54 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 10 Mar 2025 10:47:47 +0800
+Subject: iommu/vt-d: Move scalable mode ATS enablement to probe path
+
+From: Lu Baolu <baolu.lu@linux.intel.com>
+
+[ Upstream commit 5518f239aff1baf772c5748da3add7243c5fb5df ]
+
+Device ATS is currently enabled when a domain is attached to the device
+and disabled when the domain is detached. This creates a limitation:
+when the IOMMU is operating in scalable mode and IOPF is enabled, the
+device's domain cannot be changed.
+
+The previous code enables ATS when a domain is set to a device's RID and
+disables it during RID domain switch. So, if a PASID is set with a
+domain requiring PRI, ATS should remain enabled until the domain is
+removed. During the PASID domain's lifecycle, if the RID's domain
+changes, PRI will be disrupted because it depends on ATS, which is
+disabled when the blocking domain is set for the device's RID.
+
+Remove this limitation by moving ATS enablement to the device probe path.
+
+Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
+Reviewed-by: Kevin Tian <kevin.tian@intel.com>
+Tested-by: Zhangfei Gao <zhangfei.gao@linaro.org>
+Link: https://lore.kernel.org/r/20250228092631.3425464-5-baolu.lu@linux.intel.com
+Signed-off-by: Joerg Roedel <jroedel@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iommu/intel/iommu.c | 51 ++++++++++++++++++++-----------------
+ 1 file changed, 27 insertions(+), 24 deletions(-)
+
+diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
+index 07adf4ceeea06..7c863c41c8645 100644
+--- a/drivers/iommu/intel/iommu.c
++++ b/drivers/iommu/intel/iommu.c
+@@ -1172,32 +1172,28 @@ static bool dev_needs_extra_dtlb_flush(struct pci_dev *pdev)
+ return true;
+ }
+
+-static void iommu_enable_pci_caps(struct device_domain_info *info)
++static void iommu_enable_pci_ats(struct device_domain_info *info)
+ {
+ struct pci_dev *pdev;
+
+- if (!dev_is_pci(info->dev))
++ if (!info->ats_supported)
+ return;
+
+ pdev = to_pci_dev(info->dev);
+- if (info->ats_supported && pci_ats_page_aligned(pdev) &&
+- !pci_enable_ats(pdev, VTD_PAGE_SHIFT))
++ if (!pci_ats_page_aligned(pdev))
++ return;
++
++ if (!pci_enable_ats(pdev, VTD_PAGE_SHIFT))
+ info->ats_enabled = 1;
+ }
+
+-static void iommu_disable_pci_caps(struct device_domain_info *info)
++static void iommu_disable_pci_ats(struct device_domain_info *info)
+ {
+- struct pci_dev *pdev;
+-
+- if (!dev_is_pci(info->dev))
++ if (!info->ats_enabled)
+ return;
+
+- pdev = to_pci_dev(info->dev);
+-
+- if (info->ats_enabled) {
+- pci_disable_ats(pdev);
+- info->ats_enabled = 0;
+- }
++ pci_disable_ats(to_pci_dev(info->dev));
++ info->ats_enabled = 0;
+ }
+
+ static void intel_flush_iotlb_all(struct iommu_domain *domain)
+@@ -1556,12 +1552,19 @@ domain_context_mapping(struct dmar_domain *domain, struct device *dev)
+ struct device_domain_info *info = dev_iommu_priv_get(dev);
+ struct intel_iommu *iommu = info->iommu;
+ u8 bus = info->bus, devfn = info->devfn;
++ int ret;
+
+ if (!dev_is_pci(dev))
+ return domain_context_mapping_one(domain, iommu, bus, devfn);
+
+- return pci_for_each_dma_alias(to_pci_dev(dev),
+- domain_context_mapping_cb, domain);
++ ret = pci_for_each_dma_alias(to_pci_dev(dev),
++ domain_context_mapping_cb, domain);
++ if (ret)
++ return ret;
++
++ iommu_enable_pci_ats(info);
++
++ return 0;
+ }
+
+ /* Return largest possible superpage level for a given mapping */
+@@ -1843,8 +1846,6 @@ static int dmar_domain_attach_device(struct dmar_domain *domain,
+ if (ret)
+ goto out_block_translation;
+
+- iommu_enable_pci_caps(info);
+-
+ ret = cache_tag_assign_domain(domain, dev, IOMMU_NO_PASID);
+ if (ret)
+ goto out_block_translation;
+@@ -3210,6 +3211,7 @@ static void domain_context_clear(struct device_domain_info *info)
+
+ pci_for_each_dma_alias(to_pci_dev(info->dev),
+ &domain_context_clear_one_cb, info);
++ iommu_disable_pci_ats(info);
+ }
+
+ /*
+@@ -3226,7 +3228,6 @@ void device_block_translation(struct device *dev)
+ if (info->domain)
+ cache_tag_unassign_domain(info->domain, dev, IOMMU_NO_PASID);
+
+- iommu_disable_pci_caps(info);
+ if (!dev_is_real_dma_subdevice(dev)) {
+ if (sm_supported(iommu))
+ intel_pasid_tear_down_entry(iommu, dev,
+@@ -3761,6 +3762,9 @@ static struct iommu_device *intel_iommu_probe_device(struct device *dev)
+ !pci_enable_pasid(pdev, info->pasid_supported & ~1))
+ info->pasid_enabled = 1;
+
++ if (sm_supported(iommu))
++ iommu_enable_pci_ats(info);
++
+ return &iommu->iommu;
+ free_table:
+ intel_pasid_free_table(dev);
+@@ -3777,6 +3781,8 @@ static void intel_iommu_release_device(struct device *dev)
+ struct device_domain_info *info = dev_iommu_priv_get(dev);
+ struct intel_iommu *iommu = info->iommu;
+
++ iommu_disable_pci_ats(info);
++
+ if (info->pasid_enabled) {
+ pci_disable_pasid(to_pci_dev(dev));
+ info->pasid_enabled = 0;
+@@ -4415,13 +4421,10 @@ static int identity_domain_attach_dev(struct iommu_domain *domain, struct device
+ if (dev_is_real_dma_subdevice(dev))
+ return 0;
+
+- if (sm_supported(iommu)) {
++ if (sm_supported(iommu))
+ ret = intel_pasid_setup_pass_through(iommu, dev, IOMMU_NO_PASID);
+- if (!ret)
+- iommu_enable_pci_caps(info);
+- } else {
++ else
+ ret = device_setup_pass_through(dev);
+- }
+
+ return ret;
+ }
+--
+2.39.5
+
--- /dev/null
+From bc57a57f7b1053209ddd682e4344ce097b892890 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Feb 2025 02:40:12 -0800
+Subject: iommufd: Disallow allocating nested parent domain with fault ID
+
+From: Yi Liu <yi.l.liu@intel.com>
+
+[ Upstream commit 1062d81086156e42878d701b816d2f368b53a77c ]
+
+Allocating a domain with a fault ID indicates that the domain is faultable.
+However, there is a gap for the nested parent domain to support PRI. Some
+hardware lacks the capability to distinguish whether PRI occurs at stage 1
+or stage 2. This limitation may require software-based page table walking
+to resolve. Since no in-tree IOMMU driver currently supports this
+functionality, it is disallowed. For more details, refer to the related
+discussion at [1].
+
+[1] https://lore.kernel.org/linux-iommu/bd1655c6-8b2f-4cfa-adb1-badc00d01811@intel.com/
+
+Link: https://patch.msgid.link/r/20250226104012.82079-1-yi.l.liu@intel.com
+Suggested-by: Lu Baolu <baolu.lu@linux.intel.com>
+Signed-off-by: Yi Liu <yi.l.liu@intel.com>
+Reviewed-by: Kevin Tian <kevin.tian@intel.com>
+Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
+Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iommu/iommufd/hw_pagetable.c | 3 +++
+ tools/testing/selftests/iommu/iommufd.c | 4 ++++
+ 2 files changed, 7 insertions(+)
+
+diff --git a/drivers/iommu/iommufd/hw_pagetable.c b/drivers/iommu/iommufd/hw_pagetable.c
+index 598be26a14e28..9b5b0b8522299 100644
+--- a/drivers/iommu/iommufd/hw_pagetable.c
++++ b/drivers/iommu/iommufd/hw_pagetable.c
+@@ -126,6 +126,9 @@ iommufd_hwpt_paging_alloc(struct iommufd_ctx *ictx, struct iommufd_ioas *ioas,
+ if ((flags & IOMMU_HWPT_ALLOC_DIRTY_TRACKING) &&
+ !device_iommu_capable(idev->dev, IOMMU_CAP_DIRTY_TRACKING))
+ return ERR_PTR(-EOPNOTSUPP);
++ if ((flags & IOMMU_HWPT_FAULT_ID_VALID) &&
++ (flags & IOMMU_HWPT_ALLOC_NEST_PARENT))
++ return ERR_PTR(-EOPNOTSUPP);
+
+ hwpt_paging = __iommufd_object_alloc(
+ ictx, hwpt_paging, IOMMUFD_OBJ_HWPT_PAGING, common.obj);
+diff --git a/tools/testing/selftests/iommu/iommufd.c b/tools/testing/selftests/iommu/iommufd.c
+index a1b2b657999dc..618c03bb6509b 100644
+--- a/tools/testing/selftests/iommu/iommufd.c
++++ b/tools/testing/selftests/iommu/iommufd.c
+@@ -439,6 +439,10 @@ TEST_F(iommufd_ioas, alloc_hwpt_nested)
+ &test_hwpt_id);
+ test_err_hwpt_alloc(EINVAL, self->device_id, self->device_id, 0,
+ &test_hwpt_id);
++ test_err_hwpt_alloc(EOPNOTSUPP, self->device_id, self->ioas_id,
++ IOMMU_HWPT_ALLOC_NEST_PARENT |
++ IOMMU_HWPT_FAULT_ID_VALID,
++ &test_hwpt_id);
+
+ test_cmd_hwpt_alloc(self->device_id, self->ioas_id,
+ IOMMU_HWPT_ALLOC_NEST_PARENT,
+--
+2.39.5
+
--- /dev/null
+From b0629628aed174d8232bdcbec57bf441f9cdaf81 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 21 Mar 2025 11:01:42 -0700
+Subject: iommufd: Extend IOMMU_GET_HW_INFO to report PASID capability
+
+From: Yi Liu <yi.l.liu@intel.com>
+
+[ Upstream commit 803f97298e7de9242eb677a1351dcafbbcc9117e ]
+
+PASID usage requires PASID support in both device and IOMMU. Since the
+iommu drivers always enable the PASID capability for the device if it
+is supported, this extends the IOMMU_GET_HW_INFO to report the PASID
+capability to userspace. Also, enhances the selftest accordingly.
+
+Link: https://patch.msgid.link/r/20250321180143.8468-5-yi.l.liu@intel.com
+Cc: Bjorn Helgaas <bhelgaas@google.com>
+Reviewed-by: Kevin Tian <kevin.tian@intel.com>
+Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
+Tested-by: Zhangfei Gao <zhangfei.gao@linaro.org> #aarch64 platform
+Tested-by: Nicolin Chen <nicolinc@nvidia.com>
+Signed-off-by: Yi Liu <yi.l.liu@intel.com>
+Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iommu/iommufd/device.c | 34 +++++++++++++++++++++++++++++++++-
+ drivers/pci/ats.c | 33 +++++++++++++++++++++++++++++++++
+ include/linux/pci-ats.h | 3 +++
+ include/uapi/linux/iommufd.h | 14 +++++++++++++-
+ 4 files changed, 82 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/iommu/iommufd/device.c b/drivers/iommu/iommufd/device.c
+index 3c7800d4ab622..66a6b7466820d 100644
+--- a/drivers/iommu/iommufd/device.c
++++ b/drivers/iommu/iommufd/device.c
+@@ -3,6 +3,7 @@
+ */
+ #include <linux/iommu.h>
+ #include <linux/iommufd.h>
++#include <linux/pci-ats.h>
+ #include <linux/slab.h>
+ #include <uapi/linux/iommufd.h>
+
+@@ -1304,7 +1305,8 @@ int iommufd_get_hw_info(struct iommufd_ucmd *ucmd)
+ void *data;
+ int rc;
+
+- if (cmd->flags || cmd->__reserved)
++ if (cmd->flags || cmd->__reserved[0] || cmd->__reserved[1] ||
++ cmd->__reserved[2])
+ return -EOPNOTSUPP;
+
+ idev = iommufd_get_device(ucmd, cmd->dev_id);
+@@ -1361,6 +1363,36 @@ int iommufd_get_hw_info(struct iommufd_ucmd *ucmd)
+ if (device_iommu_capable(idev->dev, IOMMU_CAP_DIRTY_TRACKING))
+ cmd->out_capabilities |= IOMMU_HW_CAP_DIRTY_TRACKING;
+
++ cmd->out_max_pasid_log2 = 0;
++ /*
++ * Currently, all iommu drivers enable PASID in the probe_device()
++ * op if iommu and device supports it. So the max_pasids stored in
++ * dev->iommu indicates both PASID support and enable status. A
++ * non-zero dev->iommu->max_pasids means PASID is supported and
++ * enabled. The iommufd only reports PASID capability to userspace
++ * if it's enabled.
++ */
++ if (idev->dev->iommu->max_pasids) {
++ cmd->out_max_pasid_log2 = ilog2(idev->dev->iommu->max_pasids);
++
++ if (dev_is_pci(idev->dev)) {
++ struct pci_dev *pdev = to_pci_dev(idev->dev);
++ int ctrl;
++
++ ctrl = pci_pasid_status(pdev);
++
++ WARN_ON_ONCE(ctrl < 0 ||
++ !(ctrl & PCI_PASID_CTRL_ENABLE));
++
++ if (ctrl & PCI_PASID_CTRL_EXEC)
++ cmd->out_capabilities |=
++ IOMMU_HW_CAP_PCI_PASID_EXEC;
++ if (ctrl & PCI_PASID_CTRL_PRIV)
++ cmd->out_capabilities |=
++ IOMMU_HW_CAP_PCI_PASID_PRIV;
++ }
++ }
++
+ rc = iommufd_ucmd_respond(ucmd, sizeof(*cmd));
+ out_free:
+ kfree(data);
+diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c
+index c6b266c772c81..ec6c8dbdc5e9c 100644
+--- a/drivers/pci/ats.c
++++ b/drivers/pci/ats.c
+@@ -538,4 +538,37 @@ int pci_max_pasids(struct pci_dev *pdev)
+ return (1 << FIELD_GET(PCI_PASID_CAP_WIDTH, supported));
+ }
+ EXPORT_SYMBOL_GPL(pci_max_pasids);
++
++/**
++ * pci_pasid_status - Check the PASID status
++ * @pdev: PCI device structure
++ *
++ * Returns a negative value when no PASID capability is present.
++ * Otherwise the value of the control register is returned.
++ * Status reported are:
++ *
++ * PCI_PASID_CTRL_ENABLE - PASID enabled
++ * PCI_PASID_CTRL_EXEC - Execute permission enabled
++ * PCI_PASID_CTRL_PRIV - Privileged mode enabled
++ */
++int pci_pasid_status(struct pci_dev *pdev)
++{
++ int pasid;
++ u16 ctrl;
++
++ if (pdev->is_virtfn)
++ pdev = pci_physfn(pdev);
++
++ pasid = pdev->pasid_cap;
++ if (!pasid)
++ return -EINVAL;
++
++ pci_read_config_word(pdev, pasid + PCI_PASID_CTRL, &ctrl);
++
++ ctrl &= PCI_PASID_CTRL_ENABLE | PCI_PASID_CTRL_EXEC |
++ PCI_PASID_CTRL_PRIV;
++
++ return ctrl;
++}
++EXPORT_SYMBOL_GPL(pci_pasid_status);
+ #endif /* CONFIG_PCI_PASID */
+diff --git a/include/linux/pci-ats.h b/include/linux/pci-ats.h
+index 0e8b74e63767a..75c6c86cf09dc 100644
+--- a/include/linux/pci-ats.h
++++ b/include/linux/pci-ats.h
+@@ -42,6 +42,7 @@ int pci_enable_pasid(struct pci_dev *pdev, int features);
+ void pci_disable_pasid(struct pci_dev *pdev);
+ int pci_pasid_features(struct pci_dev *pdev);
+ int pci_max_pasids(struct pci_dev *pdev);
++int pci_pasid_status(struct pci_dev *pdev);
+ #else /* CONFIG_PCI_PASID */
+ static inline int pci_enable_pasid(struct pci_dev *pdev, int features)
+ { return -EINVAL; }
+@@ -50,6 +51,8 @@ static inline int pci_pasid_features(struct pci_dev *pdev)
+ { return -EINVAL; }
+ static inline int pci_max_pasids(struct pci_dev *pdev)
+ { return -EINVAL; }
++static inline int pci_pasid_status(struct pci_dev *pdev)
++{ return -EINVAL; }
+ #endif /* CONFIG_PCI_PASID */
+
+ #endif /* LINUX_PCI_ATS_H */
+diff --git a/include/uapi/linux/iommufd.h b/include/uapi/linux/iommufd.h
+index 78747b24bd0fb..9495604e40b06 100644
+--- a/include/uapi/linux/iommufd.h
++++ b/include/uapi/linux/iommufd.h
+@@ -608,9 +608,17 @@ enum iommu_hw_info_type {
+ * IOMMU_HWPT_GET_DIRTY_BITMAP
+ * IOMMU_HWPT_SET_DIRTY_TRACKING
+ *
++ * @IOMMU_HW_CAP_PCI_PASID_EXEC: Execute Permission Supported, user ignores it
++ * when the struct
++ * iommu_hw_info::out_max_pasid_log2 is zero.
++ * @IOMMU_HW_CAP_PCI_PASID_PRIV: Privileged Mode Supported, user ignores it
++ * when the struct
++ * iommu_hw_info::out_max_pasid_log2 is zero.
+ */
+ enum iommufd_hw_capabilities {
+ IOMMU_HW_CAP_DIRTY_TRACKING = 1 << 0,
++ IOMMU_HW_CAP_PCI_PASID_EXEC = 1 << 1,
++ IOMMU_HW_CAP_PCI_PASID_PRIV = 1 << 2,
+ };
+
+ /**
+@@ -626,6 +634,9 @@ enum iommufd_hw_capabilities {
+ * iommu_hw_info_type.
+ * @out_capabilities: Output the generic iommu capability info type as defined
+ * in the enum iommu_hw_capabilities.
++ * @out_max_pasid_log2: Output the width of PASIDs. 0 means no PASID support.
++ * PCI devices turn to out_capabilities to check if the
++ * specific capabilities is supported or not.
+ * @__reserved: Must be 0
+ *
+ * Query an iommu type specific hardware information data from an iommu behind
+@@ -649,7 +660,8 @@ struct iommu_hw_info {
+ __u32 data_len;
+ __aligned_u64 data_uptr;
+ __u32 out_data_type;
+- __u32 __reserved;
++ __u8 out_max_pasid_log2;
++ __u8 __reserved[3];
+ __aligned_u64 out_capabilities;
+ };
+ #define IOMMU_GET_HW_INFO _IO(IOMMUFD_TYPE, IOMMUFD_CMD_GET_HW_INFO)
+--
+2.39.5
+
--- /dev/null
+From d4af8df9b242204431211af615aebda8ab5450ec Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 7 Feb 2025 16:24:58 +0900
+Subject: ip: fib_rules: Fetch net from fib_rule in fib[46]_rule_configure().
+
+From: Kuniyuki Iwashima <kuniyu@amazon.com>
+
+[ Upstream commit 5a1ccffd30a08f5a2428cd5fbb3ab03e8eb6c66d ]
+
+The following patch will not set skb->sk from VRF path.
+
+Let's fetch net from fib_rule->fr_net instead of sock_net(skb->sk)
+in fib[46]_rule_configure().
+
+Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Tested-by: Ido Schimmel <idosch@nvidia.com>
+Link: https://patch.msgid.link/20250207072502.87775-5-kuniyu@amazon.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/fib_rules.c | 4 ++--
+ net/ipv6/fib6_rules.c | 4 ++--
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c
+index 9517b8667e000..041c46787d941 100644
+--- a/net/ipv4/fib_rules.c
++++ b/net/ipv4/fib_rules.c
+@@ -245,9 +245,9 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
+ struct nlattr **tb,
+ struct netlink_ext_ack *extack)
+ {
+- struct net *net = sock_net(skb->sk);
++ struct fib4_rule *rule4 = (struct fib4_rule *)rule;
++ struct net *net = rule->fr_net;
+ int err = -EINVAL;
+- struct fib4_rule *rule4 = (struct fib4_rule *) rule;
+
+ if (tb[FRA_FLOWLABEL] || tb[FRA_FLOWLABEL_MASK]) {
+ NL_SET_ERR_MSG(extack,
+diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c
+index 67d39114d9a63..40af8fd6efa70 100644
+--- a/net/ipv6/fib6_rules.c
++++ b/net/ipv6/fib6_rules.c
+@@ -399,9 +399,9 @@ static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
+ struct nlattr **tb,
+ struct netlink_ext_ack *extack)
+ {
++ struct fib6_rule *rule6 = (struct fib6_rule *)rule;
++ struct net *net = rule->fr_net;
+ int err = -EINVAL;
+- struct net *net = sock_net(skb->sk);
+- struct fib6_rule *rule6 = (struct fib6_rule *) rule;
+
+ if (!inet_validate_dscp(frh->tos)) {
+ NL_SET_ERR_MSG(extack,
+--
+2.39.5
+
--- /dev/null
+From 3e98d8a7e4eee3cc9824525b9ee8490e42a80a47 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Feb 2025 20:23:26 -0800
+Subject: ipv4: fib: Hold rtnl_net_lock() in ip_rt_ioctl().
+
+From: Kuniyuki Iwashima <kuniyu@amazon.com>
+
+[ Upstream commit c0ebe1cdc2cff0dee092a67f2c50377bb5fcf43d ]
+
+ioctl(SIOCADDRT/SIOCDELRT) calls ip_rt_ioctl() to add/remove a route in
+the netns of the specified socket.
+
+Let's hold rtnl_net_lock() there.
+
+Note that rtentry_to_fib_config() can be called without rtnl_net_lock()
+if we convert rtentry.dev handling to RCU later.
+
+Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Reviewed-by: David Ahern <dsahern@kernel.org>
+Link: https://patch.msgid.link/20250228042328.96624-11-kuniyu@amazon.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/fib_frontend.c | 10 ++++------
+ 1 file changed, 4 insertions(+), 6 deletions(-)
+
+diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
+index 493c37ce232d3..8470e259d8fd8 100644
+--- a/net/ipv4/fib_frontend.c
++++ b/net/ipv4/fib_frontend.c
+@@ -553,18 +553,16 @@ static int rtentry_to_fib_config(struct net *net, int cmd, struct rtentry *rt,
+ const struct in_ifaddr *ifa;
+ struct in_device *in_dev;
+
+- in_dev = __in_dev_get_rtnl(dev);
++ in_dev = __in_dev_get_rtnl_net(dev);
+ if (!in_dev)
+ return -ENODEV;
+
+ *colon = ':';
+
+- rcu_read_lock();
+- in_dev_for_each_ifa_rcu(ifa, in_dev) {
++ in_dev_for_each_ifa_rtnl_net(net, ifa, in_dev) {
+ if (strcmp(ifa->ifa_label, devname) == 0)
+ break;
+ }
+- rcu_read_unlock();
+
+ if (!ifa)
+ return -ENODEV;
+@@ -635,7 +633,7 @@ int ip_rt_ioctl(struct net *net, unsigned int cmd, struct rtentry *rt)
+ if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
+ return -EPERM;
+
+- rtnl_lock();
++ rtnl_net_lock(net);
+ err = rtentry_to_fib_config(net, cmd, rt, &cfg);
+ if (err == 0) {
+ struct fib_table *tb;
+@@ -659,7 +657,7 @@ int ip_rt_ioctl(struct net *net, unsigned int cmd, struct rtentry *rt)
+ /* allocated by rtentry_to_fib_config() */
+ kfree(cfg.fc_mx);
+ }
+- rtnl_unlock();
++ rtnl_net_unlock(net);
+ return err;
+ }
+ return -EINVAL;
+--
+2.39.5
+
--- /dev/null
+From 0a17ed66f8136f4fcac8e6150df4e3d68770b91d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Feb 2025 20:23:27 -0800
+Subject: ipv4: fib: Move fib_valid_key_len() to rtm_to_fib_config().
+
+From: Kuniyuki Iwashima <kuniyu@amazon.com>
+
+[ Upstream commit 254ba7e6032d3fc738050d500b0c1d8197af90ca ]
+
+fib_valid_key_len() is called in the beginning of fib_table_insert()
+or fib_table_delete() to check if the prefix length is valid.
+
+fib_table_insert() and fib_table_delete() are called from 3 paths
+
+ - ip_rt_ioctl()
+ - inet_rtm_newroute() / inet_rtm_delroute()
+ - fib_magic()
+
+In the first ioctl() path, rtentry_to_fib_config() checks the prefix
+length with bad_mask(). Also, fib_magic() always passes the correct
+prefix: 32 or ifa->ifa_prefixlen, which is already validated.
+
+Let's move fib_valid_key_len() to the rtnetlink path, rtm_to_fib_config().
+
+While at it, 2 direct returns in rtm_to_fib_config() are changed to
+goto to match other places in the same function
+
+Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Reviewed-by: David Ahern <dsahern@kernel.org>
+Link: https://patch.msgid.link/20250228042328.96624-12-kuniyu@amazon.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/fib_frontend.c | 18 ++++++++++++++++--
+ net/ipv4/fib_trie.c | 22 ----------------------
+ 2 files changed, 16 insertions(+), 24 deletions(-)
+
+diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
+index 272e42d813230..493c37ce232d3 100644
+--- a/net/ipv4/fib_frontend.c
++++ b/net/ipv4/fib_frontend.c
+@@ -837,19 +837,33 @@ static int rtm_to_fib_config(struct net *net, struct sk_buff *skb,
+ }
+ }
+
++ if (cfg->fc_dst_len > 32) {
++ NL_SET_ERR_MSG(extack, "Invalid prefix length");
++ err = -EINVAL;
++ goto errout;
++ }
++
++ if (cfg->fc_dst_len < 32 && (ntohl(cfg->fc_dst) << cfg->fc_dst_len)) {
++ NL_SET_ERR_MSG(extack, "Invalid prefix for given prefix length");
++ err = -EINVAL;
++ goto errout;
++ }
++
+ if (cfg->fc_nh_id) {
+ if (cfg->fc_oif || cfg->fc_gw_family ||
+ cfg->fc_encap || cfg->fc_mp) {
+ NL_SET_ERR_MSG(extack,
+ "Nexthop specification and nexthop id are mutually exclusive");
+- return -EINVAL;
++ err = -EINVAL;
++ goto errout;
+ }
+ }
+
+ if (has_gw && has_via) {
+ NL_SET_ERR_MSG(extack,
+ "Nexthop configuration can not contain both GATEWAY and VIA");
+- return -EINVAL;
++ err = -EINVAL;
++ goto errout;
+ }
+
+ if (!cfg->fc_table)
+diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
+index d6411ac810961..59a6f0a9638f9 100644
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -1187,22 +1187,6 @@ static int fib_insert_alias(struct trie *t, struct key_vector *tp,
+ return 0;
+ }
+
+-static bool fib_valid_key_len(u32 key, u8 plen, struct netlink_ext_ack *extack)
+-{
+- if (plen > KEYLENGTH) {
+- NL_SET_ERR_MSG(extack, "Invalid prefix length");
+- return false;
+- }
+-
+- if ((plen < KEYLENGTH) && (key << plen)) {
+- NL_SET_ERR_MSG(extack,
+- "Invalid prefix for given prefix length");
+- return false;
+- }
+-
+- return true;
+-}
+-
+ static void fib_remove_alias(struct trie *t, struct key_vector *tp,
+ struct key_vector *l, struct fib_alias *old);
+
+@@ -1223,9 +1207,6 @@ int fib_table_insert(struct net *net, struct fib_table *tb,
+
+ key = ntohl(cfg->fc_dst);
+
+- if (!fib_valid_key_len(key, plen, extack))
+- return -EINVAL;
+-
+ pr_debug("Insert table=%u %08x/%d\n", tb->tb_id, key, plen);
+
+ fi = fib_create_info(cfg, extack);
+@@ -1717,9 +1698,6 @@ int fib_table_delete(struct net *net, struct fib_table *tb,
+
+ key = ntohl(cfg->fc_dst);
+
+- if (!fib_valid_key_len(key, plen, extack))
+- return -EINVAL;
+-
+ l = fib_find_node(t, &tp, key);
+ if (!l)
+ return -ESRCH;
+--
+2.39.5
+
--- /dev/null
+From 7baabcffdfa33f60bf704b06e3b91bf3accf1607 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Feb 2025 22:36:54 +0100
+Subject: ipv4: ip_gre: Fix set but not used warning in ipgre_err() if
+ IPv4-only
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Geert Uytterhoeven <geert@linux-m68k.org>
+
+[ Upstream commit 50f37fc2a39c4a8cc4813629b4cf239b71c6097d ]
+
+if CONFIG_NET_IPGRE is enabled, but CONFIG_IPV6 is disabled:
+
+ net/ipv4/ip_gre.c: In function ‘ipgre_err’:
+ net/ipv4/ip_gre.c:144:22: error: variable ‘data_len’ set but not used [-Werror=unused-but-set-variable]
+ 144 | unsigned int data_len = 0;
+ | ^~~~~~~~
+
+Fix this by moving all data_len processing inside the IPV6-only section
+that uses its result.
+
+Reported-by: kernel test robot <lkp@intel.com>
+Closes: https://lore.kernel.org/oe-kbuild-all/202501121007.2GofXmh5-lkp@intel.com/
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/d09113cfe2bfaca02f3dddf832fb5f48dd20958b.1738704881.git.geert@linux-m68k.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/ip_gre.c | 16 ++++++++++------
+ 1 file changed, 10 insertions(+), 6 deletions(-)
+
+diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
+index ed1b6b44faf80..c9f11a046c263 100644
+--- a/net/ipv4/ip_gre.c
++++ b/net/ipv4/ip_gre.c
+@@ -141,7 +141,6 @@ static int ipgre_err(struct sk_buff *skb, u32 info,
+ const struct iphdr *iph;
+ const int type = icmp_hdr(skb)->type;
+ const int code = icmp_hdr(skb)->code;
+- unsigned int data_len = 0;
+ struct ip_tunnel *t;
+
+ if (tpi->proto == htons(ETH_P_TEB))
+@@ -182,7 +181,6 @@ static int ipgre_err(struct sk_buff *skb, u32 info,
+ case ICMP_TIME_EXCEEDED:
+ if (code != ICMP_EXC_TTL)
+ return 0;
+- data_len = icmp_hdr(skb)->un.reserved[1] * 4; /* RFC 4884 4.1 */
+ break;
+
+ case ICMP_REDIRECT:
+@@ -190,10 +188,16 @@ static int ipgre_err(struct sk_buff *skb, u32 info,
+ }
+
+ #if IS_ENABLED(CONFIG_IPV6)
+- if (tpi->proto == htons(ETH_P_IPV6) &&
+- !ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4 + tpi->hdr_len,
+- type, data_len))
+- return 0;
++ if (tpi->proto == htons(ETH_P_IPV6)) {
++ unsigned int data_len = 0;
++
++ if (type == ICMP_TIME_EXCEEDED)
++ data_len = icmp_hdr(skb)->un.reserved[1] * 4; /* RFC 4884 4.1 */
++
++ if (!ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4 + tpi->hdr_len,
++ type, data_len))
++ return 0;
++ }
+ #endif
+
+ if (t->parms.iph.daddr == 0 ||
+--
+2.39.5
+
--- /dev/null
+From 67bbdde4eb0ff6badabf3d992f97565315d89d6e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Mar 2025 22:34:08 -0500
+Subject: ipv6: remove leftover ip6 cookie initializer
+
+From: Willem de Bruijn <willemb@google.com>
+
+[ Upstream commit 54580ccdd8a9c6821fd6f72171d435480867e4c3 ]
+
+As of the blamed commit ipc6.dontfrag is always initialized at the
+start of udpv6_sendmsg, by ipcm6_init_sk, to either 0 or 1.
+
+Later checks against -1 are no longer needed and the branches are now
+dead code.
+
+The blamed commit had removed those branches. But I had overlooked
+this one case.
+
+UDP has both a lockless fast path and a slower path for corked
+requests. This branch remained in the fast path.
+
+Fixes: 096208592b09 ("ipv6: replace ipcm6_init calls with ipcm6_init_sk")
+Signed-off-by: Willem de Bruijn <willemb@google.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20250307033620.411611-2-willemdebruijn.kernel@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/ip6_output.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
+index eb636bec89796..581bc62890818 100644
+--- a/net/ipv6/ip6_output.c
++++ b/net/ipv6/ip6_output.c
+@@ -2055,8 +2055,6 @@ struct sk_buff *ip6_make_skb(struct sock *sk,
+ ip6_cork_release(cork, &v6_cork);
+ return ERR_PTR(err);
+ }
+- if (ipc6->dontfrag < 0)
+- ipc6->dontfrag = inet6_test_bit(DONTFRAG, sk);
+
+ err = __ip6_append_data(sk, &queue, cork, &v6_cork,
+ ¤t->task_frag, getfrag, from,
+--
+2.39.5
+
--- /dev/null
+From 17a855ee87d2b7a42081f85bcffc1556cb46ad7c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Mar 2025 22:34:09 -0500
+Subject: ipv6: save dontfrag in cork
+
+From: Willem de Bruijn <willemb@google.com>
+
+[ Upstream commit a18dfa9925b9ef6107ea3aa5814ca3c704d34a8a ]
+
+When spanning datagram construction over multiple send calls using
+MSG_MORE, per datagram settings are configured on the first send.
+
+That is when ip(6)_setup_cork stores these settings for subsequent use
+in __ip(6)_append_data and others.
+
+The only flag that escaped this was dontfrag. As a result, a datagram
+could be constructed with df=0 on the first sendmsg, but df=1 on a
+next. Which is what cmsg_ip.sh does in an upcoming MSG_MORE test in
+the "diff" scenario.
+
+Changing datagram conditions in the middle of constructing an skb
+makes this already complex code path even more convoluted. It is here
+unintentional. Bring this flag in line with expected sockopt/cmsg
+behavior.
+
+And stop passing ipc6 to __ip6_append_data, to avoid such issues
+in the future. This is already the case for __ip_append_data.
+
+inet6_cork had a 6 byte hole, so the 1B flag has no impact.
+
+Signed-off-by: Willem de Bruijn <willemb@google.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20250307033620.411611-3-willemdebruijn.kernel@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/ipv6.h | 1 +
+ net/ipv6/ip6_output.c | 9 +++++----
+ 2 files changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
+index a6e2aadbb91bd..5aeeed22f35bf 100644
+--- a/include/linux/ipv6.h
++++ b/include/linux/ipv6.h
+@@ -207,6 +207,7 @@ struct inet6_cork {
+ struct ipv6_txoptions *opt;
+ u8 hop_limit;
+ u8 tclass;
++ u8 dontfrag:1;
+ };
+
+ /* struct ipv6_pinfo - ipv6 private area */
+diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
+index d577bf2f30538..eb636bec89796 100644
+--- a/net/ipv6/ip6_output.c
++++ b/net/ipv6/ip6_output.c
+@@ -1386,6 +1386,7 @@ static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork,
+ }
+ v6_cork->hop_limit = ipc6->hlimit;
+ v6_cork->tclass = ipc6->tclass;
++ v6_cork->dontfrag = ipc6->dontfrag;
+ if (rt->dst.flags & DST_XFRM_TUNNEL)
+ mtu = READ_ONCE(np->pmtudisc) >= IPV6_PMTUDISC_PROBE ?
+ READ_ONCE(rt->dst.dev->mtu) : dst_mtu(&rt->dst);
+@@ -1421,7 +1422,7 @@ static int __ip6_append_data(struct sock *sk,
+ int getfrag(void *from, char *to, int offset,
+ int len, int odd, struct sk_buff *skb),
+ void *from, size_t length, int transhdrlen,
+- unsigned int flags, struct ipcm6_cookie *ipc6)
++ unsigned int flags)
+ {
+ struct sk_buff *skb, *skb_prev = NULL;
+ struct inet_cork *cork = &cork_full->base;
+@@ -1475,7 +1476,7 @@ static int __ip6_append_data(struct sock *sk,
+ if (headersize + transhdrlen > mtu)
+ goto emsgsize;
+
+- if (cork->length + length > mtu - headersize && ipc6->dontfrag &&
++ if (cork->length + length > mtu - headersize && v6_cork->dontfrag &&
+ (sk->sk_protocol == IPPROTO_UDP ||
+ sk->sk_protocol == IPPROTO_ICMPV6 ||
+ sk->sk_protocol == IPPROTO_RAW)) {
+@@ -1855,7 +1856,7 @@ int ip6_append_data(struct sock *sk,
+
+ return __ip6_append_data(sk, &sk->sk_write_queue, &inet->cork,
+ &np->cork, sk_page_frag(sk), getfrag,
+- from, length, transhdrlen, flags, ipc6);
++ from, length, transhdrlen, flags);
+ }
+ EXPORT_SYMBOL_GPL(ip6_append_data);
+
+@@ -2060,7 +2061,7 @@ struct sk_buff *ip6_make_skb(struct sock *sk,
+ err = __ip6_append_data(sk, &queue, cork, &v6_cork,
+ ¤t->task_frag, getfrag, from,
+ length + exthdrlen, transhdrlen + exthdrlen,
+- flags, ipc6);
++ flags);
+ if (err) {
+ __ip6_flush_pending_frames(sk, &queue, cork, &v6_cork);
+ return ERR_PTR(err);
+--
+2.39.5
+
--- /dev/null
+From f34f6310a5ebc7a8b67a709cccb8e8005fd0781d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jan 2025 11:16:37 +0200
+Subject: irqchip/riscv-aplic: Add support for hart indexes
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Vladimir Kondratiev <vladimir.kondratiev@mobileye.com>
+
+[ Upstream commit b93afe8a3ac53ae52296d65acfaa9c5f582a48cc ]
+
+RISC-V APLIC specification defines "hart index" in:
+
+ https://github.com/riscv/riscv-aia
+
+Within a given interrupt domain, each of the domain’s harts has a unique
+index number in the range 0 to 2^14 − 1 (= 16,383). The index number a
+domain associates with a hart may or may not have any relationship to the
+unique hart identifier (“hart ID”) that the RISC-V Privileged Architecture
+assigns to the hart. Two different interrupt domains may employ entirely
+different index numbers for the same set of harts.
+
+Further, this document says in "4.5 Memory-mapped control region for an
+interrupt domain":
+
+The array of IDC structures may include some for potential hart index
+numbers that are not actual hart index numbers in the domain. For example,
+the first IDC structure is always for hart index 0, but 0 is not
+necessarily a valid index number for any hart in the domain.
+
+Support arbitrary hart indices specified in an optional APLIC property
+"riscv,hart-indexes" which is specified as an array of u32 elements, one
+per interrupt target. If this property is not specified, fallback to use
+logical hart indices within the domain.
+
+Signed-off-by: Vladimir Kondratiev <vladimir.kondratiev@mobileye.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Reviewed-by: Anup Patel <anup@brainfault.org>
+Link: https://lore.kernel.org/all/20250129091637.1667279-3-vladimir.kondratiev@mobileye.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/irqchip/irq-riscv-aplic-direct.c | 24 +++++++++++++++++++++---
+ 1 file changed, 21 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/irqchip/irq-riscv-aplic-direct.c b/drivers/irqchip/irq-riscv-aplic-direct.c
+index 7cd6b646774b9..205ad61d15e49 100644
+--- a/drivers/irqchip/irq-riscv-aplic-direct.c
++++ b/drivers/irqchip/irq-riscv-aplic-direct.c
+@@ -31,7 +31,7 @@ struct aplic_direct {
+ };
+
+ struct aplic_idc {
+- unsigned int hart_index;
++ u32 hart_index;
+ void __iomem *regs;
+ struct aplic_direct *direct;
+ };
+@@ -219,6 +219,20 @@ static int aplic_direct_parse_parent_hwirq(struct device *dev, u32 index,
+ return 0;
+ }
+
++static int aplic_direct_get_hart_index(struct device *dev, u32 logical_index,
++ u32 *hart_index)
++{
++ const char *prop_hart_index = "riscv,hart-indexes";
++ struct device_node *np = to_of_node(dev->fwnode);
++
++ if (!np || !of_property_present(np, prop_hart_index)) {
++ *hart_index = logical_index;
++ return 0;
++ }
++
++ return of_property_read_u32_index(np, prop_hart_index, logical_index, hart_index);
++}
++
+ int aplic_direct_setup(struct device *dev, void __iomem *regs)
+ {
+ int i, j, rc, cpu, current_cpu, setup_count = 0;
+@@ -265,8 +279,12 @@ int aplic_direct_setup(struct device *dev, void __iomem *regs)
+ cpumask_set_cpu(cpu, &direct->lmask);
+
+ idc = per_cpu_ptr(&aplic_idcs, cpu);
+- idc->hart_index = i;
+- idc->regs = priv->regs + APLIC_IDC_BASE + i * APLIC_IDC_SIZE;
++ rc = aplic_direct_get_hart_index(dev, i, &idc->hart_index);
++ if (rc) {
++ dev_warn(dev, "hart index not found for IDC%d\n", i);
++ continue;
++ }
++ idc->regs = priv->regs + APLIC_IDC_BASE + idc->hart_index * APLIC_IDC_SIZE;
+ idc->direct = direct;
+
+ aplic_idc_set_delivery(idc, true);
+--
+2.39.5
+
--- /dev/null
+From 0fb6dd7ef17a4990048cd2a5460a99d6eeaf521d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 17 Feb 2025 14:26:53 +0530
+Subject: irqchip/riscv-imsic: Separate next and previous pointers in IMSIC
+ vector
+
+From: Anup Patel <apatel@ventanamicro.com>
+
+[ Upstream commit 0f67911e821c67ecfccc365a2103ce276a9a56fe ]
+
+Currently, there is only one "move" pointer in struct imsic_vector so
+during vector movement the old vector points to the new vector and new
+vector points to itself.
+
+To support forced cleanup of the old vector, add separate "move_next" and
+"move_prev" pointers to struct imsic_vector, where during vector movement
+the "move_next" pointer of the old vector points to the new vector and the
+"move_prev" pointer of the new vector points to the old vector.
+
+Both "move_next" and "move_prev" pointers are cleared separately by
+__imsic_local_sync() with a restriction that "move_prev" on the new
+CPU is cleared only after the old CPU has cleared "move_next".
+
+Signed-off-by: Anup Patel <apatel@ventanamicro.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Link: https://lore.kernel.org/all/20250217085657.789309-8-apatel@ventanamicro.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/irqchip/irq-riscv-imsic-early.c | 8 ++-
+ drivers/irqchip/irq-riscv-imsic-state.c | 96 +++++++++++++++++--------
+ drivers/irqchip/irq-riscv-imsic-state.h | 7 +-
+ 3 files changed, 78 insertions(+), 33 deletions(-)
+
+diff --git a/drivers/irqchip/irq-riscv-imsic-early.c b/drivers/irqchip/irq-riscv-imsic-early.c
+index 275df50057057..553650932c75f 100644
+--- a/drivers/irqchip/irq-riscv-imsic-early.c
++++ b/drivers/irqchip/irq-riscv-imsic-early.c
+@@ -77,6 +77,12 @@ static void imsic_handle_irq(struct irq_desc *desc)
+ struct imsic_vector *vec;
+ unsigned long local_id;
+
++ /*
++ * Process pending local synchronization instead of waiting
++ * for per-CPU local timer to expire.
++ */
++ imsic_local_sync_all(false);
++
+ chained_irq_enter(chip, desc);
+
+ while ((local_id = csr_swap(CSR_TOPEI, 0))) {
+@@ -120,7 +126,7 @@ static int imsic_starting_cpu(unsigned int cpu)
+ * Interrupts identities might have been enabled/disabled while
+ * this CPU was not running so sync-up local enable/disable state.
+ */
+- imsic_local_sync_all();
++ imsic_local_sync_all(true);
+
+ /* Enable local interrupt delivery */
+ imsic_local_delivery(true);
+diff --git a/drivers/irqchip/irq-riscv-imsic-state.c b/drivers/irqchip/irq-riscv-imsic-state.c
+index b97e6cd89ed74..1aeba76d72795 100644
+--- a/drivers/irqchip/irq-riscv-imsic-state.c
++++ b/drivers/irqchip/irq-riscv-imsic-state.c
+@@ -124,10 +124,11 @@ void __imsic_eix_update(unsigned long base_id, unsigned long num_id, bool pend,
+ }
+ }
+
+-static void __imsic_local_sync(struct imsic_local_priv *lpriv)
++static bool __imsic_local_sync(struct imsic_local_priv *lpriv)
+ {
+ struct imsic_local_config *mlocal;
+ struct imsic_vector *vec, *mvec;
++ bool ret = true;
+ int i;
+
+ lockdep_assert_held(&lpriv->lock);
+@@ -143,35 +144,75 @@ static void __imsic_local_sync(struct imsic_local_priv *lpriv)
+ __imsic_id_clear_enable(i);
+
+ /*
+- * If the ID was being moved to a new ID on some other CPU
+- * then we can get a MSI during the movement so check the
+- * ID pending bit and re-trigger the new ID on other CPU
+- * using MMIO write.
++ * Clear the previous vector pointer of the new vector only
++ * after the movement is complete on the old CPU.
+ */
+- mvec = READ_ONCE(vec->move);
+- WRITE_ONCE(vec->move, NULL);
+- if (mvec && mvec != vec) {
++ mvec = READ_ONCE(vec->move_prev);
++ if (mvec) {
++ /*
++ * If the old vector has not been updated then
++ * try again in the next sync-up call.
++ */
++ if (READ_ONCE(mvec->move_next)) {
++ ret = false;
++ continue;
++ }
++
++ WRITE_ONCE(vec->move_prev, NULL);
++ }
++
++ /*
++ * If a vector was being moved to a new vector on some other
++ * CPU then we can get a MSI during the movement so check the
++ * ID pending bit and re-trigger the new ID on other CPU using
++ * MMIO write.
++ */
++ mvec = READ_ONCE(vec->move_next);
++ if (mvec) {
+ if (__imsic_id_read_clear_pending(i)) {
+ mlocal = per_cpu_ptr(imsic->global.local, mvec->cpu);
+ writel_relaxed(mvec->local_id, mlocal->msi_va);
+ }
+
++ WRITE_ONCE(vec->move_next, NULL);
+ imsic_vector_free(&lpriv->vectors[i]);
+ }
+
+ skip:
+ bitmap_clear(lpriv->dirty_bitmap, i, 1);
+ }
++
++ return ret;
+ }
+
+-void imsic_local_sync_all(void)
++#ifdef CONFIG_SMP
++static void __imsic_local_timer_start(struct imsic_local_priv *lpriv)
++{
++ lockdep_assert_held(&lpriv->lock);
++
++ if (!timer_pending(&lpriv->timer)) {
++ lpriv->timer.expires = jiffies + 1;
++ add_timer_on(&lpriv->timer, smp_processor_id());
++ }
++}
++#else
++static inline void __imsic_local_timer_start(struct imsic_local_priv *lpriv)
++{
++}
++#endif
++
++void imsic_local_sync_all(bool force_all)
+ {
+ struct imsic_local_priv *lpriv = this_cpu_ptr(imsic->lpriv);
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&lpriv->lock, flags);
+- bitmap_fill(lpriv->dirty_bitmap, imsic->global.nr_ids + 1);
+- __imsic_local_sync(lpriv);
++
++ if (force_all)
++ bitmap_fill(lpriv->dirty_bitmap, imsic->global.nr_ids + 1);
++ if (!__imsic_local_sync(lpriv))
++ __imsic_local_timer_start(lpriv);
++
+ raw_spin_unlock_irqrestore(&lpriv->lock, flags);
+ }
+
+@@ -190,12 +231,7 @@ void imsic_local_delivery(bool enable)
+ #ifdef CONFIG_SMP
+ static void imsic_local_timer_callback(struct timer_list *timer)
+ {
+- struct imsic_local_priv *lpriv = this_cpu_ptr(imsic->lpriv);
+- unsigned long flags;
+-
+- raw_spin_lock_irqsave(&lpriv->lock, flags);
+- __imsic_local_sync(lpriv);
+- raw_spin_unlock_irqrestore(&lpriv->lock, flags);
++ imsic_local_sync_all(false);
+ }
+
+ static void __imsic_remote_sync(struct imsic_local_priv *lpriv, unsigned int cpu)
+@@ -216,14 +252,11 @@ static void __imsic_remote_sync(struct imsic_local_priv *lpriv, unsigned int cpu
+ */
+ if (cpu_online(cpu)) {
+ if (cpu == smp_processor_id()) {
+- __imsic_local_sync(lpriv);
+- return;
++ if (__imsic_local_sync(lpriv))
++ return;
+ }
+
+- if (!timer_pending(&lpriv->timer)) {
+- lpriv->timer.expires = jiffies + 1;
+- add_timer_on(&lpriv->timer, cpu);
+- }
++ __imsic_local_timer_start(lpriv);
+ }
+ }
+ #else
+@@ -278,8 +311,9 @@ void imsic_vector_unmask(struct imsic_vector *vec)
+ raw_spin_unlock(&lpriv->lock);
+ }
+
+-static bool imsic_vector_move_update(struct imsic_local_priv *lpriv, struct imsic_vector *vec,
+- bool new_enable, struct imsic_vector *new_move)
++static bool imsic_vector_move_update(struct imsic_local_priv *lpriv,
++ struct imsic_vector *vec, bool is_old_vec,
++ bool new_enable, struct imsic_vector *move_vec)
+ {
+ unsigned long flags;
+ bool enabled;
+@@ -289,7 +323,10 @@ static bool imsic_vector_move_update(struct imsic_local_priv *lpriv, struct imsi
+ /* Update enable and move details */
+ enabled = READ_ONCE(vec->enable);
+ WRITE_ONCE(vec->enable, new_enable);
+- WRITE_ONCE(vec->move, new_move);
++ if (is_old_vec)
++ WRITE_ONCE(vec->move_next, move_vec);
++ else
++ WRITE_ONCE(vec->move_prev, move_vec);
+
+ /* Mark the vector as dirty and synchronize */
+ bitmap_set(lpriv->dirty_bitmap, vec->local_id, 1);
+@@ -322,8 +359,8 @@ void imsic_vector_move(struct imsic_vector *old_vec, struct imsic_vector *new_ve
+ * interrupt on the old vector while device was being moved
+ * to the new vector.
+ */
+- enabled = imsic_vector_move_update(old_lpriv, old_vec, false, new_vec);
+- imsic_vector_move_update(new_lpriv, new_vec, enabled, new_vec);
++ enabled = imsic_vector_move_update(old_lpriv, old_vec, true, false, new_vec);
++ imsic_vector_move_update(new_lpriv, new_vec, false, enabled, old_vec);
+ }
+
+ #ifdef CONFIG_GENERIC_IRQ_DEBUGFS
+@@ -386,7 +423,8 @@ struct imsic_vector *imsic_vector_alloc(unsigned int hwirq, const struct cpumask
+ vec = &lpriv->vectors[local_id];
+ vec->hwirq = hwirq;
+ vec->enable = false;
+- vec->move = NULL;
++ vec->move_next = NULL;
++ vec->move_prev = NULL;
+
+ return vec;
+ }
+diff --git a/drivers/irqchip/irq-riscv-imsic-state.h b/drivers/irqchip/irq-riscv-imsic-state.h
+index 391e442808275..f02842b84ed58 100644
+--- a/drivers/irqchip/irq-riscv-imsic-state.h
++++ b/drivers/irqchip/irq-riscv-imsic-state.h
+@@ -23,7 +23,8 @@ struct imsic_vector {
+ unsigned int hwirq;
+ /* Details accessed using local lock held */
+ bool enable;
+- struct imsic_vector *move;
++ struct imsic_vector *move_next;
++ struct imsic_vector *move_prev;
+ };
+
+ struct imsic_local_priv {
+@@ -74,7 +75,7 @@ static inline void __imsic_id_clear_enable(unsigned long id)
+ __imsic_eix_update(id, 1, false, false);
+ }
+
+-void imsic_local_sync_all(void);
++void imsic_local_sync_all(bool force_all);
+ void imsic_local_delivery(bool enable);
+
+ void imsic_vector_mask(struct imsic_vector *vec);
+@@ -87,7 +88,7 @@ static inline bool imsic_vector_isenabled(struct imsic_vector *vec)
+
+ static inline struct imsic_vector *imsic_vector_get_move(struct imsic_vector *vec)
+ {
+- return READ_ONCE(vec->move);
++ return READ_ONCE(vec->move_prev);
+ }
+
+ void imsic_vector_move(struct imsic_vector *old_vec, struct imsic_vector *new_vec);
+--
+2.39.5
+
--- /dev/null
+From 57249338fd4bd79b07bbe7d17ae4e6ba3a0ea60d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 17 Feb 2025 14:26:47 +0530
+Subject: irqchip/riscv-imsic: Set irq_set_affinity() for IMSIC base
+
+From: Andrew Jones <ajones@ventanamicro.com>
+
+[ Upstream commit 999f458c1771354371ba367dd84f55f9a62a4233 ]
+
+The IMSIC driver assigns the IMSIC domain specific imsic_irq_set_affinity()
+callback to the per device leaf MSI domain. That's a layering violation as
+it is called with the leaf domain data and not with the IMSIC domain
+data. This prevents moving the IMSIC driver to the common MSI library which
+uses the generic msi_domain_set_affinity() callback for device MSI domains.
+
+Instead of using imsic_irq_set_affinity() for leaf MSI domains, use
+imsic_irq_set_affinity() for the non-leaf IMSIC base domain and use
+irq_chip_set_affinity_parent() for leaf MSI domains.
+
+[ tglx: Massaged change log ]
+
+Signed-off-by: Andrew Jones <ajones@ventanamicro.com>
+Signed-off-by: Anup Patel <apatel@ventanamicro.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Link: https://lore.kernel.org/all/20250217085657.789309-2-apatel@ventanamicro.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/irqchip/irq-riscv-imsic-platform.c | 16 +++++++++-------
+ 1 file changed, 9 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/irqchip/irq-riscv-imsic-platform.c b/drivers/irqchip/irq-riscv-imsic-platform.c
+index c708780e8760f..5d7c30ad8855b 100644
+--- a/drivers/irqchip/irq-riscv-imsic-platform.c
++++ b/drivers/irqchip/irq-riscv-imsic-platform.c
+@@ -96,9 +96,8 @@ static int imsic_irq_set_affinity(struct irq_data *d, const struct cpumask *mask
+ bool force)
+ {
+ struct imsic_vector *old_vec, *new_vec;
+- struct irq_data *pd = d->parent_data;
+
+- old_vec = irq_data_get_irq_chip_data(pd);
++ old_vec = irq_data_get_irq_chip_data(d);
+ if (WARN_ON(!old_vec))
+ return -ENOENT;
+
+@@ -116,13 +115,13 @@ static int imsic_irq_set_affinity(struct irq_data *d, const struct cpumask *mask
+ return -ENOSPC;
+
+ /* Point device to the new vector */
+- imsic_msi_update_msg(d, new_vec);
++ imsic_msi_update_msg(irq_get_irq_data(d->irq), new_vec);
+
+ /* Update irq descriptors with the new vector */
+- pd->chip_data = new_vec;
++ d->chip_data = new_vec;
+
+- /* Update effective affinity of parent irq data */
+- irq_data_update_effective_affinity(pd, cpumask_of(new_vec->cpu));
++ /* Update effective affinity */
++ irq_data_update_effective_affinity(d, cpumask_of(new_vec->cpu));
+
+ /* Move state of the old vector to the new vector */
+ imsic_vector_move(old_vec, new_vec);
+@@ -135,6 +134,9 @@ static struct irq_chip imsic_irq_base_chip = {
+ .name = "IMSIC",
+ .irq_mask = imsic_irq_mask,
+ .irq_unmask = imsic_irq_unmask,
++#ifdef CONFIG_SMP
++ .irq_set_affinity = imsic_irq_set_affinity,
++#endif
+ .irq_retrigger = imsic_irq_retrigger,
+ .irq_compose_msi_msg = imsic_irq_compose_msg,
+ .flags = IRQCHIP_SKIP_SET_WAKE |
+@@ -245,7 +247,7 @@ static bool imsic_init_dev_msi_info(struct device *dev,
+ if (WARN_ON_ONCE(domain != real_parent))
+ return false;
+ #ifdef CONFIG_SMP
+- info->chip->irq_set_affinity = imsic_irq_set_affinity;
++ info->chip->irq_set_affinity = irq_chip_set_affinity_parent;
+ #endif
+ break;
+ default:
+--
+2.39.5
+
--- /dev/null
+From 1d2d5c81d591948eecc99a2e1ae0320b7324f5e8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 10 Mar 2025 10:44:59 -0700
+Subject: ixgbe: add support for thermal sensor event reception
+
+From: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
+
+[ Upstream commit affead2d904e8f82c0b89e23b3835242eb8c3e1a ]
+
+E610 NICs unlike the previous devices utilising ixgbe driver
+are notified in the case of overheating by the FW ACI event.
+
+In event of overheat when threshold is exceeded, FW suspends all
+traffic and sends overtemp event to the driver. Then driver
+logs appropriate message and disables the adapter instance.
+The card remains in that state until the platform is rebooted.
+
+This approach is a solution to the fact current version of the
+E610 FW doesn't support reading thermal sensor data by the
+SW. So give to user at least any info that overtemp event
+has occurred, without interface disappearing from the OS
+without any note.
+
+Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
+Reviewed-by: Mateusz Polchlopek <mateusz.polchlopek@intel.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Signed-off-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
+Tested-by: Jeremiah Lokan <jeremiahx.j.lokan@intel.com> (A Contingent worker at Intel)
+Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
+Link: https://patch.msgid.link/20250310174502.3708121-7-anthony.l.nguyen@intel.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 4 ++++
+ drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h | 3 +++
+ 2 files changed, 7 insertions(+)
+
+diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+index 467f81239e12f..481f917f7ed28 100644
+--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
++++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+@@ -3185,6 +3185,10 @@ static void ixgbe_handle_fw_event(struct ixgbe_adapter *adapter)
+ case ixgbe_aci_opc_get_link_status:
+ ixgbe_handle_link_status_event(adapter, &event);
+ break;
++ case ixgbe_aci_opc_temp_tca_event:
++ e_crit(drv, "%s\n", ixgbe_overheat_msg);
++ ixgbe_down(adapter);
++ break;
+ default:
+ e_warn(hw, "unknown FW async event captured\n");
+ break;
+diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h
+index 8d06ade3c7cd9..617e07878e4f7 100644
+--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h
++++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h
+@@ -171,6 +171,9 @@ enum ixgbe_aci_opc {
+ ixgbe_aci_opc_done_alt_write = 0x0904,
+ ixgbe_aci_opc_clear_port_alt_write = 0x0906,
+
++ /* TCA Events */
++ ixgbe_aci_opc_temp_tca_event = 0x0C94,
++
+ /* debug commands */
+ ixgbe_aci_opc_debug_dump_internals = 0xFF08,
+
+--
+2.39.5
+
--- /dev/null
+From 994b5f9d200376a4b992f0620e3ca4185f81e7f4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 21 Jan 2025 15:09:26 +0100
+Subject: jbd2: Avoid long replay times due to high number or revoke blocks
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit a399af4e3b1ab2c5d83292d4487c4d18de551659 ]
+
+Some users are reporting journal replay takes a long time when there is
+excessive number of revoke blocks in the journal. Reported times are
+like:
+
+1048576 records - 95 seconds
+2097152 records - 580 seconds
+
+The problem is that hash chains in the revoke table gets excessively
+long in these cases. Fix the problem by sizing the revoke table
+appropriately before the revoke pass.
+
+Thanks to Alexey Zhuravlev <azhuravlev@ddn.com> for benchmarking the
+patch with large numbers of revoke blocks [1].
+
+[1] https://lore.kernel.org/all/20250113183107.7bfef7b6@x390.bzzz77.ru
+
+Signed-off-by: Jan Kara <jack@suse.cz>
+Reviewed-by: Andreas Dilger <adilger@dilger.ca>
+Reviewed-by: Zhang Yi <yi.zhang@huawei.com>
+Link: https://patch.msgid.link/20250121140925.17231-2-jack@suse.cz
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/jbd2/recovery.c | 58 ++++++++++++++++++++++++++++++++++++--------
+ fs/jbd2/revoke.c | 8 +++---
+ include/linux/jbd2.h | 2 ++
+ 3 files changed, 54 insertions(+), 14 deletions(-)
+
+diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c
+index 23502f1a67c1e..a3c39a71c4ad3 100644
+--- a/fs/jbd2/recovery.c
++++ b/fs/jbd2/recovery.c
+@@ -39,7 +39,7 @@ struct recovery_info
+
+ static int do_one_pass(journal_t *journal,
+ struct recovery_info *info, enum passtype pass);
+-static int scan_revoke_records(journal_t *, struct buffer_head *,
++static int scan_revoke_records(journal_t *, enum passtype, struct buffer_head *,
+ tid_t, struct recovery_info *);
+
+ #ifdef __KERNEL__
+@@ -328,6 +328,12 @@ int jbd2_journal_recover(journal_t *journal)
+ journal->j_transaction_sequence, journal->j_head);
+
+ jbd2_journal_clear_revoke(journal);
++ /* Free revoke table allocated for replay */
++ if (journal->j_revoke != journal->j_revoke_table[0] &&
++ journal->j_revoke != journal->j_revoke_table[1]) {
++ jbd2_journal_destroy_revoke_table(journal->j_revoke);
++ journal->j_revoke = journal->j_revoke_table[1];
++ }
+ err2 = sync_blockdev(journal->j_fs_dev);
+ if (!err)
+ err = err2;
+@@ -613,6 +619,31 @@ static int do_one_pass(journal_t *journal,
+ first_commit_ID = next_commit_ID;
+ if (pass == PASS_SCAN)
+ info->start_transaction = first_commit_ID;
++ else if (pass == PASS_REVOKE) {
++ /*
++ * Would the default revoke table have too long hash chains
++ * during replay?
++ */
++ if (info->nr_revokes > JOURNAL_REVOKE_DEFAULT_HASH * 16) {
++ unsigned int hash_size;
++
++ /*
++ * Aim for average chain length of 8, limit at 1M
++ * entries to avoid problems with malicious
++ * filesystems.
++ */
++ hash_size = min(roundup_pow_of_two(info->nr_revokes / 8),
++ 1U << 20);
++ journal->j_revoke =
++ jbd2_journal_init_revoke_table(hash_size);
++ if (!journal->j_revoke) {
++ printk(KERN_ERR
++ "JBD2: failed to allocate revoke table for replay with %u entries. "
++ "Journal replay may be slow.\n", hash_size);
++ journal->j_revoke = journal->j_revoke_table[1];
++ }
++ }
++ }
+
+ jbd2_debug(1, "Starting recovery pass %d\n", pass);
+
+@@ -852,6 +883,13 @@ static int do_one_pass(journal_t *journal,
+ continue;
+
+ case JBD2_REVOKE_BLOCK:
++ /*
++ * If we aren't in the SCAN or REVOKE pass, then we can
++ * just skip over this block.
++ */
++ if (pass != PASS_REVOKE && pass != PASS_SCAN)
++ continue;
++
+ /*
+ * Check revoke block crc in pass_scan, if csum verify
+ * failed, check commit block time later.
+@@ -864,12 +902,7 @@ static int do_one_pass(journal_t *journal,
+ need_check_commit_time = true;
+ }
+
+- /* If we aren't in the REVOKE pass, then we can
+- * just skip over this block. */
+- if (pass != PASS_REVOKE)
+- continue;
+-
+- err = scan_revoke_records(journal, bh,
++ err = scan_revoke_records(journal, pass, bh,
+ next_commit_ID, info);
+ if (err)
+ goto failed;
+@@ -923,8 +956,9 @@ static int do_one_pass(journal_t *journal,
+
+ /* Scan a revoke record, marking all blocks mentioned as revoked. */
+
+-static int scan_revoke_records(journal_t *journal, struct buffer_head *bh,
+- tid_t sequence, struct recovery_info *info)
++static int scan_revoke_records(journal_t *journal, enum passtype pass,
++ struct buffer_head *bh, tid_t sequence,
++ struct recovery_info *info)
+ {
+ jbd2_journal_revoke_header_t *header;
+ int offset, max;
+@@ -945,6 +979,11 @@ static int scan_revoke_records(journal_t *journal, struct buffer_head *bh,
+ if (jbd2_has_feature_64bit(journal))
+ record_len = 8;
+
++ if (pass == PASS_SCAN) {
++ info->nr_revokes += (max - offset) / record_len;
++ return 0;
++ }
++
+ while (offset + record_len <= max) {
+ unsigned long long blocknr;
+ int err;
+@@ -957,7 +996,6 @@ static int scan_revoke_records(journal_t *journal, struct buffer_head *bh,
+ err = jbd2_journal_set_revoke(journal, blocknr, sequence);
+ if (err)
+ return err;
+- ++info->nr_revokes;
+ }
+ return 0;
+ }
+diff --git a/fs/jbd2/revoke.c b/fs/jbd2/revoke.c
+index f68fc8c255f00..bc328c39028a2 100644
+--- a/fs/jbd2/revoke.c
++++ b/fs/jbd2/revoke.c
+@@ -215,7 +215,7 @@ int __init jbd2_journal_init_revoke_table_cache(void)
+ return 0;
+ }
+
+-static struct jbd2_revoke_table_s *jbd2_journal_init_revoke_table(int hash_size)
++struct jbd2_revoke_table_s *jbd2_journal_init_revoke_table(int hash_size)
+ {
+ int shift = 0;
+ int tmp = hash_size;
+@@ -231,7 +231,7 @@ static struct jbd2_revoke_table_s *jbd2_journal_init_revoke_table(int hash_size)
+ table->hash_size = hash_size;
+ table->hash_shift = shift;
+ table->hash_table =
+- kmalloc_array(hash_size, sizeof(struct list_head), GFP_KERNEL);
++ kvmalloc_array(hash_size, sizeof(struct list_head), GFP_KERNEL);
+ if (!table->hash_table) {
+ kmem_cache_free(jbd2_revoke_table_cache, table);
+ table = NULL;
+@@ -245,7 +245,7 @@ static struct jbd2_revoke_table_s *jbd2_journal_init_revoke_table(int hash_size)
+ return table;
+ }
+
+-static void jbd2_journal_destroy_revoke_table(struct jbd2_revoke_table_s *table)
++void jbd2_journal_destroy_revoke_table(struct jbd2_revoke_table_s *table)
+ {
+ int i;
+ struct list_head *hash_list;
+@@ -255,7 +255,7 @@ static void jbd2_journal_destroy_revoke_table(struct jbd2_revoke_table_s *table)
+ J_ASSERT(list_empty(hash_list));
+ }
+
+- kfree(table->hash_table);
++ kvfree(table->hash_table);
+ kmem_cache_free(jbd2_revoke_table_cache, table);
+ }
+
+diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
+index 561025b4f3d91..469c4a191ced4 100644
+--- a/include/linux/jbd2.h
++++ b/include/linux/jbd2.h
+@@ -1627,6 +1627,8 @@ extern void jbd2_journal_destroy_revoke_record_cache(void);
+ extern void jbd2_journal_destroy_revoke_table_cache(void);
+ extern int __init jbd2_journal_init_revoke_record_cache(void);
+ extern int __init jbd2_journal_init_revoke_table_cache(void);
++struct jbd2_revoke_table_s *jbd2_journal_init_revoke_table(int hash_size);
++void jbd2_journal_destroy_revoke_table(struct jbd2_revoke_table_s *table);
+
+ extern void jbd2_journal_destroy_revoke(journal_t *);
+ extern int jbd2_journal_revoke (handle_t *, unsigned long long, struct buffer_head *);
+--
+2.39.5
+
--- /dev/null
+From fb48a39902a8435ed8f6c8b25cf9a908eeedaf68 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Feb 2025 10:46:59 +0100
+Subject: jbd2: do not try to recover wiped journal
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit a662f3c03b754e1f97a2781fa242e95bdb139798 ]
+
+If a journal is wiped, we will set journal->j_tail to 0. However if
+'write' argument is not set (as it happens for read-only device or for
+ocfs2), the on-disk superblock is not updated accordingly and thus
+jbd2_journal_recover() cat try to recover the wiped journal. Fix the
+check in jbd2_journal_recover() to use journal->j_tail for checking
+empty journal instead.
+
+Signed-off-by: Jan Kara <jack@suse.cz>
+Reviewed-by: Zhang Yi <yi.zhang@huawei.com>
+Link: https://patch.msgid.link/20250206094657.20865-4-jack@suse.cz
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/jbd2/recovery.c | 11 ++++++-----
+ 1 file changed, 6 insertions(+), 5 deletions(-)
+
+diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c
+index 9192be7c19d83..23502f1a67c1e 100644
+--- a/fs/jbd2/recovery.c
++++ b/fs/jbd2/recovery.c
+@@ -287,19 +287,20 @@ static int fc_do_one_pass(journal_t *journal,
+ int jbd2_journal_recover(journal_t *journal)
+ {
+ int err, err2;
+- journal_superblock_t * sb;
+-
+ struct recovery_info info;
+
+ memset(&info, 0, sizeof(info));
+- sb = journal->j_superblock;
+
+ /*
+ * The journal superblock's s_start field (the current log head)
+ * is always zero if, and only if, the journal was cleanly
+- * unmounted.
++ * unmounted. We use its in-memory version j_tail here because
++ * jbd2_journal_wipe() could have updated it without updating journal
++ * superblock.
+ */
+- if (!sb->s_start) {
++ if (!journal->j_tail) {
++ journal_superblock_t *sb = journal->j_superblock;
++
+ jbd2_debug(1, "No recovery required, last transaction %d, head block %u\n",
+ be32_to_cpu(sb->s_sequence), be32_to_cpu(sb->s_head));
+ journal->j_transaction_sequence = be32_to_cpu(sb->s_sequence) + 1;
+--
+2.39.5
+
--- /dev/null
+From 263e13e92e5055130e16ab28f467361a77bfd428 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 1 Mar 2025 17:21:37 -0500
+Subject: kbuild: fix argument parsing in scripts/config
+
+From: Seyediman Seyedarab <imandevel@gmail.com>
+
+[ Upstream commit f757f6011c92b5a01db742c39149bed9e526478f ]
+
+The script previously assumed --file was always the first argument,
+which caused issues when it appeared later. This patch updates the
+parsing logic to scan all arguments to find --file, sets the config
+file correctly, and resets the argument list with the remaining
+commands.
+
+It also fixes --refresh to respect --file by passing KCONFIG_CONFIG=$FN
+to make oldconfig.
+
+Signed-off-by: Seyediman Seyedarab <imandevel@gmail.com>
+Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ scripts/config | 26 ++++++++++++++++----------
+ 1 file changed, 16 insertions(+), 10 deletions(-)
+
+diff --git a/scripts/config b/scripts/config
+index ff88e2faefd35..ea475c07de283 100755
+--- a/scripts/config
++++ b/scripts/config
+@@ -32,6 +32,7 @@ commands:
+ Disable option directly after other option
+ --module-after|-M beforeopt option
+ Turn option into module directly after other option
++ --refresh Refresh the config using old settings
+
+ commands can be repeated multiple times
+
+@@ -124,16 +125,22 @@ undef_var() {
+ txt_delete "^# $name is not set" "$FN"
+ }
+
+-if [ "$1" = "--file" ]; then
+- FN="$2"
+- if [ "$FN" = "" ] ; then
+- usage
++FN=.config
++CMDS=()
++while [[ $# -gt 0 ]]; do
++ if [ "$1" = "--file" ]; then
++ if [ "$2" = "" ]; then
++ usage
++ fi
++ FN="$2"
++ shift 2
++ else
++ CMDS+=("$1")
++ shift
+ fi
+- shift 2
+-else
+- FN=.config
+-fi
++done
+
++set -- "${CMDS[@]}"
+ if [ "$1" = "" ] ; then
+ usage
+ fi
+@@ -217,9 +224,8 @@ while [ "$1" != "" ] ; do
+ set_var "${CONFIG_}$B" "${CONFIG_}$B=m" "${CONFIG_}$A"
+ ;;
+
+- # undocumented because it ignores --file (fixme)
+ --refresh)
+- yes "" | make oldconfig
++ yes "" | make oldconfig KCONFIG_CONFIG=$FN
+ ;;
+
+ *)
+--
+2.39.5
+
--- /dev/null
+From 5c7426336e9a3df6682ed3ded767f16d3ea49c92 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 8 Feb 2025 03:41:55 +0900
+Subject: kconfig: do not clear SYMBOL_VALID when reading
+ include/config/auto.conf
+
+From: Masahiro Yamada <masahiroy@kernel.org>
+
+[ Upstream commit 226ac19c217f24f0927d0a73cf9ee613971a188d ]
+
+When conf_read_simple() is called with S_DEF_AUTO, it is meant to read
+previous symbol values from include/config/auto.conf to determine which
+include/config/* files should be touched.
+
+This process should not modify the current symbol status in any way.
+However, conf_touch_deps() currently invalidates all symbol values and
+recalculates them, which is totally unneeded.
+
+Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ scripts/kconfig/confdata.c | 19 ++++++++++++-------
+ 1 file changed, 12 insertions(+), 7 deletions(-)
+
+diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c
+index 3b55e7a4131d9..ac95661a1c9dd 100644
+--- a/scripts/kconfig/confdata.c
++++ b/scripts/kconfig/confdata.c
+@@ -385,7 +385,7 @@ int conf_read_simple(const char *name, int def)
+
+ def_flags = SYMBOL_DEF << def;
+ for_all_symbols(sym) {
+- sym->flags &= ~(def_flags|SYMBOL_VALID);
++ sym->flags &= ~def_flags;
+ switch (sym->type) {
+ case S_INT:
+ case S_HEX:
+@@ -398,7 +398,11 @@ int conf_read_simple(const char *name, int def)
+ }
+ }
+
+- expr_invalidate_all();
++ if (def == S_DEF_USER) {
++ for_all_symbols(sym)
++ sym->flags &= ~SYMBOL_VALID;
++ expr_invalidate_all();
++ }
+
+ while (getline_stripped(&line, &line_asize, in) != -1) {
+ struct menu *choice;
+@@ -464,6 +468,9 @@ int conf_read_simple(const char *name, int def)
+ if (conf_set_sym_val(sym, def, def_flags, val))
+ continue;
+
++ if (def != S_DEF_USER)
++ continue;
++
+ /*
+ * If this is a choice member, give it the highest priority.
+ * If conflicting CONFIG options are given from an input file,
+@@ -967,10 +974,8 @@ static int conf_touch_deps(void)
+ depfile_path[depfile_prefix_len] = 0;
+
+ conf_read_simple(name, S_DEF_AUTO);
+- sym_calc_value(modules_sym);
+
+ for_all_symbols(sym) {
+- sym_calc_value(sym);
+ if (sym_is_choice(sym))
+ continue;
+ if (sym->flags & SYMBOL_WRITE) {
+@@ -1084,12 +1089,12 @@ int conf_write_autoconf(int overwrite)
+ if (ret)
+ return -1;
+
+- if (conf_touch_deps())
+- return 1;
+-
+ for_all_symbols(sym)
+ sym_calc_value(sym);
+
++ if (conf_touch_deps())
++ return 1;
++
+ ret = __conf_write_autoconf(conf_get_autoheader_name(),
+ print_symbol_for_c,
+ &comment_style_c);
+--
+2.39.5
+
--- /dev/null
+From 21609391f804ae146dc39b5a6bf57a982fba933a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 28 Mar 2025 14:28:37 +0000
+Subject: kconfig: merge_config: use an empty file as initfile
+
+From: Daniel Gomez <da.gomez@samsung.com>
+
+[ Upstream commit a26fe287eed112b4e21e854f173c8918a6a8596d ]
+
+The scripts/kconfig/merge_config.sh script requires an existing
+$INITFILE (or the $1 argument) as a base file for merging Kconfig
+fragments. However, an empty $INITFILE can serve as an initial starting
+point, later referenced by the KCONFIG_ALLCONFIG Makefile variable
+if -m is not used. This variable can point to any configuration file
+containing preset config symbols (the merged output) as stated in
+Documentation/kbuild/kconfig.rst. When -m is used $INITFILE will
+contain just the merge output requiring the user to run make (i.e.
+KCONFIG_ALLCONFIG=<$INITFILE> make <allnoconfig/alldefconfig> or make
+olddefconfig).
+
+Instead of failing when `$INITFILE` is missing, create an empty file and
+use it as the starting point for merges.
+
+Signed-off-by: Daniel Gomez <da.gomez@samsung.com>
+Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ scripts/kconfig/merge_config.sh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/scripts/kconfig/merge_config.sh b/scripts/kconfig/merge_config.sh
+index 0b7952471c18f..79c09b378be81 100755
+--- a/scripts/kconfig/merge_config.sh
++++ b/scripts/kconfig/merge_config.sh
+@@ -112,8 +112,8 @@ INITFILE=$1
+ shift;
+
+ if [ ! -r "$INITFILE" ]; then
+- echo "The base file '$INITFILE' does not exist. Exit." >&2
+- exit 1
++ echo "The base file '$INITFILE' does not exist. Creating one..." >&2
++ touch "$INITFILE"
+ fi
+
+ MERGE_LIST=$*
+--
+2.39.5
+
--- /dev/null
+From 25a717297c69bf728ca7ef85fdfae89a520d5f2d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 13 Feb 2025 15:50:19 +0100
+Subject: kernfs: Acquire kernfs_rwsem in kernfs_get_parent_dentry().
+
+From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+
+[ Upstream commit 122ab92dee80582c39740609a627198dd5b6b595 ]
+
+kernfs_get_parent_dentry() passes kernfs_node::parent to
+kernfs_get_inode().
+
+Acquire kernfs_root::kernfs_rwsem to ensure kernfs_node::parent isn't
+replaced during the operation.
+
+Acked-by: Tejun Heo <tj@kernel.org>
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Link: https://lore.kernel.org/r/20250213145023.2820193-3-bigeasy@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/kernfs/mount.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c
+index 0f6379ae258d1..4a0ff08d589ca 100644
+--- a/fs/kernfs/mount.c
++++ b/fs/kernfs/mount.c
+@@ -145,7 +145,9 @@ static struct dentry *kernfs_fh_to_parent(struct super_block *sb,
+ static struct dentry *kernfs_get_parent_dentry(struct dentry *child)
+ {
+ struct kernfs_node *kn = kernfs_dentry_node(child);
++ struct kernfs_root *root = kernfs_root(kn);
+
++ guard(rwsem_read)(&root->kernfs_rwsem);
+ return d_obtain_alias(kernfs_get_inode(child->d_sb, kn->parent));
+ }
+
+--
+2.39.5
+
--- /dev/null
+From f6f132bdcac41f2b42619efd69a1112b6a5a2dde Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 13 Feb 2025 15:50:20 +0100
+Subject: kernfs: Acquire kernfs_rwsem in kernfs_node_dentry().
+
+From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+
+[ Upstream commit 5b2fabf7fe8f745ff214ff003e6067b64f172271 ]
+
+kernfs_node_dentry() passes kernfs_node::name to
+lookup_positive_unlocked().
+
+Acquire kernfs_root::kernfs_rwsem to ensure the node is not renamed
+during the operation.
+
+Acked-by: Tejun Heo <tj@kernel.org>
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Link: https://lore.kernel.org/r/20250213145023.2820193-4-bigeasy@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/kernfs/mount.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c
+index 1358c21837f1a..0f6379ae258d1 100644
+--- a/fs/kernfs/mount.c
++++ b/fs/kernfs/mount.c
+@@ -207,6 +207,7 @@ struct dentry *kernfs_node_dentry(struct kernfs_node *kn,
+ {
+ struct dentry *dentry;
+ struct kernfs_node *knparent;
++ struct kernfs_root *root;
+
+ BUG_ON(sb->s_op != &kernfs_sops);
+
+@@ -216,6 +217,9 @@ struct dentry *kernfs_node_dentry(struct kernfs_node *kn,
+ if (!kn->parent)
+ return dentry;
+
++ root = kernfs_root(kn);
++ guard(rwsem_read)(&root->kernfs_rwsem);
++
+ knparent = find_next_ancestor(kn, NULL);
+ if (WARN_ON(!knparent)) {
+ dput(dentry);
+--
+2.39.5
+
--- /dev/null
+From c004b9f6c4df78b795678226de60856ef13ca3ca Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 13 Feb 2025 15:50:18 +0100
+Subject: kernfs: Acquire kernfs_rwsem in kernfs_notify_workfn().
+
+From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+
+[ Upstream commit 400188ae361a9d9a72a47a6cedaf2d2efcc84aa8 ]
+
+kernfs_notify_workfn() dereferences kernfs_node::name and passes it
+later to fsnotify(). If the node is renamed then the previously observed
+name pointer becomes invalid.
+
+Acquire kernfs_root::kernfs_rwsem to block renames of the node.
+
+Acked-by: Tejun Heo <tj@kernel.org>
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Link: https://lore.kernel.org/r/20250213145023.2820193-2-bigeasy@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/kernfs/file.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c
+index 0eb320617d7b1..c4ffa8dc89ebc 100644
+--- a/fs/kernfs/file.c
++++ b/fs/kernfs/file.c
+@@ -911,6 +911,7 @@ static void kernfs_notify_workfn(struct work_struct *work)
+ /* kick fsnotify */
+
+ down_read(&root->kernfs_supers_rwsem);
++ down_read(&root->kernfs_rwsem);
+ list_for_each_entry(info, &kernfs_root(kn)->supers, node) {
+ struct kernfs_node *parent;
+ struct inode *p_inode = NULL;
+@@ -947,6 +948,7 @@ static void kernfs_notify_workfn(struct work_struct *work)
+ iput(inode);
+ }
+
++ up_read(&root->kernfs_rwsem);
+ up_read(&root->kernfs_supers_rwsem);
+ kernfs_put(kn);
+ goto repeat;
+--
+2.39.5
+
--- /dev/null
+From d207a5442668cab762f65cae33b30cc749ede28e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 13 Feb 2025 15:50:21 +0100
+Subject: kernfs: Don't re-lock kernfs_root::kernfs_rwsem in
+ kernfs_fop_readdir().
+
+From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+
+[ Upstream commit 9aab10a0249eab4ec77c6a5e4f66442610c12a09 ]
+
+The readdir operation iterates over all entries and invokes dir_emit()
+for every entry passing kernfs_node::name as argument.
+Since the name argument can change, and become invalid, the
+kernfs_root::kernfs_rwsem lock should not be dropped to prevent renames
+during the operation.
+
+The lock drop around dir_emit() has been initially introduced in commit
+ 1e5289c97bba2 ("sysfs: Cache the last sysfs_dirent to improve readdir scalability v2")
+
+to avoid holding a global lock during a page fault. The lock drop is
+wrong since the support of renames and not a big burden since the lock
+is no longer global.
+
+Don't re-acquire kernfs_root::kernfs_rwsem while copying the name to the
+userpace buffer.
+
+Acked-by: Tejun Heo <tj@kernel.org>
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Link: https://lore.kernel.org/r/20250213145023.2820193-5-bigeasy@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/kernfs/dir.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
+index 5f0f8b95f44c0..43fbada678381 100644
+--- a/fs/kernfs/dir.c
++++ b/fs/kernfs/dir.c
+@@ -1869,10 +1869,10 @@ static int kernfs_fop_readdir(struct file *file, struct dir_context *ctx)
+ file->private_data = pos;
+ kernfs_get(pos);
+
+- up_read(&root->kernfs_rwsem);
+- if (!dir_emit(ctx, name, len, ino, type))
++ if (!dir_emit(ctx, name, len, ino, type)) {
++ up_read(&root->kernfs_rwsem);
+ return 0;
+- down_read(&root->kernfs_rwsem);
++ }
+ }
+ up_read(&root->kernfs_rwsem);
+ file->private_data = NULL;
+--
+2.39.5
+
--- /dev/null
+From a19c98bbfce95b52ef574173a1be3cbe45aa0ad0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Feb 2025 17:39:38 +0100
+Subject: kernfs: Drop kernfs_rwsem while invoking lookup_positive_unlocked().
+
+From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+
+[ Upstream commit 6ef5b6fae304091593956be59065c0c8633ad9e8 ]
+
+syzbot reported two warnings:
+- kernfs_node::name was accessed outside of a RCU section so it created
+ warning. The kernfs_rwsem was held so it was okay but it wasn't seen.
+
+- While kernfs_rwsem was held invoked lookup_positive_unlocked()->
+ kernfs_dop_revalidate() which acquired kernfs_rwsem.
+
+kernfs_rwsem was both acquired as a read lock so it can be acquired
+twice. However if a writer acquires the lock after the first reader then
+neither the writer nor the second reader can obtain the lock so it
+deadlocks.
+
+The reason for the lock is to ensure that kernfs_node::name remain
+stable during lookup_positive_unlocked()'s invocation. The function can
+not be invoked within a RCU section because it may sleep.
+
+Make a temporary copy of the kernfs_node::name under the lock so
+GFP_KERNEL can be used and use this instead.
+
+Reported-by: syzbot+ecccecbc636b455f9084@syzkaller.appspotmail.com
+Fixes: 5b2fabf7fe8f ("kernfs: Acquire kernfs_rwsem in kernfs_node_dentry().")
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Acked-by: Tejun Heo <tj@kernel.org>
+Link: https://lore.kernel.org/r/20250218163938.xmvjlJ0K@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/kernfs/mount.c | 33 ++++++++++++++++++++++++---------
+ 1 file changed, 24 insertions(+), 9 deletions(-)
+
+diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c
+index d1f512b7bf867..f1cea282aae32 100644
+--- a/fs/kernfs/mount.c
++++ b/fs/kernfs/mount.c
+@@ -220,12 +220,19 @@ struct dentry *kernfs_node_dentry(struct kernfs_node *kn,
+ return dentry;
+
+ root = kernfs_root(kn);
+- guard(rwsem_read)(&root->kernfs_rwsem);
+-
+- knparent = find_next_ancestor(kn, NULL);
+- if (WARN_ON(!knparent)) {
+- dput(dentry);
++ /*
++ * As long as kn is valid, its parent can not vanish. This is cgroup's
++ * kn so it not have its parent replaced. Therefore it is safe to use
++ * the ancestor node outside of the RCU or locked section.
++ */
++ if (WARN_ON_ONCE(!(root->flags & KERNFS_ROOT_INVARIANT_PARENT)))
+ return ERR_PTR(-EINVAL);
++ scoped_guard(rcu) {
++ knparent = find_next_ancestor(kn, NULL);
++ if (WARN_ON(!knparent)) {
++ dput(dentry);
++ return ERR_PTR(-EINVAL);
++ }
+ }
+
+ do {
+@@ -235,14 +242,22 @@ struct dentry *kernfs_node_dentry(struct kernfs_node *kn,
+
+ if (kn == knparent)
+ return dentry;
+- kntmp = find_next_ancestor(kn, knparent);
+- if (WARN_ON(!kntmp)) {
++
++ scoped_guard(rwsem_read, &root->kernfs_rwsem) {
++ kntmp = find_next_ancestor(kn, knparent);
++ if (WARN_ON(!kntmp)) {
++ dput(dentry);
++ return ERR_PTR(-EINVAL);
++ }
++ name = kstrdup(kernfs_rcu_name(kntmp), GFP_KERNEL);
++ }
++ if (!name) {
+ dput(dentry);
+- return ERR_PTR(-EINVAL);
++ return ERR_PTR(-ENOMEM);
+ }
+- name = rcu_dereference(kntmp->name);
+ dtmp = lookup_positive_unlocked(name, dentry, strlen(name));
+ dput(dentry);
++ kfree(name);
+ if (IS_ERR(dtmp))
+ return dtmp;
+ knparent = kntmp;
+--
+2.39.5
+
--- /dev/null
+From 8e1b2461023eba183fce8c2b3ef54a3e6b6eb056 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 13 Feb 2025 15:50:23 +0100
+Subject: kernfs: Use RCU to access kernfs_node::name.
+
+From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+
+[ Upstream commit 741c10b096bc4dd79cd9f215b6ef173bb953e75c ]
+
+Using RCU lifetime rules to access kernfs_node::name can avoid the
+trouble with kernfs_rename_lock in kernfs_name() and kernfs_path_from_node()
+if the fs was created with KERNFS_ROOT_INVARIANT_PARENT. This is usefull
+as it allows to implement kernfs_path_from_node() only with RCU
+protection and avoiding kernfs_rename_lock. The lock is only required if
+the __parent node can be changed and the function requires an unchanged
+hierarchy while it iterates from the node to its parent.
+The change is needed to allow the lookup of the node's path
+(kernfs_path_from_node()) from context which runs always with disabled
+preemption and or interrutps even on PREEMPT_RT. The problem is that
+kernfs_rename_lock becomes a sleeping lock on PREEMPT_RT.
+
+I went through all ::name users and added the required access for the lookup
+with a few extensions:
+- rdtgroup_pseudo_lock_create() drops all locks and then uses the name
+ later on. resctrl supports rename with different parents. Here I made
+ a temporal copy of the name while it is used outside of the lock.
+
+- kernfs_rename_ns() accepts NULL as new_parent. This simplifies
+ sysfs_move_dir_ns() where it can set NULL in order to reuse the current
+ name.
+
+- kernfs_rename_ns() is only using kernfs_rename_lock if the parents are
+ different. All users use either kernfs_rwsem (for stable path view) or
+ just RCU for the lookup. The ::name uses always RCU free.
+
+Use RCU lifetime guarantees to access kernfs_node::name.
+
+Suggested-by: Tejun Heo <tj@kernel.org>
+Acked-by: Tejun Heo <tj@kernel.org>
+Reported-by: syzbot+6ea37e2e6ffccf41a7e6@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/lkml/67251dc6.050a0220.529b6.015e.GAE@google.com/
+Reported-by: Hillf Danton <hdanton@sina.com>
+Closes: https://lore.kernel.org/20241102001224.2789-1-hdanton@sina.com
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Link: https://lore.kernel.org/r/20250213145023.2820193-7-bigeasy@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: 6ef5b6fae304 ("kernfs: Drop kernfs_rwsem while invoking lookup_positive_unlocked().")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/kernel/cpu/resctrl/internal.h | 5 +
+ arch/x86/kernel/cpu/resctrl/pseudo_lock.c | 14 ++-
+ arch/x86/kernel/cpu/resctrl/rdtgroup.c | 10 +-
+ fs/kernfs/dir.c | 113 ++++++++++++----------
+ fs/kernfs/file.c | 4 +-
+ fs/kernfs/kernfs-internal.h | 5 +
+ fs/kernfs/mount.c | 5 +-
+ fs/kernfs/symlink.c | 7 +-
+ fs/sysfs/dir.c | 2 +-
+ include/linux/kernfs.h | 4 +-
+ security/selinux/hooks.c | 7 +-
+ 11 files changed, 105 insertions(+), 71 deletions(-)
+
+diff --git a/arch/x86/kernel/cpu/resctrl/internal.h b/arch/x86/kernel/cpu/resctrl/internal.h
+index 20c898f09b7e7..dd5d6b4bfcc22 100644
+--- a/arch/x86/kernel/cpu/resctrl/internal.h
++++ b/arch/x86/kernel/cpu/resctrl/internal.h
+@@ -507,6 +507,11 @@ int parse_bw(struct rdt_parse_data *data, struct resctrl_schema *s,
+
+ extern struct mutex rdtgroup_mutex;
+
++static inline const char *rdt_kn_name(const struct kernfs_node *kn)
++{
++ return rcu_dereference_check(kn->name, lockdep_is_held(&rdtgroup_mutex));
++}
++
+ extern struct rdt_hw_resource rdt_resources_all[];
+ extern struct rdtgroup rdtgroup_default;
+ extern struct dentry *debugfs_resctrl;
+diff --git a/arch/x86/kernel/cpu/resctrl/pseudo_lock.c b/arch/x86/kernel/cpu/resctrl/pseudo_lock.c
+index 42cc162f7fc91..7a2db7fa41083 100644
+--- a/arch/x86/kernel/cpu/resctrl/pseudo_lock.c
++++ b/arch/x86/kernel/cpu/resctrl/pseudo_lock.c
+@@ -52,7 +52,8 @@ static char *pseudo_lock_devnode(const struct device *dev, umode_t *mode)
+ rdtgrp = dev_get_drvdata(dev);
+ if (mode)
+ *mode = 0600;
+- return kasprintf(GFP_KERNEL, "pseudo_lock/%s", rdtgrp->kn->name);
++ guard(mutex)(&rdtgroup_mutex);
++ return kasprintf(GFP_KERNEL, "pseudo_lock/%s", rdt_kn_name(rdtgrp->kn));
+ }
+
+ static const struct class pseudo_lock_class = {
+@@ -1293,6 +1294,7 @@ int rdtgroup_pseudo_lock_create(struct rdtgroup *rdtgrp)
+ struct task_struct *thread;
+ unsigned int new_minor;
+ struct device *dev;
++ char *kn_name __free(kfree) = NULL;
+ int ret;
+
+ ret = pseudo_lock_region_alloc(plr);
+@@ -1304,6 +1306,11 @@ int rdtgroup_pseudo_lock_create(struct rdtgroup *rdtgrp)
+ ret = -EINVAL;
+ goto out_region;
+ }
++ kn_name = kstrdup(rdt_kn_name(rdtgrp->kn), GFP_KERNEL);
++ if (!kn_name) {
++ ret = -ENOMEM;
++ goto out_cstates;
++ }
+
+ plr->thread_done = 0;
+
+@@ -1348,8 +1355,7 @@ int rdtgroup_pseudo_lock_create(struct rdtgroup *rdtgrp)
+ mutex_unlock(&rdtgroup_mutex);
+
+ if (!IS_ERR_OR_NULL(debugfs_resctrl)) {
+- plr->debugfs_dir = debugfs_create_dir(rdtgrp->kn->name,
+- debugfs_resctrl);
++ plr->debugfs_dir = debugfs_create_dir(kn_name, debugfs_resctrl);
+ if (!IS_ERR_OR_NULL(plr->debugfs_dir))
+ debugfs_create_file("pseudo_lock_measure", 0200,
+ plr->debugfs_dir, rdtgrp,
+@@ -1358,7 +1364,7 @@ int rdtgroup_pseudo_lock_create(struct rdtgroup *rdtgrp)
+
+ dev = device_create(&pseudo_lock_class, NULL,
+ MKDEV(pseudo_lock_major, new_minor),
+- rdtgrp, "%s", rdtgrp->kn->name);
++ rdtgrp, "%s", kn_name);
+
+ mutex_lock(&rdtgroup_mutex);
+
+diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c
+index 3d2a850ea737d..1f769d819a864 100644
+--- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c
++++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c
+@@ -917,14 +917,14 @@ int proc_resctrl_show(struct seq_file *s, struct pid_namespace *ns,
+ continue;
+
+ seq_printf(s, "res:%s%s\n", (rdtg == &rdtgroup_default) ? "/" : "",
+- rdtg->kn->name);
++ rdt_kn_name(rdtg->kn));
+ seq_puts(s, "mon:");
+ list_for_each_entry(crg, &rdtg->mon.crdtgrp_list,
+ mon.crdtgrp_list) {
+ if (!resctrl_arch_match_rmid(tsk, crg->mon.parent->closid,
+ crg->mon.rmid))
+ continue;
+- seq_printf(s, "%s", crg->kn->name);
++ seq_printf(s, "%s", rdt_kn_name(crg->kn));
+ break;
+ }
+ seq_putc(s, '\n');
+@@ -3676,7 +3676,7 @@ static int rdtgroup_mkdir_ctrl_mon(struct kernfs_node *parent_kn,
+ */
+ static bool is_mon_groups(struct kernfs_node *kn, const char *name)
+ {
+- return (!strcmp(kn->name, "mon_groups") &&
++ return (!strcmp(rdt_kn_name(kn), "mon_groups") &&
+ strcmp(name, "mon_groups"));
+ }
+
+@@ -3825,7 +3825,7 @@ static int rdtgroup_rmdir(struct kernfs_node *kn)
+ ret = rdtgroup_rmdir_ctrl(rdtgrp, tmpmask);
+ }
+ } else if (rdtgrp->type == RDTMON_GROUP &&
+- is_mon_groups(parent_kn, kn->name)) {
++ is_mon_groups(parent_kn, rdt_kn_name(kn))) {
+ ret = rdtgroup_rmdir_mon(rdtgrp, tmpmask);
+ } else {
+ ret = -EPERM;
+@@ -3913,7 +3913,7 @@ static int rdtgroup_rename(struct kernfs_node *kn,
+
+ kn_parent = rdt_kn_parent(kn);
+ if (rdtgrp->type != RDTMON_GROUP || !kn_parent ||
+- !is_mon_groups(kn_parent, kn->name)) {
++ !is_mon_groups(kn_parent, rdt_kn_name(kn))) {
+ rdt_last_cmd_puts("Source must be a MON group\n");
+ ret = -EPERM;
+ goto out;
+diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
+index 1d370c497e8a3..c5a578c46759a 100644
+--- a/fs/kernfs/dir.c
++++ b/fs/kernfs/dir.c
+@@ -51,14 +51,6 @@ static bool kernfs_lockdep(struct kernfs_node *kn)
+ #endif
+ }
+
+-static int kernfs_name_locked(struct kernfs_node *kn, char *buf, size_t buflen)
+-{
+- if (!kn)
+- return strscpy(buf, "(null)", buflen);
+-
+- return strscpy(buf, rcu_access_pointer(kn->__parent) ? kn->name : "/", buflen);
+-}
+-
+ /* kernfs_node_depth - compute depth from @from to @to */
+ static size_t kernfs_depth(struct kernfs_node *from, struct kernfs_node *to)
+ {
+@@ -168,11 +160,13 @@ static int kernfs_path_from_node_locked(struct kernfs_node *kn_to,
+
+ /* Calculate how many bytes we need for the rest */
+ for (i = depth_to - 1; i >= 0; i--) {
++ const char *name;
+
+ for (kn = kn_to, j = 0; j < i; j++)
+ kn = rcu_dereference(kn->__parent);
+
+- len += scnprintf(buf + len, buflen - len, "/%s", kn->name);
++ name = rcu_dereference(kn->name);
++ len += scnprintf(buf + len, buflen - len, "/%s", name);
+ }
+
+ return len;
+@@ -196,13 +190,18 @@ static int kernfs_path_from_node_locked(struct kernfs_node *kn_to,
+ */
+ int kernfs_name(struct kernfs_node *kn, char *buf, size_t buflen)
+ {
+- unsigned long flags;
+- int ret;
++ struct kernfs_node *kn_parent;
+
+- read_lock_irqsave(&kernfs_rename_lock, flags);
+- ret = kernfs_name_locked(kn, buf, buflen);
+- read_unlock_irqrestore(&kernfs_rename_lock, flags);
+- return ret;
++ if (!kn)
++ return strscpy(buf, "(null)", buflen);
++
++ guard(rcu)();
++ /*
++ * KERNFS_ROOT_INVARIANT_PARENT is ignored here. The name is RCU freed and
++ * the parent is either existing or not.
++ */
++ kn_parent = rcu_dereference(kn->__parent);
++ return strscpy(buf, kn_parent ? rcu_dereference(kn->name) : "/", buflen);
+ }
+
+ /**
+@@ -224,14 +223,17 @@ int kernfs_name(struct kernfs_node *kn, char *buf, size_t buflen)
+ int kernfs_path_from_node(struct kernfs_node *to, struct kernfs_node *from,
+ char *buf, size_t buflen)
+ {
+- unsigned long flags;
+- int ret;
++ struct kernfs_root *root;
+
+ guard(rcu)();
+- read_lock_irqsave(&kernfs_rename_lock, flags);
+- ret = kernfs_path_from_node_locked(to, from, buf, buflen);
+- read_unlock_irqrestore(&kernfs_rename_lock, flags);
+- return ret;
++ if (to) {
++ root = kernfs_root(to);
++ if (!(root->flags & KERNFS_ROOT_INVARIANT_PARENT)) {
++ guard(read_lock_irqsave)(&kernfs_rename_lock);
++ return kernfs_path_from_node_locked(to, from, buf, buflen);
++ }
++ }
++ return kernfs_path_from_node_locked(to, from, buf, buflen);
+ }
+ EXPORT_SYMBOL_GPL(kernfs_path_from_node);
+
+@@ -338,13 +340,13 @@ static int kernfs_name_compare(unsigned int hash, const char *name,
+ return -1;
+ if (ns > kn->ns)
+ return 1;
+- return strcmp(name, kn->name);
++ return strcmp(name, kernfs_rcu_name(kn));
+ }
+
+ static int kernfs_sd_compare(const struct kernfs_node *left,
+ const struct kernfs_node *right)
+ {
+- return kernfs_name_compare(left->hash, left->name, left->ns, right);
++ return kernfs_name_compare(left->hash, kernfs_rcu_name(left), left->ns, right);
+ }
+
+ /**
+@@ -542,7 +544,8 @@ static void kernfs_free_rcu(struct rcu_head *rcu)
+ {
+ struct kernfs_node *kn = container_of(rcu, struct kernfs_node, rcu);
+
+- kfree_const(kn->name);
++ /* If the whole node goes away, then name can't be used outside */
++ kfree_const(rcu_access_pointer(kn->name));
+
+ if (kn->iattr) {
+ simple_xattrs_free(&kn->iattr->xattrs, NULL);
+@@ -575,7 +578,8 @@ void kernfs_put(struct kernfs_node *kn)
+
+ WARN_ONCE(atomic_read(&kn->active) != KN_DEACTIVATED_BIAS,
+ "kernfs_put: %s/%s: released with incorrect active_ref %d\n",
+- parent ? parent->name : "", kn->name, atomic_read(&kn->active));
++ parent ? rcu_dereference(parent->name) : "",
++ rcu_dereference(kn->name), atomic_read(&kn->active));
+
+ if (kernfs_type(kn) == KERNFS_LINK)
+ kernfs_put(kn->symlink.target_kn);
+@@ -652,7 +656,7 @@ static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root,
+ atomic_set(&kn->active, KN_DEACTIVATED_BIAS);
+ RB_CLEAR_NODE(&kn->rb);
+
+- kn->name = name;
++ rcu_assign_pointer(kn->name, name);
+ kn->mode = mode;
+ kn->flags = flags;
+
+@@ -790,7 +794,8 @@ int kernfs_add_one(struct kernfs_node *kn)
+ ret = -EINVAL;
+ has_ns = kernfs_ns_enabled(parent);
+ if (WARN(has_ns != (bool)kn->ns, KERN_WARNING "kernfs: ns %s in '%s' for '%s'\n",
+- has_ns ? "required" : "invalid", parent->name, kn->name))
++ has_ns ? "required" : "invalid",
++ kernfs_rcu_name(parent), kernfs_rcu_name(kn)))
+ goto out_unlock;
+
+ if (kernfs_type(parent) != KERNFS_DIR)
+@@ -800,7 +805,7 @@ int kernfs_add_one(struct kernfs_node *kn)
+ if (parent->flags & (KERNFS_REMOVING | KERNFS_EMPTY_DIR))
+ goto out_unlock;
+
+- kn->hash = kernfs_name_hash(kn->name, kn->ns);
++ kn->hash = kernfs_name_hash(kernfs_rcu_name(kn), kn->ns);
+
+ ret = kernfs_link_sibling(kn);
+ if (ret)
+@@ -856,7 +861,7 @@ static struct kernfs_node *kernfs_find_ns(struct kernfs_node *parent,
+
+ if (has_ns != (bool)ns) {
+ WARN(1, KERN_WARNING "kernfs: ns %s in '%s' for '%s'\n",
+- has_ns ? "required" : "invalid", parent->name, name);
++ has_ns ? "required" : "invalid", kernfs_rcu_name(parent), name);
+ return NULL;
+ }
+
+@@ -1135,8 +1140,6 @@ static int kernfs_dop_revalidate(struct inode *dir, const struct qstr *name,
+
+ /* Negative hashed dentry? */
+ if (d_really_is_negative(dentry)) {
+- struct kernfs_node *parent;
+-
+ /* If the kernfs parent node has changed discard and
+ * proceed to ->lookup.
+ *
+@@ -1184,7 +1187,7 @@ static int kernfs_dop_revalidate(struct inode *dir, const struct qstr *name,
+ goto out_bad;
+
+ /* The kernfs node has been renamed */
+- if (strcmp(dentry->d_name.name, kn->name) != 0)
++ if (strcmp(dentry->d_name.name, kernfs_rcu_name(kn)) != 0)
+ goto out_bad;
+
+ /* The kernfs node has been moved to a different namespace */
+@@ -1478,7 +1481,7 @@ static void __kernfs_remove(struct kernfs_node *kn)
+ if (kernfs_parent(kn) && RB_EMPTY_NODE(&kn->rb))
+ return;
+
+- pr_debug("kernfs %s: removing\n", kn->name);
++ pr_debug("kernfs %s: removing\n", kernfs_rcu_name(kn));
+
+ /* prevent new usage by marking all nodes removing and deactivating */
+ pos = NULL;
+@@ -1734,7 +1737,7 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent,
+ {
+ struct kernfs_node *old_parent;
+ struct kernfs_root *root;
+- const char *old_name = NULL;
++ const char *old_name;
+ int error;
+
+ /* can't move or rename root */
+@@ -1757,8 +1760,11 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent,
+ }
+
+ error = 0;
++ old_name = kernfs_rcu_name(kn);
++ if (!new_name)
++ new_name = old_name;
+ if ((old_parent == new_parent) && (kn->ns == new_ns) &&
+- (strcmp(kn->name, new_name) == 0))
++ (strcmp(old_name, new_name) == 0))
+ goto out; /* nothing to rename */
+
+ error = -EEXIST;
+@@ -1766,7 +1772,7 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent,
+ goto out;
+
+ /* rename kernfs_node */
+- if (strcmp(kn->name, new_name) != 0) {
++ if (strcmp(old_name, new_name) != 0) {
+ error = -ENOMEM;
+ new_name = kstrdup_const(new_name, GFP_KERNEL);
+ if (!new_name)
+@@ -1779,27 +1785,32 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent,
+ * Move to the appropriate place in the appropriate directories rbtree.
+ */
+ kernfs_unlink_sibling(kn);
+- kernfs_get(new_parent);
+
+- /* rename_lock protects ->parent and ->name accessors */
+- write_lock_irq(&kernfs_rename_lock);
++ /* rename_lock protects ->parent accessors */
++ if (old_parent != new_parent) {
++ kernfs_get(new_parent);
++ write_lock_irq(&kernfs_rename_lock);
+
+- old_parent = kernfs_parent(kn);
+- rcu_assign_pointer(kn->__parent, new_parent);
++ rcu_assign_pointer(kn->__parent, new_parent);
+
+- kn->ns = new_ns;
+- if (new_name) {
+- old_name = kn->name;
+- kn->name = new_name;
+- }
++ kn->ns = new_ns;
++ if (new_name)
++ rcu_assign_pointer(kn->name, new_name);
+
+- write_unlock_irq(&kernfs_rename_lock);
++ write_unlock_irq(&kernfs_rename_lock);
++ kernfs_put(old_parent);
++ } else {
++ /* name assignment is RCU protected, parent is the same */
++ kn->ns = new_ns;
++ if (new_name)
++ rcu_assign_pointer(kn->name, new_name);
++ }
+
+- kn->hash = kernfs_name_hash(kn->name, kn->ns);
++ kn->hash = kernfs_name_hash(new_name ?: old_name, kn->ns);
+ kernfs_link_sibling(kn);
+
+- kernfs_put(old_parent);
+- kfree_const(old_name);
++ if (new_name && !is_kernel_rodata((unsigned long)old_name))
++ kfree_rcu_mightsleep(old_name);
+
+ error = 0;
+ out:
+@@ -1884,7 +1895,7 @@ static int kernfs_fop_readdir(struct file *file, struct dir_context *ctx)
+ for (pos = kernfs_dir_pos(ns, parent, ctx->pos, pos);
+ pos;
+ pos = kernfs_dir_next_pos(ns, parent, ctx->pos, pos)) {
+- const char *name = pos->name;
++ const char *name = kernfs_rcu_name(pos);
+ unsigned int type = fs_umode_to_dtype(pos->mode);
+ int len = strlen(name);
+ ino_t ino = kernfs_ino(pos);
+diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c
+index c4ffa8dc89ebc..66fe8fe41f060 100644
+--- a/fs/kernfs/file.c
++++ b/fs/kernfs/file.c
+@@ -915,6 +915,7 @@ static void kernfs_notify_workfn(struct work_struct *work)
+ list_for_each_entry(info, &kernfs_root(kn)->supers, node) {
+ struct kernfs_node *parent;
+ struct inode *p_inode = NULL;
++ const char *kn_name;
+ struct inode *inode;
+ struct qstr name;
+
+@@ -928,7 +929,8 @@ static void kernfs_notify_workfn(struct work_struct *work)
+ if (!inode)
+ continue;
+
+- name = QSTR(kn->name);
++ kn_name = kernfs_rcu_name(kn);
++ name = QSTR(kn_name);
+ parent = kernfs_get_parent(kn);
+ if (parent) {
+ p_inode = ilookup(info->sb, kernfs_ino(parent));
+diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h
+index c43bee18b79f7..40a2a9cd819d0 100644
+--- a/fs/kernfs/kernfs-internal.h
++++ b/fs/kernfs/kernfs-internal.h
+@@ -107,6 +107,11 @@ static inline bool kernfs_root_is_locked(const struct kernfs_node *kn)
+ return lockdep_is_held(&kernfs_root(kn)->kernfs_rwsem);
+ }
+
++static inline const char *kernfs_rcu_name(const struct kernfs_node *kn)
++{
++ return rcu_dereference_check(kn->name, kernfs_root_is_locked(kn));
++}
++
+ static inline struct kernfs_node *kernfs_parent(const struct kernfs_node *kn)
+ {
+ /*
+diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c
+index 2252b16e6ef0b..d1f512b7bf867 100644
+--- a/fs/kernfs/mount.c
++++ b/fs/kernfs/mount.c
+@@ -231,6 +231,7 @@ struct dentry *kernfs_node_dentry(struct kernfs_node *kn,
+ do {
+ struct dentry *dtmp;
+ struct kernfs_node *kntmp;
++ const char *name;
+
+ if (kn == knparent)
+ return dentry;
+@@ -239,8 +240,8 @@ struct dentry *kernfs_node_dentry(struct kernfs_node *kn,
+ dput(dentry);
+ return ERR_PTR(-EINVAL);
+ }
+- dtmp = lookup_positive_unlocked(kntmp->name, dentry,
+- strlen(kntmp->name));
++ name = rcu_dereference(kntmp->name);
++ dtmp = lookup_positive_unlocked(name, dentry, strlen(name));
+ dput(dentry);
+ if (IS_ERR(dtmp))
+ return dtmp;
+diff --git a/fs/kernfs/symlink.c b/fs/kernfs/symlink.c
+index 05c62ca93c53d..0bd8a2143723d 100644
+--- a/fs/kernfs/symlink.c
++++ b/fs/kernfs/symlink.c
+@@ -81,7 +81,7 @@ static int kernfs_get_target_path(struct kernfs_node *parent,
+ /* determine end of target string for reverse fillup */
+ kn = target;
+ while (kernfs_parent(kn) && kn != base) {
+- len += strlen(kn->name) + 1;
++ len += strlen(kernfs_rcu_name(kn)) + 1;
+ kn = kernfs_parent(kn);
+ }
+
+@@ -95,10 +95,11 @@ static int kernfs_get_target_path(struct kernfs_node *parent,
+ /* reverse fillup of target string from target to base */
+ kn = target;
+ while (kernfs_parent(kn) && kn != base) {
+- int slen = strlen(kn->name);
++ const char *name = kernfs_rcu_name(kn);
++ int slen = strlen(name);
+
+ len -= slen;
+- memcpy(s + len, kn->name, slen);
++ memcpy(s + len, name, slen);
+ if (len)
+ s[--len] = '/';
+
+diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
+index 4df2afa551dc6..94e12efd92f21 100644
+--- a/fs/sysfs/dir.c
++++ b/fs/sysfs/dir.c
+@@ -123,7 +123,7 @@ int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj,
+ new_parent = new_parent_kobj && new_parent_kobj->sd ?
+ new_parent_kobj->sd : sysfs_root_kn;
+
+- return kernfs_rename_ns(kn, new_parent, kn->name, new_ns);
++ return kernfs_rename_ns(kn, new_parent, NULL, new_ns);
+ }
+
+ /**
+diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h
+index 5dda9a268e44c..b5a5f32fdfd1a 100644
+--- a/include/linux/kernfs.h
++++ b/include/linux/kernfs.h
+@@ -204,8 +204,8 @@ struct kernfs_node {
+ * never moved to a different parent, it is safe to access the
+ * parent directly.
+ */
+- const char *name;
+ struct kernfs_node __rcu *__parent;
++ const char __rcu *name;
+
+ struct rb_node rb;
+
+@@ -400,7 +400,7 @@ static inline bool kernfs_ns_enabled(struct kernfs_node *kn)
+ }
+
+ int kernfs_name(struct kernfs_node *kn, char *buf, size_t buflen);
+-int kernfs_path_from_node(struct kernfs_node *root_kn, struct kernfs_node *kn,
++int kernfs_path_from_node(struct kernfs_node *kn_to, struct kernfs_node *kn_from,
+ char *buf, size_t buflen);
+ void pr_cont_kernfs_name(struct kernfs_node *kn);
+ void pr_cont_kernfs_path(struct kernfs_node *kn);
+diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
+index 7b867dfec88ba..7dee9616147d2 100644
+--- a/security/selinux/hooks.c
++++ b/security/selinux/hooks.c
+@@ -3584,10 +3584,13 @@ static int selinux_kernfs_init_security(struct kernfs_node *kn_dir,
+ newsid = tsec->create_sid;
+ } else {
+ u16 secclass = inode_mode_to_security_class(kn->mode);
++ const char *kn_name;
+ struct qstr q;
+
+- q.name = kn->name;
+- q.hash_len = hashlen_string(kn_dir, kn->name);
++ /* kn is fresh, can't be renamed, name goes not away */
++ kn_name = rcu_dereference_check(kn->name, true);
++ q.name = kn_name;
++ q.hash_len = hashlen_string(kn_dir, kn_name);
+
+ rc = security_transition_sid(tsec->sid,
+ parent_sid, secclass, &q,
+--
+2.39.5
+
--- /dev/null
+From d00673680b5c872e774bcf1edfc01462fd88bb55 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 13 Feb 2025 15:50:22 +0100
+Subject: kernfs: Use RCU to access kernfs_node::parent.
+
+From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+
+[ Upstream commit 633488947ef66b194377411322dc9e12aab79b65 ]
+
+kernfs_rename_lock is used to obtain stable kernfs_node::{name|parent}
+pointer. This is a preparation to access kernfs_node::parent under RCU
+and ensure that the pointer remains stable under the RCU lifetime
+guarantees.
+
+For a complete path, as it is done in kernfs_path_from_node(), the
+kernfs_rename_lock is still required in order to obtain a stable parent
+relationship while computing the relevant node depth. This must not
+change while the nodes are inspected in order to build the path.
+If the kernfs user never moves the nodes (changes the parent) then the
+kernfs_rename_lock is not required and the RCU guarantees are
+sufficient. This "restriction" can be set with
+KERNFS_ROOT_INVARIANT_PARENT. Otherwise the lock is required.
+
+Rename kernfs_node::parent to kernfs_node::__parent to denote the RCU
+access and use RCU accessor while accessing the node.
+Make cgroup use KERNFS_ROOT_INVARIANT_PARENT since the parent here can
+not change.
+
+Acked-by: Tejun Heo <tj@kernel.org>
+Cc: Yonghong Song <yonghong.song@linux.dev>
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Link: https://lore.kernel.org/r/20250213145023.2820193-6-bigeasy@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: 6ef5b6fae304 ("kernfs: Drop kernfs_rwsem while invoking lookup_positive_unlocked().")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/kernel/cpu/resctrl/rdtgroup.c | 65 +++++++++----
+ fs/kernfs/dir.c | 96 ++++++++++++-------
+ fs/kernfs/kernfs-internal.h | 32 ++++++-
+ fs/kernfs/mount.c | 10 +-
+ fs/kernfs/symlink.c | 23 ++---
+ fs/sysfs/file.c | 24 +++--
+ include/linux/kernfs.h | 10 +-
+ kernel/cgroup/cgroup-v1.c | 2 +-
+ kernel/cgroup/cgroup.c | 24 ++++-
+ .../selftests/bpf/progs/profiler.inc.h | 2 +-
+ 10 files changed, 195 insertions(+), 93 deletions(-)
+
+diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c
+index 04b653d613e88..3d2a850ea737d 100644
+--- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c
++++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c
+@@ -957,10 +957,20 @@ static int rdt_last_cmd_status_show(struct kernfs_open_file *of,
+ return 0;
+ }
+
++static void *rdt_kn_parent_priv(struct kernfs_node *kn)
++{
++ /*
++ * The parent pointer is only valid within RCU section since it can be
++ * replaced.
++ */
++ guard(rcu)();
++ return rcu_dereference(kn->__parent)->priv;
++}
++
+ static int rdt_num_closids_show(struct kernfs_open_file *of,
+ struct seq_file *seq, void *v)
+ {
+- struct resctrl_schema *s = of->kn->parent->priv;
++ struct resctrl_schema *s = rdt_kn_parent_priv(of->kn);
+
+ seq_printf(seq, "%u\n", s->num_closid);
+ return 0;
+@@ -969,7 +979,7 @@ static int rdt_num_closids_show(struct kernfs_open_file *of,
+ static int rdt_default_ctrl_show(struct kernfs_open_file *of,
+ struct seq_file *seq, void *v)
+ {
+- struct resctrl_schema *s = of->kn->parent->priv;
++ struct resctrl_schema *s = rdt_kn_parent_priv(of->kn);
+ struct rdt_resource *r = s->res;
+
+ seq_printf(seq, "%x\n", r->default_ctrl);
+@@ -979,7 +989,7 @@ static int rdt_default_ctrl_show(struct kernfs_open_file *of,
+ static int rdt_min_cbm_bits_show(struct kernfs_open_file *of,
+ struct seq_file *seq, void *v)
+ {
+- struct resctrl_schema *s = of->kn->parent->priv;
++ struct resctrl_schema *s = rdt_kn_parent_priv(of->kn);
+ struct rdt_resource *r = s->res;
+
+ seq_printf(seq, "%u\n", r->cache.min_cbm_bits);
+@@ -989,7 +999,7 @@ static int rdt_min_cbm_bits_show(struct kernfs_open_file *of,
+ static int rdt_shareable_bits_show(struct kernfs_open_file *of,
+ struct seq_file *seq, void *v)
+ {
+- struct resctrl_schema *s = of->kn->parent->priv;
++ struct resctrl_schema *s = rdt_kn_parent_priv(of->kn);
+ struct rdt_resource *r = s->res;
+
+ seq_printf(seq, "%x\n", r->cache.shareable_bits);
+@@ -1013,7 +1023,7 @@ static int rdt_shareable_bits_show(struct kernfs_open_file *of,
+ static int rdt_bit_usage_show(struct kernfs_open_file *of,
+ struct seq_file *seq, void *v)
+ {
+- struct resctrl_schema *s = of->kn->parent->priv;
++ struct resctrl_schema *s = rdt_kn_parent_priv(of->kn);
+ /*
+ * Use unsigned long even though only 32 bits are used to ensure
+ * test_bit() is used safely.
+@@ -1095,7 +1105,7 @@ static int rdt_bit_usage_show(struct kernfs_open_file *of,
+ static int rdt_min_bw_show(struct kernfs_open_file *of,
+ struct seq_file *seq, void *v)
+ {
+- struct resctrl_schema *s = of->kn->parent->priv;
++ struct resctrl_schema *s = rdt_kn_parent_priv(of->kn);
+ struct rdt_resource *r = s->res;
+
+ seq_printf(seq, "%u\n", r->membw.min_bw);
+@@ -1105,7 +1115,7 @@ static int rdt_min_bw_show(struct kernfs_open_file *of,
+ static int rdt_num_rmids_show(struct kernfs_open_file *of,
+ struct seq_file *seq, void *v)
+ {
+- struct rdt_resource *r = of->kn->parent->priv;
++ struct rdt_resource *r = rdt_kn_parent_priv(of->kn);
+
+ seq_printf(seq, "%d\n", r->num_rmid);
+
+@@ -1115,7 +1125,7 @@ static int rdt_num_rmids_show(struct kernfs_open_file *of,
+ static int rdt_mon_features_show(struct kernfs_open_file *of,
+ struct seq_file *seq, void *v)
+ {
+- struct rdt_resource *r = of->kn->parent->priv;
++ struct rdt_resource *r = rdt_kn_parent_priv(of->kn);
+ struct mon_evt *mevt;
+
+ list_for_each_entry(mevt, &r->evt_list, list) {
+@@ -1130,7 +1140,7 @@ static int rdt_mon_features_show(struct kernfs_open_file *of,
+ static int rdt_bw_gran_show(struct kernfs_open_file *of,
+ struct seq_file *seq, void *v)
+ {
+- struct resctrl_schema *s = of->kn->parent->priv;
++ struct resctrl_schema *s = rdt_kn_parent_priv(of->kn);
+ struct rdt_resource *r = s->res;
+
+ seq_printf(seq, "%u\n", r->membw.bw_gran);
+@@ -1140,7 +1150,7 @@ static int rdt_bw_gran_show(struct kernfs_open_file *of,
+ static int rdt_delay_linear_show(struct kernfs_open_file *of,
+ struct seq_file *seq, void *v)
+ {
+- struct resctrl_schema *s = of->kn->parent->priv;
++ struct resctrl_schema *s = rdt_kn_parent_priv(of->kn);
+ struct rdt_resource *r = s->res;
+
+ seq_printf(seq, "%u\n", r->membw.delay_linear);
+@@ -1158,7 +1168,7 @@ static int max_threshold_occ_show(struct kernfs_open_file *of,
+ static int rdt_thread_throttle_mode_show(struct kernfs_open_file *of,
+ struct seq_file *seq, void *v)
+ {
+- struct resctrl_schema *s = of->kn->parent->priv;
++ struct resctrl_schema *s = rdt_kn_parent_priv(of->kn);
+ struct rdt_resource *r = s->res;
+
+ if (r->membw.throttle_mode == THREAD_THROTTLE_PER_THREAD)
+@@ -1223,7 +1233,7 @@ static enum resctrl_conf_type resctrl_peer_type(enum resctrl_conf_type my_type)
+ static int rdt_has_sparse_bitmasks_show(struct kernfs_open_file *of,
+ struct seq_file *seq, void *v)
+ {
+- struct resctrl_schema *s = of->kn->parent->priv;
++ struct resctrl_schema *s = rdt_kn_parent_priv(of->kn);
+ struct rdt_resource *r = s->res;
+
+ seq_printf(seq, "%u\n", r->cache.arch_has_sparse_bitmasks);
+@@ -1635,7 +1645,7 @@ static int mbm_config_show(struct seq_file *s, struct rdt_resource *r, u32 evtid
+ static int mbm_total_bytes_config_show(struct kernfs_open_file *of,
+ struct seq_file *seq, void *v)
+ {
+- struct rdt_resource *r = of->kn->parent->priv;
++ struct rdt_resource *r = rdt_kn_parent_priv(of->kn);
+
+ mbm_config_show(seq, r, QOS_L3_MBM_TOTAL_EVENT_ID);
+
+@@ -1645,7 +1655,7 @@ static int mbm_total_bytes_config_show(struct kernfs_open_file *of,
+ static int mbm_local_bytes_config_show(struct kernfs_open_file *of,
+ struct seq_file *seq, void *v)
+ {
+- struct rdt_resource *r = of->kn->parent->priv;
++ struct rdt_resource *r = rdt_kn_parent_priv(of->kn);
+
+ mbm_config_show(seq, r, QOS_L3_MBM_LOCAL_EVENT_ID);
+
+@@ -1751,7 +1761,7 @@ static ssize_t mbm_total_bytes_config_write(struct kernfs_open_file *of,
+ char *buf, size_t nbytes,
+ loff_t off)
+ {
+- struct rdt_resource *r = of->kn->parent->priv;
++ struct rdt_resource *r = rdt_kn_parent_priv(of->kn);
+ int ret;
+
+ /* Valid input requires a trailing newline */
+@@ -1777,7 +1787,7 @@ static ssize_t mbm_local_bytes_config_write(struct kernfs_open_file *of,
+ char *buf, size_t nbytes,
+ loff_t off)
+ {
+- struct rdt_resource *r = of->kn->parent->priv;
++ struct rdt_resource *r = rdt_kn_parent_priv(of->kn);
+ int ret;
+
+ /* Valid input requires a trailing newline */
+@@ -2441,12 +2451,13 @@ static struct rdtgroup *kernfs_to_rdtgroup(struct kernfs_node *kn)
+ * resource. "info" and its subdirectories don't
+ * have rdtgroup structures, so return NULL here.
+ */
+- if (kn == kn_info || kn->parent == kn_info)
++ if (kn == kn_info ||
++ rcu_access_pointer(kn->__parent) == kn_info)
+ return NULL;
+ else
+ return kn->priv;
+ } else {
+- return kn->parent->priv;
++ return rdt_kn_parent_priv(kn);
+ }
+ }
+
+@@ -3772,9 +3783,18 @@ static int rdtgroup_rmdir_ctrl(struct rdtgroup *rdtgrp, cpumask_var_t tmpmask)
+ return 0;
+ }
+
++static struct kernfs_node *rdt_kn_parent(struct kernfs_node *kn)
++{
++ /*
++ * Valid within the RCU section it was obtained or while rdtgroup_mutex
++ * is held.
++ */
++ return rcu_dereference_check(kn->__parent, lockdep_is_held(&rdtgroup_mutex));
++}
++
+ static int rdtgroup_rmdir(struct kernfs_node *kn)
+ {
+- struct kernfs_node *parent_kn = kn->parent;
++ struct kernfs_node *parent_kn;
+ struct rdtgroup *rdtgrp;
+ cpumask_var_t tmpmask;
+ int ret = 0;
+@@ -3787,6 +3807,7 @@ static int rdtgroup_rmdir(struct kernfs_node *kn)
+ ret = -EPERM;
+ goto out;
+ }
++ parent_kn = rdt_kn_parent(kn);
+
+ /*
+ * If the rdtgroup is a ctrl_mon group and parent directory
+@@ -3855,6 +3876,7 @@ static void mongrp_reparent(struct rdtgroup *rdtgrp,
+ static int rdtgroup_rename(struct kernfs_node *kn,
+ struct kernfs_node *new_parent, const char *new_name)
+ {
++ struct kernfs_node *kn_parent;
+ struct rdtgroup *new_prdtgrp;
+ struct rdtgroup *rdtgrp;
+ cpumask_var_t tmpmask;
+@@ -3889,8 +3911,9 @@ static int rdtgroup_rename(struct kernfs_node *kn,
+ goto out;
+ }
+
+- if (rdtgrp->type != RDTMON_GROUP || !kn->parent ||
+- !is_mon_groups(kn->parent, kn->name)) {
++ kn_parent = rdt_kn_parent(kn);
++ if (rdtgrp->type != RDTMON_GROUP || !kn_parent ||
++ !is_mon_groups(kn_parent, kn->name)) {
+ rdt_last_cmd_puts("Source must be a MON group\n");
+ ret = -EPERM;
+ goto out;
+diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
+index 43fbada678381..1d370c497e8a3 100644
+--- a/fs/kernfs/dir.c
++++ b/fs/kernfs/dir.c
+@@ -17,7 +17,7 @@
+
+ #include "kernfs-internal.h"
+
+-static DEFINE_RWLOCK(kernfs_rename_lock); /* kn->parent and ->name */
++DEFINE_RWLOCK(kernfs_rename_lock); /* kn->parent and ->name */
+ /*
+ * Don't use rename_lock to piggy back on pr_cont_buf. We don't want to
+ * call pr_cont() while holding rename_lock. Because sometimes pr_cont()
+@@ -56,7 +56,7 @@ static int kernfs_name_locked(struct kernfs_node *kn, char *buf, size_t buflen)
+ if (!kn)
+ return strscpy(buf, "(null)", buflen);
+
+- return strscpy(buf, kn->parent ? kn->name : "/", buflen);
++ return strscpy(buf, rcu_access_pointer(kn->__parent) ? kn->name : "/", buflen);
+ }
+
+ /* kernfs_node_depth - compute depth from @from to @to */
+@@ -64,9 +64,9 @@ static size_t kernfs_depth(struct kernfs_node *from, struct kernfs_node *to)
+ {
+ size_t depth = 0;
+
+- while (to->parent && to != from) {
++ while (rcu_dereference(to->__parent) && to != from) {
+ depth++;
+- to = to->parent;
++ to = rcu_dereference(to->__parent);
+ }
+ return depth;
+ }
+@@ -84,18 +84,18 @@ static struct kernfs_node *kernfs_common_ancestor(struct kernfs_node *a,
+ db = kernfs_depth(rb->kn, b);
+
+ while (da > db) {
+- a = a->parent;
++ a = rcu_dereference(a->__parent);
+ da--;
+ }
+ while (db > da) {
+- b = b->parent;
++ b = rcu_dereference(b->__parent);
+ db--;
+ }
+
+ /* worst case b and a will be the same at root */
+ while (b != a) {
+- b = b->parent;
+- a = a->parent;
++ b = rcu_dereference(b->__parent);
++ a = rcu_dereference(a->__parent);
+ }
+
+ return a;
+@@ -168,8 +168,9 @@ static int kernfs_path_from_node_locked(struct kernfs_node *kn_to,
+
+ /* Calculate how many bytes we need for the rest */
+ for (i = depth_to - 1; i >= 0; i--) {
++
+ for (kn = kn_to, j = 0; j < i; j++)
+- kn = kn->parent;
++ kn = rcu_dereference(kn->__parent);
+
+ len += scnprintf(buf + len, buflen - len, "/%s", kn->name);
+ }
+@@ -226,6 +227,7 @@ int kernfs_path_from_node(struct kernfs_node *to, struct kernfs_node *from,
+ unsigned long flags;
+ int ret;
+
++ guard(rcu)();
+ read_lock_irqsave(&kernfs_rename_lock, flags);
+ ret = kernfs_path_from_node_locked(to, from, buf, buflen);
+ read_unlock_irqrestore(&kernfs_rename_lock, flags);
+@@ -295,7 +297,7 @@ struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn)
+ unsigned long flags;
+
+ read_lock_irqsave(&kernfs_rename_lock, flags);
+- parent = kn->parent;
++ parent = kernfs_parent(kn);
+ kernfs_get(parent);
+ read_unlock_irqrestore(&kernfs_rename_lock, flags);
+
+@@ -360,8 +362,12 @@ static int kernfs_sd_compare(const struct kernfs_node *left,
+ */
+ static int kernfs_link_sibling(struct kernfs_node *kn)
+ {
+- struct rb_node **node = &kn->parent->dir.children.rb_node;
+ struct rb_node *parent = NULL;
++ struct kernfs_node *kn_parent;
++ struct rb_node **node;
++
++ kn_parent = kernfs_parent(kn);
++ node = &kn_parent->dir.children.rb_node;
+
+ while (*node) {
+ struct kernfs_node *pos;
+@@ -380,13 +386,13 @@ static int kernfs_link_sibling(struct kernfs_node *kn)
+
+ /* add new node and rebalance the tree */
+ rb_link_node(&kn->rb, parent, node);
+- rb_insert_color(&kn->rb, &kn->parent->dir.children);
++ rb_insert_color(&kn->rb, &kn_parent->dir.children);
+
+ /* successfully added, account subdir number */
+ down_write(&kernfs_root(kn)->kernfs_iattr_rwsem);
+ if (kernfs_type(kn) == KERNFS_DIR)
+- kn->parent->dir.subdirs++;
+- kernfs_inc_rev(kn->parent);
++ kn_parent->dir.subdirs++;
++ kernfs_inc_rev(kn_parent);
+ up_write(&kernfs_root(kn)->kernfs_iattr_rwsem);
+
+ return 0;
+@@ -407,16 +413,19 @@ static int kernfs_link_sibling(struct kernfs_node *kn)
+ */
+ static bool kernfs_unlink_sibling(struct kernfs_node *kn)
+ {
++ struct kernfs_node *kn_parent;
++
+ if (RB_EMPTY_NODE(&kn->rb))
+ return false;
+
++ kn_parent = kernfs_parent(kn);
+ down_write(&kernfs_root(kn)->kernfs_iattr_rwsem);
+ if (kernfs_type(kn) == KERNFS_DIR)
+- kn->parent->dir.subdirs--;
+- kernfs_inc_rev(kn->parent);
++ kn_parent->dir.subdirs--;
++ kernfs_inc_rev(kn_parent);
+ up_write(&kernfs_root(kn)->kernfs_iattr_rwsem);
+
+- rb_erase(&kn->rb, &kn->parent->dir.children);
++ rb_erase(&kn->rb, &kn_parent->dir.children);
+ RB_CLEAR_NODE(&kn->rb);
+ return true;
+ }
+@@ -562,7 +571,7 @@ void kernfs_put(struct kernfs_node *kn)
+ * Moving/renaming is always done while holding reference.
+ * kn->parent won't change beneath us.
+ */
+- parent = kn->parent;
++ parent = kernfs_parent(kn);
+
+ WARN_ONCE(atomic_read(&kn->active) != KN_DEACTIVATED_BIAS,
+ "kernfs_put: %s/%s: released with incorrect active_ref %d\n",
+@@ -701,7 +710,7 @@ struct kernfs_node *kernfs_new_node(struct kernfs_node *parent,
+ name, mode, uid, gid, flags);
+ if (kn) {
+ kernfs_get(parent);
+- kn->parent = parent;
++ rcu_assign_pointer(kn->__parent, parent);
+ }
+ return kn;
+ }
+@@ -769,13 +778,14 @@ struct kernfs_node *kernfs_find_and_get_node_by_id(struct kernfs_root *root,
+ */
+ int kernfs_add_one(struct kernfs_node *kn)
+ {
+- struct kernfs_node *parent = kn->parent;
+- struct kernfs_root *root = kernfs_root(parent);
++ struct kernfs_root *root = kernfs_root(kn);
+ struct kernfs_iattrs *ps_iattr;
++ struct kernfs_node *parent;
+ bool has_ns;
+ int ret;
+
+ down_write(&root->kernfs_rwsem);
++ parent = kernfs_parent(kn);
+
+ ret = -EINVAL;
+ has_ns = kernfs_ns_enabled(parent);
+@@ -949,6 +959,11 @@ struct kernfs_node *kernfs_walk_and_get_ns(struct kernfs_node *parent,
+ return kn;
+ }
+
++unsigned int kernfs_root_flags(struct kernfs_node *kn)
++{
++ return kernfs_root(kn)->flags;
++}
++
+ /**
+ * kernfs_create_root - create a new kernfs hierarchy
+ * @scops: optional syscall operations for the hierarchy
+@@ -1112,7 +1127,7 @@ struct kernfs_node *kernfs_create_empty_dir(struct kernfs_node *parent,
+ static int kernfs_dop_revalidate(struct inode *dir, const struct qstr *name,
+ struct dentry *dentry, unsigned int flags)
+ {
+- struct kernfs_node *kn;
++ struct kernfs_node *kn, *parent;
+ struct kernfs_root *root;
+
+ if (flags & LOOKUP_RCU)
+@@ -1163,8 +1178,9 @@ static int kernfs_dop_revalidate(struct inode *dir, const struct qstr *name,
+ if (!kernfs_active(kn))
+ goto out_bad;
+
++ parent = kernfs_parent(kn);
+ /* The kernfs node has been moved? */
+- if (kernfs_dentry_node(dentry->d_parent) != kn->parent)
++ if (kernfs_dentry_node(dentry->d_parent) != parent)
+ goto out_bad;
+
+ /* The kernfs node has been renamed */
+@@ -1172,7 +1188,7 @@ static int kernfs_dop_revalidate(struct inode *dir, const struct qstr *name,
+ goto out_bad;
+
+ /* The kernfs node has been moved to a different namespace */
+- if (kn->parent && kernfs_ns_enabled(kn->parent) &&
++ if (parent && kernfs_ns_enabled(parent) &&
+ kernfs_info(dentry->d_sb)->ns != kn->ns)
+ goto out_bad;
+
+@@ -1365,7 +1381,7 @@ static struct kernfs_node *kernfs_next_descendant_post(struct kernfs_node *pos,
+ return kernfs_leftmost_descendant(rb_to_kn(rbn));
+
+ /* no sibling left, visit parent */
+- return pos->parent;
++ return kernfs_parent(pos);
+ }
+
+ static void kernfs_activate_one(struct kernfs_node *kn)
+@@ -1377,7 +1393,7 @@ static void kernfs_activate_one(struct kernfs_node *kn)
+ if (kernfs_active(kn) || (kn->flags & (KERNFS_HIDDEN | KERNFS_REMOVING)))
+ return;
+
+- WARN_ON_ONCE(kn->parent && RB_EMPTY_NODE(&kn->rb));
++ WARN_ON_ONCE(rcu_access_pointer(kn->__parent) && RB_EMPTY_NODE(&kn->rb));
+ WARN_ON_ONCE(atomic_read(&kn->active) != KN_DEACTIVATED_BIAS);
+
+ atomic_sub(KN_DEACTIVATED_BIAS, &kn->active);
+@@ -1447,7 +1463,7 @@ void kernfs_show(struct kernfs_node *kn, bool show)
+
+ static void __kernfs_remove(struct kernfs_node *kn)
+ {
+- struct kernfs_node *pos;
++ struct kernfs_node *pos, *parent;
+
+ /* Short-circuit if non-root @kn has already finished removal. */
+ if (!kn)
+@@ -1459,7 +1475,7 @@ static void __kernfs_remove(struct kernfs_node *kn)
+ * This is for kernfs_remove_self() which plays with active ref
+ * after removal.
+ */
+- if (kn->parent && RB_EMPTY_NODE(&kn->rb))
++ if (kernfs_parent(kn) && RB_EMPTY_NODE(&kn->rb))
+ return;
+
+ pr_debug("kernfs %s: removing\n", kn->name);
+@@ -1485,14 +1501,14 @@ static void __kernfs_remove(struct kernfs_node *kn)
+ kernfs_get(pos);
+
+ kernfs_drain(pos);
+-
++ parent = kernfs_parent(pos);
+ /*
+ * kernfs_unlink_sibling() succeeds once per node. Use it
+ * to decide who's responsible for cleanups.
+ */
+- if (!pos->parent || kernfs_unlink_sibling(pos)) {
++ if (!parent || kernfs_unlink_sibling(pos)) {
+ struct kernfs_iattrs *ps_iattr =
+- pos->parent ? pos->parent->iattr : NULL;
++ parent ? parent->iattr : NULL;
+
+ /* update timestamps on the parent */
+ down_write(&kernfs_root(kn)->kernfs_iattr_rwsem);
+@@ -1722,7 +1738,7 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent,
+ int error;
+
+ /* can't move or rename root */
+- if (!kn->parent)
++ if (!rcu_access_pointer(kn->__parent))
+ return -EINVAL;
+
+ root = kernfs_root(kn);
+@@ -1733,8 +1749,15 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent,
+ (new_parent->flags & KERNFS_EMPTY_DIR))
+ goto out;
+
++ old_parent = kernfs_parent(kn);
++ if (root->flags & KERNFS_ROOT_INVARIANT_PARENT) {
++ error = -EINVAL;
++ if (WARN_ON_ONCE(old_parent != new_parent))
++ goto out;
++ }
++
+ error = 0;
+- if ((kn->parent == new_parent) && (kn->ns == new_ns) &&
++ if ((old_parent == new_parent) && (kn->ns == new_ns) &&
+ (strcmp(kn->name, new_name) == 0))
+ goto out; /* nothing to rename */
+
+@@ -1761,8 +1784,8 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent,
+ /* rename_lock protects ->parent and ->name accessors */
+ write_lock_irq(&kernfs_rename_lock);
+
+- old_parent = kn->parent;
+- kn->parent = new_parent;
++ old_parent = kernfs_parent(kn);
++ rcu_assign_pointer(kn->__parent, new_parent);
+
+ kn->ns = new_ns;
+ if (new_name) {
+@@ -1795,7 +1818,8 @@ static struct kernfs_node *kernfs_dir_pos(const void *ns,
+ {
+ if (pos) {
+ int valid = kernfs_active(pos) &&
+- pos->parent == parent && hash == pos->hash;
++ rcu_access_pointer(pos->__parent) == parent &&
++ hash == pos->hash;
+ kernfs_put(pos);
+ if (!valid)
+ pos = NULL;
+diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h
+index b42ee6547cdc1..c43bee18b79f7 100644
+--- a/fs/kernfs/kernfs-internal.h
++++ b/fs/kernfs/kernfs-internal.h
+@@ -19,6 +19,8 @@
+ #include <linux/kernfs.h>
+ #include <linux/fs_context.h>
+
++extern rwlock_t kernfs_rename_lock;
++
+ struct kernfs_iattrs {
+ kuid_t ia_uid;
+ kgid_t ia_gid;
+@@ -64,11 +66,14 @@ struct kernfs_root {
+ *
+ * Return: the kernfs_root @kn belongs to.
+ */
+-static inline struct kernfs_root *kernfs_root(struct kernfs_node *kn)
++static inline struct kernfs_root *kernfs_root(const struct kernfs_node *kn)
+ {
++ const struct kernfs_node *knp;
+ /* if parent exists, it's always a dir; otherwise, @sd is a dir */
+- if (kn->parent)
+- kn = kn->parent;
++ guard(rcu)();
++ knp = rcu_dereference(kn->__parent);
++ if (knp)
++ kn = knp;
+ return kn->dir.root;
+ }
+
+@@ -97,6 +102,27 @@ struct kernfs_super_info {
+ };
+ #define kernfs_info(SB) ((struct kernfs_super_info *)(SB->s_fs_info))
+
++static inline bool kernfs_root_is_locked(const struct kernfs_node *kn)
++{
++ return lockdep_is_held(&kernfs_root(kn)->kernfs_rwsem);
++}
++
++static inline struct kernfs_node *kernfs_parent(const struct kernfs_node *kn)
++{
++ /*
++ * The kernfs_node::__parent remains valid within a RCU section. The kn
++ * can be reparented (and renamed) which changes the entry. This can be
++ * avoided by locking kernfs_root::kernfs_rwsem or kernfs_rename_lock.
++ * Both locks can be used to obtain a reference on __parent. Once the
++ * reference count reaches 0 then the node is about to be freed
++ * and can not be renamed (or become a different parent) anymore.
++ */
++ return rcu_dereference_check(kn->__parent,
++ kernfs_root_is_locked(kn) ||
++ lockdep_is_held(&kernfs_rename_lock) ||
++ !atomic_read(&kn->count));
++}
++
+ static inline struct kernfs_node *kernfs_dentry_node(struct dentry *dentry)
+ {
+ if (d_really_is_negative(dentry))
+diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c
+index 4a0ff08d589ca..2252b16e6ef0b 100644
+--- a/fs/kernfs/mount.c
++++ b/fs/kernfs/mount.c
+@@ -148,7 +148,7 @@ static struct dentry *kernfs_get_parent_dentry(struct dentry *child)
+ struct kernfs_root *root = kernfs_root(kn);
+
+ guard(rwsem_read)(&root->kernfs_rwsem);
+- return d_obtain_alias(kernfs_get_inode(child->d_sb, kn->parent));
++ return d_obtain_alias(kernfs_get_inode(child->d_sb, kernfs_parent(kn)));
+ }
+
+ static const struct export_operations kernfs_export_ops = {
+@@ -188,10 +188,10 @@ static struct kernfs_node *find_next_ancestor(struct kernfs_node *child,
+ return NULL;
+ }
+
+- while (child->parent != parent) {
+- if (!child->parent)
++ while (kernfs_parent(child) != parent) {
++ child = kernfs_parent(child);
++ if (!child)
+ return NULL;
+- child = child->parent;
+ }
+
+ return child;
+@@ -216,7 +216,7 @@ struct dentry *kernfs_node_dentry(struct kernfs_node *kn,
+ dentry = dget(sb->s_root);
+
+ /* Check if this is the root kernfs_node */
+- if (!kn->parent)
++ if (!rcu_access_pointer(kn->__parent))
+ return dentry;
+
+ root = kernfs_root(kn);
+diff --git a/fs/kernfs/symlink.c b/fs/kernfs/symlink.c
+index 45371a70caa71..05c62ca93c53d 100644
+--- a/fs/kernfs/symlink.c
++++ b/fs/kernfs/symlink.c
+@@ -62,10 +62,10 @@ static int kernfs_get_target_path(struct kernfs_node *parent,
+
+ /* go up to the root, stop at the base */
+ base = parent;
+- while (base->parent) {
+- kn = target->parent;
+- while (kn->parent && base != kn)
+- kn = kn->parent;
++ while (kernfs_parent(base)) {
++ kn = kernfs_parent(target);
++ while (kernfs_parent(kn) && base != kn)
++ kn = kernfs_parent(kn);
+
+ if (base == kn)
+ break;
+@@ -75,14 +75,14 @@ static int kernfs_get_target_path(struct kernfs_node *parent,
+
+ strcpy(s, "../");
+ s += 3;
+- base = base->parent;
++ base = kernfs_parent(base);
+ }
+
+ /* determine end of target string for reverse fillup */
+ kn = target;
+- while (kn->parent && kn != base) {
++ while (kernfs_parent(kn) && kn != base) {
+ len += strlen(kn->name) + 1;
+- kn = kn->parent;
++ kn = kernfs_parent(kn);
+ }
+
+ /* check limits */
+@@ -94,7 +94,7 @@ static int kernfs_get_target_path(struct kernfs_node *parent,
+
+ /* reverse fillup of target string from target to base */
+ kn = target;
+- while (kn->parent && kn != base) {
++ while (kernfs_parent(kn) && kn != base) {
+ int slen = strlen(kn->name);
+
+ len -= slen;
+@@ -102,7 +102,7 @@ static int kernfs_get_target_path(struct kernfs_node *parent,
+ if (len)
+ s[--len] = '/';
+
+- kn = kn->parent;
++ kn = kernfs_parent(kn);
+ }
+
+ return 0;
+@@ -111,12 +111,13 @@ static int kernfs_get_target_path(struct kernfs_node *parent,
+ static int kernfs_getlink(struct inode *inode, char *path)
+ {
+ struct kernfs_node *kn = inode->i_private;
+- struct kernfs_node *parent = kn->parent;
++ struct kernfs_node *parent;
+ struct kernfs_node *target = kn->symlink.target_kn;
+- struct kernfs_root *root = kernfs_root(parent);
++ struct kernfs_root *root = kernfs_root(kn);
+ int error;
+
+ down_read(&root->kernfs_rwsem);
++ parent = kernfs_parent(kn);
+ error = kernfs_get_target_path(parent, target, path);
+ up_read(&root->kernfs_rwsem);
+
+diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
+index 6931308876c4a..c3d3b079aedde 100644
+--- a/fs/sysfs/file.c
++++ b/fs/sysfs/file.c
+@@ -19,13 +19,19 @@
+
+ #include "sysfs.h"
+
++static struct kobject *sysfs_file_kobj(struct kernfs_node *kn)
++{
++ guard(rcu)();
++ return rcu_dereference(kn->__parent)->priv;
++}
++
+ /*
+ * Determine ktype->sysfs_ops for the given kernfs_node. This function
+ * must be called while holding an active reference.
+ */
+ static const struct sysfs_ops *sysfs_file_ops(struct kernfs_node *kn)
+ {
+- struct kobject *kobj = kn->parent->priv;
++ struct kobject *kobj = sysfs_file_kobj(kn);
+
+ if (kn->flags & KERNFS_LOCKDEP)
+ lockdep_assert_held(kn);
+@@ -40,7 +46,7 @@ static const struct sysfs_ops *sysfs_file_ops(struct kernfs_node *kn)
+ static int sysfs_kf_seq_show(struct seq_file *sf, void *v)
+ {
+ struct kernfs_open_file *of = sf->private;
+- struct kobject *kobj = of->kn->parent->priv;
++ struct kobject *kobj = sysfs_file_kobj(of->kn);
+ const struct sysfs_ops *ops = sysfs_file_ops(of->kn);
+ ssize_t count;
+ char *buf;
+@@ -78,7 +84,7 @@ static ssize_t sysfs_kf_bin_read(struct kernfs_open_file *of, char *buf,
+ size_t count, loff_t pos)
+ {
+ struct bin_attribute *battr = of->kn->priv;
+- struct kobject *kobj = of->kn->parent->priv;
++ struct kobject *kobj = sysfs_file_kobj(of->kn);
+ loff_t size = file_inode(of->file)->i_size;
+
+ if (!count)
+@@ -105,7 +111,7 @@ static ssize_t sysfs_kf_read(struct kernfs_open_file *of, char *buf,
+ size_t count, loff_t pos)
+ {
+ const struct sysfs_ops *ops = sysfs_file_ops(of->kn);
+- struct kobject *kobj = of->kn->parent->priv;
++ struct kobject *kobj = sysfs_file_kobj(of->kn);
+ ssize_t len;
+
+ /*
+@@ -131,7 +137,7 @@ static ssize_t sysfs_kf_write(struct kernfs_open_file *of, char *buf,
+ size_t count, loff_t pos)
+ {
+ const struct sysfs_ops *ops = sysfs_file_ops(of->kn);
+- struct kobject *kobj = of->kn->parent->priv;
++ struct kobject *kobj = sysfs_file_kobj(of->kn);
+
+ if (!count)
+ return 0;
+@@ -144,7 +150,7 @@ static ssize_t sysfs_kf_bin_write(struct kernfs_open_file *of, char *buf,
+ size_t count, loff_t pos)
+ {
+ struct bin_attribute *battr = of->kn->priv;
+- struct kobject *kobj = of->kn->parent->priv;
++ struct kobject *kobj = sysfs_file_kobj(of->kn);
+ loff_t size = file_inode(of->file)->i_size;
+
+ if (size) {
+@@ -168,7 +174,7 @@ static int sysfs_kf_bin_mmap(struct kernfs_open_file *of,
+ struct vm_area_struct *vma)
+ {
+ struct bin_attribute *battr = of->kn->priv;
+- struct kobject *kobj = of->kn->parent->priv;
++ struct kobject *kobj = sysfs_file_kobj(of->kn);
+
+ return battr->mmap(of->file, kobj, battr, vma);
+ }
+@@ -177,7 +183,7 @@ static loff_t sysfs_kf_bin_llseek(struct kernfs_open_file *of, loff_t offset,
+ int whence)
+ {
+ struct bin_attribute *battr = of->kn->priv;
+- struct kobject *kobj = of->kn->parent->priv;
++ struct kobject *kobj = sysfs_file_kobj(of->kn);
+
+ if (battr->llseek)
+ return battr->llseek(of->file, kobj, battr, offset, whence);
+@@ -494,7 +500,7 @@ EXPORT_SYMBOL_GPL(sysfs_break_active_protection);
+ */
+ void sysfs_unbreak_active_protection(struct kernfs_node *kn)
+ {
+- struct kobject *kobj = kn->parent->priv;
++ struct kobject *kobj = sysfs_file_kobj(kn);
+
+ kernfs_unbreak_active_protection(kn);
+ kernfs_put(kn);
+diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h
+index 87c79d076d6d7..5dda9a268e44c 100644
+--- a/include/linux/kernfs.h
++++ b/include/linux/kernfs.h
+@@ -147,6 +147,11 @@ enum kernfs_root_flag {
+ * Support user xattrs to be written to nodes rooted at this root.
+ */
+ KERNFS_ROOT_SUPPORT_USER_XATTR = 0x0008,
++
++ /*
++ * Renames must not change the parent node.
++ */
++ KERNFS_ROOT_INVARIANT_PARENT = 0x0010,
+ };
+
+ /* type-specific structures for kernfs_node union members */
+@@ -199,8 +204,8 @@ struct kernfs_node {
+ * never moved to a different parent, it is safe to access the
+ * parent directly.
+ */
+- struct kernfs_node *parent;
+ const char *name;
++ struct kernfs_node __rcu *__parent;
+
+ struct rb_node rb;
+
+@@ -416,6 +421,7 @@ struct dentry *kernfs_node_dentry(struct kernfs_node *kn,
+ struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops,
+ unsigned int flags, void *priv);
+ void kernfs_destroy_root(struct kernfs_root *root);
++unsigned int kernfs_root_flags(struct kernfs_node *kn);
+
+ struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent,
+ const char *name, umode_t mode,
+@@ -514,6 +520,8 @@ kernfs_create_root(struct kernfs_syscall_ops *scops, unsigned int flags,
+ { return ERR_PTR(-ENOSYS); }
+
+ static inline void kernfs_destroy_root(struct kernfs_root *root) { }
++static inline unsigned int kernfs_root_flags(struct kernfs_node *kn)
++{ return 0; }
+
+ static inline struct kernfs_node *
+ kernfs_create_dir_ns(struct kernfs_node *parent, const char *name,
+diff --git a/kernel/cgroup/cgroup-v1.c b/kernel/cgroup/cgroup-v1.c
+index e28d5f0d20ed0..c9752eb607ec9 100644
+--- a/kernel/cgroup/cgroup-v1.c
++++ b/kernel/cgroup/cgroup-v1.c
+@@ -844,7 +844,7 @@ static int cgroup1_rename(struct kernfs_node *kn, struct kernfs_node *new_parent
+
+ if (kernfs_type(kn) != KERNFS_DIR)
+ return -ENOTDIR;
+- if (kn->parent != new_parent)
++ if (rcu_access_pointer(kn->__parent) != new_parent)
+ return -EIO;
+
+ /*
+diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
+index 660d27a0cb3d4..1e2bc9f74fe29 100644
+--- a/kernel/cgroup/cgroup.c
++++ b/kernel/cgroup/cgroup.c
+@@ -633,9 +633,22 @@ int cgroup_task_count(const struct cgroup *cgrp)
+ return count;
+ }
+
++static struct cgroup *kn_priv(struct kernfs_node *kn)
++{
++ struct kernfs_node *parent;
++ /*
++ * The parent can not be replaced due to KERNFS_ROOT_INVARIANT_PARENT.
++ * Therefore it is always safe to dereference this pointer outside of a
++ * RCU section.
++ */
++ parent = rcu_dereference_check(kn->__parent,
++ kernfs_root_flags(kn) & KERNFS_ROOT_INVARIANT_PARENT);
++ return parent->priv;
++}
++
+ struct cgroup_subsys_state *of_css(struct kernfs_open_file *of)
+ {
+- struct cgroup *cgrp = of->kn->parent->priv;
++ struct cgroup *cgrp = kn_priv(of->kn);
+ struct cftype *cft = of_cft(of);
+
+ /*
+@@ -1612,7 +1625,7 @@ void cgroup_kn_unlock(struct kernfs_node *kn)
+ if (kernfs_type(kn) == KERNFS_DIR)
+ cgrp = kn->priv;
+ else
+- cgrp = kn->parent->priv;
++ cgrp = kn_priv(kn);
+
+ cgroup_unlock();
+
+@@ -1644,7 +1657,7 @@ struct cgroup *cgroup_kn_lock_live(struct kernfs_node *kn, bool drain_offline)
+ if (kernfs_type(kn) == KERNFS_DIR)
+ cgrp = kn->priv;
+ else
+- cgrp = kn->parent->priv;
++ cgrp = kn_priv(kn);
+
+ /*
+ * We're gonna grab cgroup_mutex which nests outside kernfs
+@@ -2118,7 +2131,8 @@ int cgroup_setup_root(struct cgroup_root *root, u16 ss_mask)
+ root->kf_root = kernfs_create_root(kf_sops,
+ KERNFS_ROOT_CREATE_DEACTIVATED |
+ KERNFS_ROOT_SUPPORT_EXPORTOP |
+- KERNFS_ROOT_SUPPORT_USER_XATTR,
++ KERNFS_ROOT_SUPPORT_USER_XATTR |
++ KERNFS_ROOT_INVARIANT_PARENT,
+ root_cgrp);
+ if (IS_ERR(root->kf_root)) {
+ ret = PTR_ERR(root->kf_root);
+@@ -4144,7 +4158,7 @@ static ssize_t cgroup_file_write(struct kernfs_open_file *of, char *buf,
+ size_t nbytes, loff_t off)
+ {
+ struct cgroup_file_ctx *ctx = of->priv;
+- struct cgroup *cgrp = of->kn->parent->priv;
++ struct cgroup *cgrp = kn_priv(of->kn);
+ struct cftype *cft = of_cft(of);
+ struct cgroup_subsys_state *css;
+ int ret;
+diff --git a/tools/testing/selftests/bpf/progs/profiler.inc.h b/tools/testing/selftests/bpf/progs/profiler.inc.h
+index 8bd1ebd7d6afd..813143b4985dc 100644
+--- a/tools/testing/selftests/bpf/progs/profiler.inc.h
++++ b/tools/testing/selftests/bpf/progs/profiler.inc.h
+@@ -223,7 +223,7 @@ static INLINE void* read_full_cgroup_path(struct kernfs_node* cgroup_node,
+ if (bpf_cmp_likely(filepart_length, <=, MAX_PATH)) {
+ payload += filepart_length;
+ }
+- cgroup_node = BPF_CORE_READ(cgroup_node, parent);
++ cgroup_node = BPF_CORE_READ(cgroup_node, __parent);
+ }
+ return payload;
+ }
+--
+2.39.5
+
--- /dev/null
+From 1aeee13f00992342bd96176b6fcd3728c7ce23ab Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 13 Mar 2025 19:27:13 +0000
+Subject: kunit: tool: Fix bug in parsing test plan
+
+From: Rae Moar <rmoar@google.com>
+
+[ Upstream commit 1d4c06d51963f89f67c7b75d5c0c34e9d1bb2ae6 ]
+
+A bug was identified where the KTAP below caused an infinite loop:
+
+ TAP version 13
+ ok 4 test_case
+ 1..4
+
+The infinite loop was caused by the parser not parsing a test plan
+if following a test result line.
+
+Fix this bug by parsing test plan line to avoid the infinite loop.
+
+Link: https://lore.kernel.org/r/20250313192714.1380005-1-rmoar@google.com
+Signed-off-by: Rae Moar <rmoar@google.com>
+Reviewed-by: David Gow <davidgow@google.com>
+Signed-off-by: Shuah Khan <shuah@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/testing/kunit/kunit_parser.py | 9 ++++-----
+ 1 file changed, 4 insertions(+), 5 deletions(-)
+
+diff --git a/tools/testing/kunit/kunit_parser.py b/tools/testing/kunit/kunit_parser.py
+index 29fc27e8949bd..da53a709773a2 100644
+--- a/tools/testing/kunit/kunit_parser.py
++++ b/tools/testing/kunit/kunit_parser.py
+@@ -759,7 +759,7 @@ def parse_test(lines: LineStream, expected_num: int, log: List[str], is_subtest:
+ # If parsing the main/top-level test, parse KTAP version line and
+ # test plan
+ test.name = "main"
+- ktap_line = parse_ktap_header(lines, test, printer)
++ parse_ktap_header(lines, test, printer)
+ test.log.extend(parse_diagnostic(lines))
+ parse_test_plan(lines, test)
+ parent_test = True
+@@ -768,13 +768,12 @@ def parse_test(lines: LineStream, expected_num: int, log: List[str], is_subtest:
+ # the KTAP version line and/or subtest header line
+ ktap_line = parse_ktap_header(lines, test, printer)
+ subtest_line = parse_test_header(lines, test)
++ test.log.extend(parse_diagnostic(lines))
++ parse_test_plan(lines, test)
+ parent_test = (ktap_line or subtest_line)
+ if parent_test:
+- # If KTAP version line and/or subtest header is found, attempt
+- # to parse test plan and print test header
+- test.log.extend(parse_diagnostic(lines))
+- parse_test_plan(lines, test)
+ print_test_header(test, printer)
++
+ expected_count = test.expected_count
+ subtests = []
+ test_num = 1
+--
+2.39.5
+
--- /dev/null
+From a95d9511a99ff5e66f65491232afeedcc6a1d827 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 24 Jan 2025 11:01:42 +0000
+Subject: kunit: tool: Use qboot on QEMU x86_64
+
+From: Brendan Jackman <jackmanb@google.com>
+
+[ Upstream commit 08fafac4c9f289a9d9a22d838921e4b3eb22c664 ]
+
+As noted in [0], SeaBIOS (QEMU default) makes a mess of the terminal,
+qboot does not.
+
+It turns out this is actually useful with kunit.py, since the user is
+exposed to this issue if they set --raw_output=all.
+
+qboot is also faster than SeaBIOS, but it's is marginal for this
+usecase.
+
+[0] https://lore.kernel.org/all/CA+i-1C0wYb-gZ8Mwh3WSVpbk-LF-Uo+njVbASJPe1WXDURoV7A@mail.gmail.com/
+
+Both SeaBIOS and qboot are x86-specific.
+
+Link: https://lore.kernel.org/r/20250124-kunit-qboot-v1-1-815e4d4c6f7c@google.com
+Signed-off-by: Brendan Jackman <jackmanb@google.com>
+Reviewed-by: David Gow <davidgow@google.com>
+Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/testing/kunit/qemu_configs/x86_64.py | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/tools/testing/kunit/qemu_configs/x86_64.py b/tools/testing/kunit/qemu_configs/x86_64.py
+index dc79490768630..4a6bf4e048f5b 100644
+--- a/tools/testing/kunit/qemu_configs/x86_64.py
++++ b/tools/testing/kunit/qemu_configs/x86_64.py
+@@ -7,4 +7,6 @@ CONFIG_SERIAL_8250_CONSOLE=y''',
+ qemu_arch='x86_64',
+ kernel_path='arch/x86/boot/bzImage',
+ kernel_command_line='console=ttyS0',
+- extra_qemu_params=[])
++ # qboot is faster than SeaBIOS and doesn't mess up
++ # the terminal.
++ extra_qemu_params=['-bios', 'qboot.rom'])
+--
+2.39.5
+
--- /dev/null
+From de40986e4d227334420ed2852ca69982f374d3ad Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Feb 2025 17:12:50 +0000
+Subject: leds: Kconfig: leds-st1202: Add select for required
+ LEDS_TRIGGER_PATTERN
+
+From: Manuel Fombuena <fombuena@outlook.com>
+
+[ Upstream commit be2f92844d0f8cb059cb6958c6d9582d381ca68e ]
+
+leds-st1202 requires the LED Pattern Trigger (LEDS_TRIGGER_PATTERN), which
+is not selected when LED Trigger support is (LEDS_TRIGGERS).
+
+To reproduce this:
+
+- make menuconfig KCONFIG_CONFIG=
+- select LEDS_ST1202 dependencies OF, I2C and LEDS_CLASS.
+- select LEDS_ST1202
+- LEDS_TRIGGERS is selected but LEDS_TRIGGER_PATTERN isn't.
+
+The absence of LEDS_TRIGGER_PATTERN explicitly required can lead to builds
+in which LEDS_ST1202 is selected while LEDS_TRIGGER_PATTERN isn't. The direct
+result of that would be that /sys/class/leds/<led>/hw_pattern wouldn't be
+available and there would be no way of interacting with the driver and
+hardware from user space.
+
+Add select LEDS_TRIGGER_PATTERN to Kconfig to meet the requirement and
+indirectly document it as well.
+
+Signed-off-by: Manuel Fombuena <fombuena@outlook.com>
+Link: https://lore.kernel.org/r/CWLP123MB5473F4DF3A668F7DD057A280C5C22@CWLP123MB5473.GBRP123.PROD.OUTLOOK.COM
+Signed-off-by: Lee Jones <lee@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/leds/Kconfig | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
+index 2b27d043921ce..8859e8fe292a9 100644
+--- a/drivers/leds/Kconfig
++++ b/drivers/leds/Kconfig
+@@ -971,6 +971,7 @@ config LEDS_ST1202
+ depends on I2C
+ depends on OF
+ select LEDS_TRIGGERS
++ select LEDS_TRIGGER_PATTERN
+ help
+ Say Y to enable support for LEDs connected to LED1202
+ LED driver chips accessed via the I2C bus.
+--
+2.39.5
+
--- /dev/null
+From 8c75dcdf583bcd389d4398eb3ab9e3ff87e4bedb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Feb 2025 17:06:40 +0000
+Subject: leds: leds-st1202: Initialize hardware before DT node child
+ operations
+
+From: Manuel Fombuena <fombuena@outlook.com>
+
+[ Upstream commit a17d9e736ddd78323e77d3066c1e86371a99023c ]
+
+Arguably, there are more chances of errors occurring during the
+initialization of the hardware, so this should complete successfully
+before the devicetree node's children are initialized.
+
+st1202_dt_init() fills the led_classdev struct.
+
+st1202_setup() initializes the hardware. Specifically, resets the chip,
+enables its phase-shift delay feature, enables the device and disables all
+the LEDs channels. All that writing to registers, with no input from
+st1202_dt_init().
+
+Real-world testing corroborates that calling st1202_setup() before
+st1202_dt_init() doesn't cause any issue during initialization.
+
+Switch the order of st1202_dt_init() and st1202_setup() to ensure the
+hardware is correctly initialized before the led_classdev struct is
+filled.
+
+Signed-off-by: Manuel Fombuena <fombuena@outlook.com>
+Link: https://lore.kernel.org/r/CWLP123MB54731877A8DC54EDD33F0229C5C22@CWLP123MB5473.GBRP123.PROD.OUTLOOK.COM
+Signed-off-by: Lee Jones <lee@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/leds/leds-st1202.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/leds/leds-st1202.c b/drivers/leds/leds-st1202.c
+index 4cebc0203c227..ccea216c11f9b 100644
+--- a/drivers/leds/leds-st1202.c
++++ b/drivers/leds/leds-st1202.c
+@@ -350,11 +350,11 @@ static int st1202_probe(struct i2c_client *client)
+ return ret;
+ chip->client = client;
+
+- ret = st1202_dt_init(chip);
++ ret = st1202_setup(chip);
+ if (ret < 0)
+ return ret;
+
+- ret = st1202_setup(chip);
++ ret = st1202_dt_init(chip);
+ if (ret < 0)
+ return ret;
+
+--
+2.39.5
+
--- /dev/null
+From d87288cdf9580e775d65ab21d9e00589fbb8da43 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 23 Feb 2025 20:14:59 +0800
+Subject: leds: pwm-multicolor: Add check for fwnode_property_read_u32
+
+From: Yuanjun Gong <ruc_gongyuanjun@163.com>
+
+[ Upstream commit 6d91124e7edc109f114b1afe6d00d85d0d0ac174 ]
+
+Add a check to the return value of fwnode_property_read_u32()
+in case it fails.
+
+Signed-off-by: Yuanjun Gong <ruc_gongyuanjun@163.com>
+Link: https://lore.kernel.org/r/20250223121459.2889484-1-ruc_gongyuanjun@163.com
+Signed-off-by: Lee Jones <lee@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/leds/rgb/leds-pwm-multicolor.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/leds/rgb/leds-pwm-multicolor.c b/drivers/leds/rgb/leds-pwm-multicolor.c
+index f80a06cc31f8a..1c7705bafdfc7 100644
+--- a/drivers/leds/rgb/leds-pwm-multicolor.c
++++ b/drivers/leds/rgb/leds-pwm-multicolor.c
+@@ -141,8 +141,11 @@ static int led_pwm_mc_probe(struct platform_device *pdev)
+
+ /* init the multicolor's LED class device */
+ cdev = &priv->mc_cdev.led_cdev;
+- fwnode_property_read_u32(mcnode, "max-brightness",
++ ret = fwnode_property_read_u32(mcnode, "max-brightness",
+ &cdev->max_brightness);
++ if (ret)
++ goto release_mcnode;
++
+ cdev->flags = LED_CORE_SUSPENDRESUME;
+ cdev->brightness_set_blocking = led_pwm_mc_set;
+
+--
+2.39.5
+
--- /dev/null
+From fd6258d20e37b52572d9668850bf6ae07f065b7f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 20 Jan 2025 12:36:53 +0100
+Subject: leds: trigger: netdev: Configure LED blink interval for HW offload
+
+From: Marek Vasut <marex@denx.de>
+
+[ Upstream commit c629c972b310af41e9e072febb6dae9a299edde6 ]
+
+In case a PHY LED implements .blink_set callback to set LED blink
+interval, call it even if .hw_control is already set, as that LED
+blink interval likely controls the blink rate of that HW offloaded
+LED. For PHY LEDs, that can be their activity blinking interval.
+
+The software blinking is not affected by this change.
+
+With this change, the LED interval setting looks something like this:
+$ echo netdev > /sys/class/leds/led:green:lan/trigger
+$ echo 1 > /sys/class/leds/led:green:lan/brightness
+$ echo 250 > /sys/class/leds/led:green:lan/interval
+
+Signed-off-by: Marek Vasut <marex@denx.de>
+Link: https://lore.kernel.org/r/20250120113740.91807-1-marex@denx.de
+Signed-off-by: Lee Jones <lee@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/leds/trigger/ledtrig-netdev.c | 16 +++++++++++++---
+ 1 file changed, 13 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c
+index c15efe3e50780..4e048e08c4fde 100644
+--- a/drivers/leds/trigger/ledtrig-netdev.c
++++ b/drivers/leds/trigger/ledtrig-netdev.c
+@@ -68,6 +68,7 @@ struct led_netdev_data {
+ unsigned int last_activity;
+
+ unsigned long mode;
++ unsigned long blink_delay;
+ int link_speed;
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(supported_link_modes);
+ u8 duplex;
+@@ -86,6 +87,10 @@ static void set_baseline_state(struct led_netdev_data *trigger_data)
+ /* Already validated, hw control is possible with the requested mode */
+ if (trigger_data->hw_control) {
+ led_cdev->hw_control_set(led_cdev, trigger_data->mode);
++ if (led_cdev->blink_set) {
++ led_cdev->blink_set(led_cdev, &trigger_data->blink_delay,
++ &trigger_data->blink_delay);
++ }
+
+ return;
+ }
+@@ -454,10 +459,11 @@ static ssize_t interval_store(struct device *dev,
+ size_t size)
+ {
+ struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
++ struct led_classdev *led_cdev = trigger_data->led_cdev;
+ unsigned long value;
+ int ret;
+
+- if (trigger_data->hw_control)
++ if (trigger_data->hw_control && !led_cdev->blink_set)
+ return -EINVAL;
+
+ ret = kstrtoul(buf, 0, &value);
+@@ -466,9 +472,13 @@ static ssize_t interval_store(struct device *dev,
+
+ /* impose some basic bounds on the timer interval */
+ if (value >= 5 && value <= 10000) {
+- cancel_delayed_work_sync(&trigger_data->work);
++ if (trigger_data->hw_control) {
++ trigger_data->blink_delay = value;
++ } else {
++ cancel_delayed_work_sync(&trigger_data->work);
+
+- atomic_set(&trigger_data->interval, msecs_to_jiffies(value));
++ atomic_set(&trigger_data->interval, msecs_to_jiffies(value));
++ }
+ set_baseline_state(trigger_data); /* resets timer */
+ }
+
+--
+2.39.5
+
--- /dev/null
+From e2547548c76d0c0e4aea2a3ba6a418d18ac58cd5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Feb 2025 17:48:08 -0800
+Subject: libbpf: fix LDX/STX/ST CO-RE relocation size adjustment logic
+
+From: Andrii Nakryiko <andrii@kernel.org>
+
+[ Upstream commit 06096d19ee3897a7e70922580159607fe315da7a ]
+
+Libbpf has a somewhat obscure feature of automatically adjusting the
+"size" of LDX/STX/ST instruction (memory store and load instructions),
+based on originally recorded access size (u8, u16, u32, or u64) and the
+actual size of the field on target kernel. This is meant to facilitate
+using BPF CO-RE on 32-bit architectures (pointers are always 64-bit in
+BPF, but host kernel's BTF will have it as 32-bit type), as well as
+generally supporting safe type changes (unsigned integer type changes
+can be transparently "relocated").
+
+One issue that surfaced only now, 5 years after this logic was
+implemented, is how this all works when dealing with fields that are
+arrays. This isn't all that easy and straightforward to hit (see
+selftests that reproduce this condition), but one of sched_ext BPF
+programs did hit it with innocent looking loop.
+
+Long story short, libbpf used to calculate entire array size, instead of
+making sure to only calculate array's element size. But it's the element
+that is loaded by LDX/STX/ST instructions (1, 2, 4, or 8 bytes), so
+that's what libbpf should check. This patch adjusts the logic for
+arrays and fixed the issue.
+
+Reported-by: Emil Tsalapatis <emil@etsalapatis.com>
+Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
+Acked-by: Eduard Zingerman <eddyz87@gmail.com>
+Link: https://lore.kernel.org/r/20250207014809.1573841-1-andrii@kernel.org
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/lib/bpf/relo_core.c | 24 ++++++++++++++++++++----
+ 1 file changed, 20 insertions(+), 4 deletions(-)
+
+diff --git a/tools/lib/bpf/relo_core.c b/tools/lib/bpf/relo_core.c
+index 7632e9d418271..2b83c98a11372 100644
+--- a/tools/lib/bpf/relo_core.c
++++ b/tools/lib/bpf/relo_core.c
+@@ -683,7 +683,7 @@ static int bpf_core_calc_field_relo(const char *prog_name,
+ {
+ const struct bpf_core_accessor *acc;
+ const struct btf_type *t;
+- __u32 byte_off, byte_sz, bit_off, bit_sz, field_type_id;
++ __u32 byte_off, byte_sz, bit_off, bit_sz, field_type_id, elem_id;
+ const struct btf_member *m;
+ const struct btf_type *mt;
+ bool bitfield;
+@@ -706,8 +706,14 @@ static int bpf_core_calc_field_relo(const char *prog_name,
+ if (!acc->name) {
+ if (relo->kind == BPF_CORE_FIELD_BYTE_OFFSET) {
+ *val = spec->bit_offset / 8;
+- /* remember field size for load/store mem size */
+- sz = btf__resolve_size(spec->btf, acc->type_id);
++ /* remember field size for load/store mem size;
++ * note, for arrays we care about individual element
++ * sizes, not the overall array size
++ */
++ t = skip_mods_and_typedefs(spec->btf, acc->type_id, &elem_id);
++ while (btf_is_array(t))
++ t = skip_mods_and_typedefs(spec->btf, btf_array(t)->type, &elem_id);
++ sz = btf__resolve_size(spec->btf, elem_id);
+ if (sz < 0)
+ return -EINVAL;
+ *field_sz = sz;
+@@ -767,7 +773,17 @@ static int bpf_core_calc_field_relo(const char *prog_name,
+ case BPF_CORE_FIELD_BYTE_OFFSET:
+ *val = byte_off;
+ if (!bitfield) {
+- *field_sz = byte_sz;
++ /* remember field size for load/store mem size;
++ * note, for arrays we care about individual element
++ * sizes, not the overall array size
++ */
++ t = skip_mods_and_typedefs(spec->btf, field_type_id, &elem_id);
++ while (btf_is_array(t))
++ t = skip_mods_and_typedefs(spec->btf, btf_array(t)->type, &elem_id);
++ sz = btf__resolve_size(spec->btf, elem_id);
++ if (sz < 0)
++ return -EINVAL;
++ *field_sz = sz;
+ *type_id = field_type_id;
+ }
+ break;
+--
+2.39.5
+
--- /dev/null
+From a72f65f82e39f3f8ec5f6fe3ad13e189fced1870 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 22 Feb 2025 02:31:11 +0530
+Subject: libbpf: Fix out-of-bound read
+
+From: Nandakumar Edamana <nandakumar@nandakumar.co.in>
+
+[ Upstream commit 236d3910117e9f97ebf75e511d8bcc950f1a4e5f ]
+
+In `set_kcfg_value_str`, an untrusted string is accessed with the assumption
+that it will be at least two characters long due to the presence of checks for
+opening and closing quotes. But the check for the closing quote
+(value[len - 1] != '"') misses the fact that it could be checking the opening
+quote itself in case of an invalid input that consists of just the opening
+quote.
+
+This commit adds an explicit check to make sure the string is at least two
+characters long.
+
+Signed-off-by: Nandakumar Edamana <nandakumar@nandakumar.co.in>
+Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
+Link: https://lore.kernel.org/bpf/20250221210110.3182084-1-nandakumar@nandakumar.co.in
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/lib/bpf/libbpf.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
+index 6b436ec872b0f..1791a12b1aac5 100644
+--- a/tools/lib/bpf/libbpf.c
++++ b/tools/lib/bpf/libbpf.c
+@@ -2106,7 +2106,7 @@ static int set_kcfg_value_str(struct extern_desc *ext, char *ext_val,
+ }
+
+ len = strlen(value);
+- if (value[len - 1] != '"') {
++ if (len < 2 || value[len - 1] != '"') {
+ pr_warn("extern (kcfg) '%s': invalid string config '%s'\n",
+ ext->name, value);
+ return -EINVAL;
+--
+2.39.5
+
--- /dev/null
+From 7a8beec7026564efe57ebf9c4c568ed0071f2e39 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 17 Mar 2025 17:40:38 +0000
+Subject: libbpf: Pass BPF token from find_prog_btf_id to BPF_BTF_GET_FD_BY_ID
+
+From: Mykyta Yatsenko <yatsenko@meta.com>
+
+[ Upstream commit 974ef9f0d23edc1a802691c585b84514b414a96d ]
+
+Pass BPF token from bpf_program__set_attach_target to
+BPF_BTF_GET_FD_BY_ID bpf command.
+When freplace program attaches to target program, it needs to look up
+for BTF of the target, this may require BPF token, if, for example,
+running from user namespace.
+
+Signed-off-by: Mykyta Yatsenko <yatsenko@meta.com>
+Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
+Acked-by: Yonghong Song <yonghong.song@linux.dev>
+Link: https://lore.kernel.org/bpf/20250317174039.161275-4-mykyta.yatsenko5@gmail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/lib/bpf/bpf.c | 3 ++-
+ tools/lib/bpf/bpf.h | 3 ++-
+ tools/lib/bpf/btf.c | 15 +++++++++++++--
+ tools/lib/bpf/libbpf.c | 10 +++++-----
+ tools/lib/bpf/libbpf_internal.h | 1 +
+ 5 files changed, 23 insertions(+), 9 deletions(-)
+
+diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
+index 359f73ead6137..a9c3e33d0f8a9 100644
+--- a/tools/lib/bpf/bpf.c
++++ b/tools/lib/bpf/bpf.c
+@@ -1097,7 +1097,7 @@ int bpf_map_get_fd_by_id(__u32 id)
+ int bpf_btf_get_fd_by_id_opts(__u32 id,
+ const struct bpf_get_fd_by_id_opts *opts)
+ {
+- const size_t attr_sz = offsetofend(union bpf_attr, open_flags);
++ const size_t attr_sz = offsetofend(union bpf_attr, fd_by_id_token_fd);
+ union bpf_attr attr;
+ int fd;
+
+@@ -1107,6 +1107,7 @@ int bpf_btf_get_fd_by_id_opts(__u32 id,
+ memset(&attr, 0, attr_sz);
+ attr.btf_id = id;
+ attr.open_flags = OPTS_GET(opts, open_flags, 0);
++ attr.fd_by_id_token_fd = OPTS_GET(opts, token_fd, 0);
+
+ fd = sys_bpf_fd(BPF_BTF_GET_FD_BY_ID, &attr, attr_sz);
+ return libbpf_err_errno(fd);
+diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
+index 435da95d20589..777627d33d257 100644
+--- a/tools/lib/bpf/bpf.h
++++ b/tools/lib/bpf/bpf.h
+@@ -487,9 +487,10 @@ LIBBPF_API int bpf_link_get_next_id(__u32 start_id, __u32 *next_id);
+ struct bpf_get_fd_by_id_opts {
+ size_t sz; /* size of this struct for forward/backward compatibility */
+ __u32 open_flags; /* permissions requested for the operation on fd */
++ __u32 token_fd;
+ size_t :0;
+ };
+-#define bpf_get_fd_by_id_opts__last_field open_flags
++#define bpf_get_fd_by_id_opts__last_field token_fd
+
+ LIBBPF_API int bpf_prog_get_fd_by_id(__u32 id);
+ LIBBPF_API int bpf_prog_get_fd_by_id_opts(__u32 id,
+diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c
+index 560b519f820e2..03cc7c46c16b5 100644
+--- a/tools/lib/bpf/btf.c
++++ b/tools/lib/bpf/btf.c
+@@ -1619,12 +1619,18 @@ struct btf *btf_get_from_fd(int btf_fd, struct btf *base_btf)
+ return btf;
+ }
+
+-struct btf *btf__load_from_kernel_by_id_split(__u32 id, struct btf *base_btf)
++struct btf *btf_load_from_kernel(__u32 id, struct btf *base_btf, int token_fd)
+ {
+ struct btf *btf;
+ int btf_fd;
++ LIBBPF_OPTS(bpf_get_fd_by_id_opts, opts);
++
++ if (token_fd) {
++ opts.open_flags |= BPF_F_TOKEN_FD;
++ opts.token_fd = token_fd;
++ }
+
+- btf_fd = bpf_btf_get_fd_by_id(id);
++ btf_fd = bpf_btf_get_fd_by_id_opts(id, &opts);
+ if (btf_fd < 0)
+ return libbpf_err_ptr(-errno);
+
+@@ -1634,6 +1640,11 @@ struct btf *btf__load_from_kernel_by_id_split(__u32 id, struct btf *base_btf)
+ return libbpf_ptr(btf);
+ }
+
++struct btf *btf__load_from_kernel_by_id_split(__u32 id, struct btf *base_btf)
++{
++ return btf_load_from_kernel(id, base_btf, 0);
++}
++
+ struct btf *btf__load_from_kernel_by_id(__u32 id)
+ {
+ return btf__load_from_kernel_by_id_split(id, NULL);
+diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
+index 194809da51725..6b436ec872b0f 100644
+--- a/tools/lib/bpf/libbpf.c
++++ b/tools/lib/bpf/libbpf.c
+@@ -9959,7 +9959,7 @@ int libbpf_find_vmlinux_btf_id(const char *name,
+ return libbpf_err(err);
+ }
+
+-static int libbpf_find_prog_btf_id(const char *name, __u32 attach_prog_fd)
++static int libbpf_find_prog_btf_id(const char *name, __u32 attach_prog_fd, int token_fd)
+ {
+ struct bpf_prog_info info;
+ __u32 info_len = sizeof(info);
+@@ -9979,7 +9979,7 @@ static int libbpf_find_prog_btf_id(const char *name, __u32 attach_prog_fd)
+ pr_warn("The target program doesn't have BTF\n");
+ goto out;
+ }
+- btf = btf__load_from_kernel_by_id(info.btf_id);
++ btf = btf_load_from_kernel(info.btf_id, NULL, token_fd);
+ err = libbpf_get_error(btf);
+ if (err) {
+ pr_warn("Failed to get BTF %d of the program: %s\n", info.btf_id, errstr(err));
+@@ -10062,7 +10062,7 @@ static int libbpf_find_attach_btf_id(struct bpf_program *prog, const char *attac
+ pr_warn("prog '%s': attach program FD is not set\n", prog->name);
+ return -EINVAL;
+ }
+- err = libbpf_find_prog_btf_id(attach_name, attach_prog_fd);
++ err = libbpf_find_prog_btf_id(attach_name, attach_prog_fd, prog->obj->token_fd);
+ if (err < 0) {
+ pr_warn("prog '%s': failed to find BPF program (FD %d) BTF ID for '%s': %s\n",
+ prog->name, attach_prog_fd, attach_name, errstr(err));
+@@ -12858,7 +12858,7 @@ struct bpf_link *bpf_program__attach_freplace(const struct bpf_program *prog,
+ if (target_fd) {
+ LIBBPF_OPTS(bpf_link_create_opts, target_opts);
+
+- btf_id = libbpf_find_prog_btf_id(attach_func_name, target_fd);
++ btf_id = libbpf_find_prog_btf_id(attach_func_name, target_fd, prog->obj->token_fd);
+ if (btf_id < 0)
+ return libbpf_err_ptr(btf_id);
+
+@@ -13679,7 +13679,7 @@ int bpf_program__set_attach_target(struct bpf_program *prog,
+
+ if (attach_prog_fd) {
+ btf_id = libbpf_find_prog_btf_id(attach_func_name,
+- attach_prog_fd);
++ attach_prog_fd, prog->obj->token_fd);
+ if (btf_id < 0)
+ return libbpf_err(btf_id);
+ } else {
+diff --git a/tools/lib/bpf/libbpf_internal.h b/tools/lib/bpf/libbpf_internal.h
+index de498e2dd6b0b..76669c73dcd16 100644
+--- a/tools/lib/bpf/libbpf_internal.h
++++ b/tools/lib/bpf/libbpf_internal.h
+@@ -409,6 +409,7 @@ int libbpf__load_raw_btf(const char *raw_types, size_t types_len,
+ int btf_load_into_kernel(struct btf *btf,
+ char *log_buf, size_t log_sz, __u32 log_level,
+ int token_fd);
++struct btf *btf_load_from_kernel(__u32 id, struct btf *base_btf, int token_fd);
+
+ struct btf *btf_get_from_fd(int btf_fd, struct btf *base_btf);
+ void btf_get_kernel_prefix_kind(enum bpf_attach_type attach_type,
+--
+2.39.5
+
--- /dev/null
+From 040ac72b937fe02c207a0544d48d1f4654d437b8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 20 Mar 2025 12:22:22 +0100
+Subject: libnvdimm/labels: Fix divide error in nd_label_data_init()
+
+From: Robert Richter <rrichter@amd.com>
+
+[ Upstream commit ef1d3455bbc1922f94a91ed58d3d7db440652959 ]
+
+If a faulty CXL memory device returns a broken zero LSA size in its
+memory device information (Identify Memory Device (Opcode 4000h), CXL
+spec. 3.1, 8.2.9.9.1.1), a divide error occurs in the libnvdimm
+driver:
+
+ Oops: divide error: 0000 [#1] PREEMPT SMP NOPTI
+ RIP: 0010:nd_label_data_init+0x10e/0x800 [libnvdimm]
+
+Code and flow:
+
+1) CXL Command 4000h returns LSA size = 0
+2) config_size is assigned to zero LSA size (CXL pmem driver):
+
+drivers/cxl/pmem.c: .config_size = mds->lsa_size,
+
+3) max_xfer is set to zero (nvdimm driver):
+
+drivers/nvdimm/label.c: max_xfer = min_t(size_t, ndd->nsarea.max_xfer, config_size);
+
+4) A subsequent DIV_ROUND_UP() causes a division by zero:
+
+drivers/nvdimm/label.c: /* Make our initial read size a multiple of max_xfer size */
+drivers/nvdimm/label.c: read_size = min(DIV_ROUND_UP(read_size, max_xfer) * max_xfer,
+drivers/nvdimm/label.c- config_size);
+
+Fix this by checking the config size parameter by extending an
+existing check.
+
+Signed-off-by: Robert Richter <rrichter@amd.com>
+Reviewed-by: Pankaj Gupta <pankaj.gupta@amd.com>
+Reviewed-by: Ira Weiny <ira.weiny@intel.com>
+Link: https://patch.msgid.link/20250320112223.608320-1-rrichter@amd.com
+Signed-off-by: Ira Weiny <ira.weiny@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/nvdimm/label.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c
+index 082253a3a9560..04f4a049599a1 100644
+--- a/drivers/nvdimm/label.c
++++ b/drivers/nvdimm/label.c
+@@ -442,7 +442,8 @@ int nd_label_data_init(struct nvdimm_drvdata *ndd)
+ if (ndd->data)
+ return 0;
+
+- if (ndd->nsarea.status || ndd->nsarea.max_xfer == 0) {
++ if (ndd->nsarea.status || ndd->nsarea.max_xfer == 0 ||
++ ndd->nsarea.config_size == 0) {
+ dev_dbg(ndd->dev, "failed to init config data area: (%u:%u)\n",
+ ndd->nsarea.max_xfer, ndd->nsarea.config_size);
+ return -ENXIO;
+--
+2.39.5
+
--- /dev/null
+From 2dfb8b75b57370d50db318243a05a7d0b0d2304e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 21 Mar 2025 07:33:22 -0700
+Subject: lockdep: Fix wait context check on softirq for PREEMPT_RT
+
+From: Ryo Takakura <ryotkkr98@gmail.com>
+
+[ Upstream commit 61c39d8c83e2077f33e0a2c8980a76a7f323f0ce ]
+
+Since:
+
+ 0c1d7a2c2d32 ("lockdep: Remove softirq accounting on PREEMPT_RT.")
+
+the wait context test for mutex usage within "in softirq context" fails
+as it references @softirq_context:
+
+ | wait context tests |
+ --------------------------------------------------------------------------
+ | rcu | raw | spin |mutex |
+ --------------------------------------------------------------------------
+ in hardirq context: ok | ok | ok | ok |
+ in hardirq context (not threaded): ok | ok | ok | ok |
+ in softirq context: ok | ok | ok |FAILED|
+
+As a fix, add lockdep map for BH disabled section. This fixes the
+issue by letting us catch cases when local_bh_disable() gets called
+with preemption disabled where local_lock doesn't get acquired.
+In the case of "in softirq context" selftest, local_bh_disable() was
+being called with preemption disable as it's early in the boot.
+
+[ boqun: Move the lockdep annotations into __local_bh_*() to avoid false
+ positives because of unpaired local_bh_disable() reported by
+ Borislav Petkov and Peter Zijlstra, and make bh_lock_map
+ only exist for PREEMPT_RT. ]
+
+[ mingo: Restored authorship and improved the bh_lock_map definition. ]
+
+Signed-off-by: Ryo Takakura <ryotkkr98@gmail.com>
+Signed-off-by: Boqun Feng <boqun.feng@gmail.com>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Link: https://lore.kernel.org/r/20250321143322.79651-1-boqun.feng@gmail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/softirq.c | 18 ++++++++++++++++++
+ 1 file changed, 18 insertions(+)
+
+diff --git a/kernel/softirq.c b/kernel/softirq.c
+index 4dae6ac2e83fb..513b1945987cc 100644
+--- a/kernel/softirq.c
++++ b/kernel/softirq.c
+@@ -126,6 +126,18 @@ static DEFINE_PER_CPU(struct softirq_ctrl, softirq_ctrl) = {
+ .lock = INIT_LOCAL_LOCK(softirq_ctrl.lock),
+ };
+
++#ifdef CONFIG_DEBUG_LOCK_ALLOC
++static struct lock_class_key bh_lock_key;
++struct lockdep_map bh_lock_map = {
++ .name = "local_bh",
++ .key = &bh_lock_key,
++ .wait_type_outer = LD_WAIT_FREE,
++ .wait_type_inner = LD_WAIT_CONFIG, /* PREEMPT_RT makes BH preemptible. */
++ .lock_type = LD_LOCK_PERCPU,
++};
++EXPORT_SYMBOL_GPL(bh_lock_map);
++#endif
++
+ /**
+ * local_bh_blocked() - Check for idle whether BH processing is blocked
+ *
+@@ -148,6 +160,8 @@ void __local_bh_disable_ip(unsigned long ip, unsigned int cnt)
+
+ WARN_ON_ONCE(in_hardirq());
+
++ lock_map_acquire_read(&bh_lock_map);
++
+ /* First entry of a task into a BH disabled section? */
+ if (!current->softirq_disable_cnt) {
+ if (preemptible()) {
+@@ -211,6 +225,8 @@ void __local_bh_enable_ip(unsigned long ip, unsigned int cnt)
+ WARN_ON_ONCE(in_hardirq());
+ lockdep_assert_irqs_enabled();
+
++ lock_map_release(&bh_lock_map);
++
+ local_irq_save(flags);
+ curcnt = __this_cpu_read(softirq_ctrl.cnt);
+
+@@ -261,6 +277,8 @@ static inline void ksoftirqd_run_begin(void)
+ /* Counterpart to ksoftirqd_run_begin() */
+ static inline void ksoftirqd_run_end(void)
+ {
++ /* pairs with the lock_map_acquire_read() in ksoftirqd_run_begin() */
++ lock_map_release(&bh_lock_map);
+ __local_bh_enable(SOFTIRQ_OFFSET, true);
+ WARN_ON_ONCE(in_interrupt());
+ local_irq_enable();
+--
+2.39.5
+
--- /dev/null
+From 741688b17cc8abdddbdbae15e8a51dfb139ce5cf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jan 2025 13:00:40 +0100
+Subject: loop: check in LO_FLAGS_DIRECT_IO in loop_default_blocksize
+
+From: Christoph Hellwig <hch@lst.de>
+
+[ Upstream commit f6f9e32fe1e454ae8ac0190b2c2bd6074914beec ]
+
+We can't go below the minimum direct I/O size no matter if direct I/O is
+enabled by passing in an O_DIRECT file descriptor or due to the explicit
+flag. Now that LO_FLAGS_DIRECT_IO is set earlier after assigning a
+backing file, loop_default_blocksize can check it instead of the
+O_DIRECT flag to handle both conditions.
+
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
+Link: https://lore.kernel.org/r/20250131120120.1315125-4-hch@lst.de
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/block/loop.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/block/loop.c b/drivers/block/loop.c
+index 1e5ef09cdde68..f68f86e9cb716 100644
+--- a/drivers/block/loop.c
++++ b/drivers/block/loop.c
+@@ -920,7 +920,7 @@ static unsigned int loop_default_blocksize(struct loop_device *lo,
+ struct block_device *backing_bdev)
+ {
+ /* In case of direct I/O, match underlying block size */
+- if ((lo->lo_backing_file->f_flags & O_DIRECT) && backing_bdev)
++ if ((lo->lo_flags & LO_FLAGS_DIRECT_IO) && backing_bdev)
+ return bdev_logical_block_size(backing_bdev);
+ return SECTOR_SIZE;
+ }
+--
+2.39.5
+
--- /dev/null
+From b2e23c6b7d6d2934c1cb6f0788143ab7e19cd1ea Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Mar 2025 15:29:55 +0800
+Subject: loop: move vfs_fsync() out of loop_update_dio()
+
+From: Ming Lei <ming.lei@redhat.com>
+
+[ Upstream commit 86947bdc28894520ed5aab0cf21b99ff0b659e07 ]
+
+If vfs_flush() is called with queue frozen, the queue freeze lock may be
+connected with FS internal lock, and lockdep warning can be triggered
+because the queue freeze lock is connected with too many global or
+sub-system locks.
+
+Fix the warning by moving vfs_fsync() out of loop_update_dio():
+
+- vfs_fsync() is only needed when switching to dio
+
+- only loop_change_fd() and loop_configure() may switch from buffered
+IO to direct IO, so call vfs_fsync() directly here. This way is safe
+because either loop is in unbound, or new file isn't attached
+
+- for the other two cases of set_status and set_block_size, direct IO
+can only become off, so no need to call vfs_fsync()
+
+Cc: Christoph Hellwig <hch@infradead.org>
+Reported-by: Kun Hu <huk23@m.fudan.edu.cn>
+Reported-by: Jiaji Qin <jjtan24@m.fudan.edu.cn>
+Closes: https://lore.kernel.org/linux-block/359BC288-B0B1-4815-9F01-3A349B12E816@m.fudan.edu.cn/T/#u
+Signed-off-by: Ming Lei <ming.lei@redhat.com>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Link: https://lore.kernel.org/r/20250318072955.3893805-1-ming.lei@redhat.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/block/loop.c | 20 ++++++++++++++------
+ 1 file changed, 14 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/block/loop.c b/drivers/block/loop.c
+index b378d2aa49f06..1e5ef09cdde68 100644
+--- a/drivers/block/loop.c
++++ b/drivers/block/loop.c
+@@ -205,8 +205,6 @@ static bool lo_can_use_dio(struct loop_device *lo)
+ */
+ static inline void loop_update_dio(struct loop_device *lo)
+ {
+- bool dio_in_use = lo->lo_flags & LO_FLAGS_DIRECT_IO;
+-
+ lockdep_assert_held(&lo->lo_mutex);
+ WARN_ON_ONCE(lo->lo_state == Lo_bound &&
+ lo->lo_queue->mq_freeze_depth == 0);
+@@ -215,10 +213,6 @@ static inline void loop_update_dio(struct loop_device *lo)
+ lo->lo_flags |= LO_FLAGS_DIRECT_IO;
+ if ((lo->lo_flags & LO_FLAGS_DIRECT_IO) && !lo_can_use_dio(lo))
+ lo->lo_flags &= ~LO_FLAGS_DIRECT_IO;
+-
+- /* flush dirty pages before starting to issue direct I/O */
+- if ((lo->lo_flags & LO_FLAGS_DIRECT_IO) && !dio_in_use)
+- vfs_fsync(lo->lo_backing_file, 0);
+ }
+
+ /**
+@@ -568,6 +562,13 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev,
+ if (get_loop_size(lo, file) != get_loop_size(lo, old_file))
+ goto out_err;
+
++ /*
++ * We might switch to direct I/O mode for the loop device, write back
++ * all dirty data the page cache now that so that the individual I/O
++ * operations don't have to do that.
++ */
++ vfs_fsync(file, 0);
++
+ /* and ... switch */
+ disk_force_media_change(lo->lo_disk);
+ memflags = blk_mq_freeze_queue(lo->lo_queue);
+@@ -1046,6 +1047,13 @@ static int loop_configure(struct loop_device *lo, blk_mode_t mode,
+ if (error)
+ goto out_unlock;
+
++ /*
++ * We might switch to direct I/O mode for the loop device, write back
++ * all dirty data the page cache now that so that the individual I/O
++ * operations don't have to do that.
++ */
++ vfs_fsync(file, 0);
++
+ loop_update_dio(lo);
+ loop_sysfs_init(lo);
+
+--
+2.39.5
+
--- /dev/null
+From 215648eacbcb644a682a773d15b096a4a8d9175d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 13 Mar 2025 15:28:51 +0000
+Subject: mailbox: pcc: Use acpi_os_ioremap() instead of ioremap()
+
+From: Sudeep Holla <sudeep.holla@arm.com>
+
+[ Upstream commit d181acea5b864e91f38f5771b8961215ce5017ae ]
+
+The Platform Communication Channel (PCC) mailbox driver currently uses
+ioremap() to map channel shared memory regions. However it is preferred
+to use acpi_os_ioremap(), which is mapping function specific to EFI/ACPI
+defined memory regions. It ensures that the correct memory attributes
+are applied when mapping ACPI-provided regions.
+
+While at it, also add checks for handling any errors with the mapping.
+
+Acked-by: Huisong Li <lihuisong@huawei.com>
+Tested-by: Huisong Li <lihuisong@huawei.com>
+Tested-by: Adam Young <admiyo@os.amperecomputing.com>
+Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
+Signed-off-by: Jassi Brar <jassisinghbrar@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/mailbox/pcc.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c
+index f8215a8f656a4..49254d99a8ad6 100644
+--- a/drivers/mailbox/pcc.c
++++ b/drivers/mailbox/pcc.c
+@@ -419,8 +419,12 @@ int pcc_mbox_ioremap(struct mbox_chan *chan)
+ return -1;
+ pchan_info = chan->con_priv;
+ pcc_mbox_chan = &pchan_info->chan;
+- pcc_mbox_chan->shmem = ioremap(pcc_mbox_chan->shmem_base_addr,
+- pcc_mbox_chan->shmem_size);
++
++ pcc_mbox_chan->shmem = acpi_os_ioremap(pcc_mbox_chan->shmem_base_addr,
++ pcc_mbox_chan->shmem_size);
++ if (!pcc_mbox_chan->shmem)
++ return -ENXIO;
++
+ return 0;
+ }
+ EXPORT_SYMBOL_GPL(pcc_mbox_ioremap);
+--
+2.39.5
+
--- /dev/null
+From 427b10c24024b6a9d1e1e0c5e0fe0fa5e9cb8581 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 24 Feb 2025 08:27:13 +0000
+Subject: mailbox: use error ret code of of_parse_phandle_with_args()
+
+From: Tudor Ambarus <tudor.ambarus@linaro.org>
+
+[ Upstream commit 24fdd5074b205cfb0ef4cd0751a2d03031455929 ]
+
+In case of error, of_parse_phandle_with_args() returns -EINVAL when the
+passed index is negative, or -ENOENT when the index is for an empty
+phandle. The mailbox core overwrote the error return code with a less
+precise -ENODEV. Use the error returned code from
+of_parse_phandle_with_args().
+
+Signed-off-by: Tudor Ambarus <tudor.ambarus@linaro.org>
+Signed-off-by: Jassi Brar <jassisinghbrar@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/mailbox/mailbox.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c
+index d3d26a2c98956..cb174e788a96c 100644
+--- a/drivers/mailbox/mailbox.c
++++ b/drivers/mailbox/mailbox.c
+@@ -415,11 +415,12 @@ struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index)
+
+ mutex_lock(&con_mutex);
+
+- if (of_parse_phandle_with_args(dev->of_node, "mboxes",
+- "#mbox-cells", index, &spec)) {
++ ret = of_parse_phandle_with_args(dev->of_node, "mboxes", "#mbox-cells",
++ index, &spec);
++ if (ret) {
+ dev_dbg(dev, "%s: can't parse \"mboxes\" property\n", __func__);
+ mutex_unlock(&con_mutex);
+- return ERR_PTR(-ENODEV);
++ return ERR_PTR(ret);
+ }
+
+ chan = ERR_PTR(-EPROBE_DEFER);
+--
+2.39.5
+
--- /dev/null
+From 3a61d633539b05e672d327fb208d2d815ca9e2fc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 25 Mar 2025 16:10:08 +0800
+Subject: mctp: Fix incorrect tx flow invalidation condition in mctp-i2c
+
+From: Daniel Hsu <d486250@gmail.com>
+
+[ Upstream commit 70facbf978ac90c6da17a3de2a8dd111b06f1bac ]
+
+Previously, the condition for invalidating the tx flow in
+mctp_i2c_invalidate_tx_flow() checked if `rc` was nonzero.
+However, this could incorrectly trigger the invalidation
+even when `rc > 0` was returned as a success status.
+
+This patch updates the condition to explicitly check for `rc < 0`,
+ensuring that only error cases trigger the invalidation.
+
+Signed-off-by: Daniel Hsu <Daniel-Hsu@quantatw.com>
+Reviewed-by: Jeremy Kerr <jk@codeconstruct.com.au>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/mctp/mctp-i2c.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/mctp/mctp-i2c.c b/drivers/net/mctp/mctp-i2c.c
+index d74d47dd6e04d..f782d93f826ef 100644
+--- a/drivers/net/mctp/mctp-i2c.c
++++ b/drivers/net/mctp/mctp-i2c.c
+@@ -537,7 +537,7 @@ static void mctp_i2c_xmit(struct mctp_i2c_dev *midev, struct sk_buff *skb)
+ rc = __i2c_transfer(midev->adapter, &msg, 1);
+
+ /* on tx errors, the flow can no longer be considered valid */
+- if (rc)
++ if (rc < 0)
+ mctp_i2c_invalidate_tx_flow(midev, skb);
+
+ break;
+--
+2.39.5
+
--- /dev/null
+From 0fbfaa268f45a5b33d3d12dc12c1caee57ea4e33 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 22 Feb 2025 00:09:07 +0100
+Subject: media: adv7180: Disable test-pattern control on adv7180
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
+
+[ Upstream commit a980bc5f56b0292336e408f657f79e574e8067c0 ]
+
+The register that enables selecting a test-pattern to be outputted in
+free-run mode (FREE_RUN_PAT_SEL[2:0]) is only available on adv7280 based
+devices, not the adv7180 based ones.
+
+Add a flag to mark devices that are capable of generating test-patterns,
+and those that are not. And only register the control on supported
+devices.
+
+Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
+Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/i2c/adv7180.c | 34 ++++++++++++++++++++++------------
+ 1 file changed, 22 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
+index ff7dfa0278a7a..6e50b14f888f1 100644
+--- a/drivers/media/i2c/adv7180.c
++++ b/drivers/media/i2c/adv7180.c
+@@ -195,6 +195,7 @@ struct adv7180_state;
+ #define ADV7180_FLAG_V2 BIT(1)
+ #define ADV7180_FLAG_MIPI_CSI2 BIT(2)
+ #define ADV7180_FLAG_I2P BIT(3)
++#define ADV7180_FLAG_TEST_PATTERN BIT(4)
+
+ struct adv7180_chip_info {
+ unsigned int flags;
+@@ -682,11 +683,15 @@ static int adv7180_init_controls(struct adv7180_state *state)
+ ADV7180_HUE_MAX, 1, ADV7180_HUE_DEF);
+ v4l2_ctrl_new_custom(&state->ctrl_hdl, &adv7180_ctrl_fast_switch, NULL);
+
+- v4l2_ctrl_new_std_menu_items(&state->ctrl_hdl, &adv7180_ctrl_ops,
+- V4L2_CID_TEST_PATTERN,
+- ARRAY_SIZE(test_pattern_menu) - 1,
+- 0, ARRAY_SIZE(test_pattern_menu) - 1,
+- test_pattern_menu);
++ if (state->chip_info->flags & ADV7180_FLAG_TEST_PATTERN) {
++ v4l2_ctrl_new_std_menu_items(&state->ctrl_hdl,
++ &adv7180_ctrl_ops,
++ V4L2_CID_TEST_PATTERN,
++ ARRAY_SIZE(test_pattern_menu) - 1,
++ 0,
++ ARRAY_SIZE(test_pattern_menu) - 1,
++ test_pattern_menu);
++ }
+
+ state->sd.ctrl_handler = &state->ctrl_hdl;
+ if (state->ctrl_hdl.error) {
+@@ -1221,7 +1226,7 @@ static const struct adv7180_chip_info adv7182_info = {
+ };
+
+ static const struct adv7180_chip_info adv7280_info = {
+- .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P,
++ .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P | ADV7180_FLAG_TEST_PATTERN,
+ .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
+ BIT(ADV7182_INPUT_CVBS_AIN2) |
+ BIT(ADV7182_INPUT_CVBS_AIN3) |
+@@ -1235,7 +1240,8 @@ static const struct adv7180_chip_info adv7280_info = {
+ };
+
+ static const struct adv7180_chip_info adv7280_m_info = {
+- .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P,
++ .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P |
++ ADV7180_FLAG_TEST_PATTERN,
+ .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
+ BIT(ADV7182_INPUT_CVBS_AIN2) |
+ BIT(ADV7182_INPUT_CVBS_AIN3) |
+@@ -1256,7 +1262,8 @@ static const struct adv7180_chip_info adv7280_m_info = {
+ };
+
+ static const struct adv7180_chip_info adv7281_info = {
+- .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2,
++ .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 |
++ ADV7180_FLAG_TEST_PATTERN,
+ .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
+ BIT(ADV7182_INPUT_CVBS_AIN2) |
+ BIT(ADV7182_INPUT_CVBS_AIN7) |
+@@ -1271,7 +1278,8 @@ static const struct adv7180_chip_info adv7281_info = {
+ };
+
+ static const struct adv7180_chip_info adv7281_m_info = {
+- .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2,
++ .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 |
++ ADV7180_FLAG_TEST_PATTERN,
+ .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
+ BIT(ADV7182_INPUT_CVBS_AIN2) |
+ BIT(ADV7182_INPUT_CVBS_AIN3) |
+@@ -1291,7 +1299,8 @@ static const struct adv7180_chip_info adv7281_m_info = {
+ };
+
+ static const struct adv7180_chip_info adv7281_ma_info = {
+- .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2,
++ .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 |
++ ADV7180_FLAG_TEST_PATTERN,
+ .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
+ BIT(ADV7182_INPUT_CVBS_AIN2) |
+ BIT(ADV7182_INPUT_CVBS_AIN3) |
+@@ -1316,7 +1325,7 @@ static const struct adv7180_chip_info adv7281_ma_info = {
+ };
+
+ static const struct adv7180_chip_info adv7282_info = {
+- .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P,
++ .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P | ADV7180_FLAG_TEST_PATTERN,
+ .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
+ BIT(ADV7182_INPUT_CVBS_AIN2) |
+ BIT(ADV7182_INPUT_CVBS_AIN7) |
+@@ -1331,7 +1340,8 @@ static const struct adv7180_chip_info adv7282_info = {
+ };
+
+ static const struct adv7180_chip_info adv7282_m_info = {
+- .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P,
++ .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P |
++ ADV7180_FLAG_TEST_PATTERN,
+ .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
+ BIT(ADV7182_INPUT_CVBS_AIN2) |
+ BIT(ADV7182_INPUT_CVBS_AIN3) |
+--
+2.39.5
+
--- /dev/null
+From 3db14100f8e867508ec59f8290d1b9bd872c9024 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 4 Oct 2024 15:50:15 +0200
+Subject: media: c8sectpfe: Call of_node_put(i2c_bus) only once in
+ c8sectpfe_probe()
+
+From: Markus Elfring <elfring@users.sourceforge.net>
+
+[ Upstream commit b773530a34df0687020520015057075f8b7b4ac4 ]
+
+An of_node_put(i2c_bus) call was immediately used after a pointer check
+for an of_find_i2c_adapter_by_node() call in this function implementation.
+Thus call such a function only once instead directly before the check.
+
+This issue was transformed by using the Coccinelle software.
+
+Signed-off-by: Markus Elfring <elfring@users.sourceforge.net>
+Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c
+index 7b3a37957e3ae..d151d2ed1f64b 100644
+--- a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c
++++ b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c
+@@ -797,13 +797,12 @@ static int c8sectpfe_probe(struct platform_device *pdev)
+ }
+ tsin->i2c_adapter =
+ of_find_i2c_adapter_by_node(i2c_bus);
++ of_node_put(i2c_bus);
+ if (!tsin->i2c_adapter) {
+ dev_err(&pdev->dev, "No i2c adapter found\n");
+- of_node_put(i2c_bus);
+ ret = -ENODEV;
+ goto err_node_put;
+ }
+- of_node_put(i2c_bus);
+
+ /* Acquire reset GPIO and activate it */
+ tsin->rst_gpio = devm_fwnode_gpiod_get(dev,
+--
+2.39.5
+
--- /dev/null
+From f7cea4792cb0ba04f12d546629c5dbe54c906d49 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Mar 2025 20:11:25 +0500
+Subject: media: cec: use us_to_ktime() where appropriate
+
+From: Vitaliy Shevtsov <v.shevtsov@mt-integration.ru>
+
+[ Upstream commit c0c1a6bf80e9075e3f6b81fd542550d8eb91e57a ]
+
+[Why]
+There are several ns_to_ktime() calls that require using nanoseconds. It is
+better to replace them with us_to_ktime() to make code clear, getting rid
+of multiplication by 1000.
+
+Also the timer function code may have an integer wrap-around issue. Since
+both tx_custom_low_usecs and tx_custom_high_usecs can be set to up to
+9999999 from the user space via cec_pin_error_inj_parse_line(), this may
+cause usecs to be overflowed when adap->monitor_pin_cnt is zero and usecs
+is multiplied by 1000.
+
+[How]
+Take advantage of using an appropriate helper func us_to_ktime() instead of
+ns_to_ktime() to improve readability and to make the code clearer. And this
+also mitigates possible integer wrap-arounds when usecs value is too large
+and it is multiplied by 1000.
+
+Found by Linux Verification Center (linuxtesting.org) with Svace.
+
+Signed-off-by: Vitaliy Shevtsov <v.shevtsov@mt-integration.ru>
+Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/cec/core/cec-pin.c | 11 +++++------
+ 1 file changed, 5 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/media/cec/core/cec-pin.c b/drivers/media/cec/core/cec-pin.c
+index a70451d99ebc9..f232c3df7ee16 100644
+--- a/drivers/media/cec/core/cec-pin.c
++++ b/drivers/media/cec/core/cec-pin.c
+@@ -873,19 +873,19 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer)
+ if (pin->wait_usecs > 150) {
+ pin->wait_usecs -= 100;
+ pin->timer_ts = ktime_add_us(ts, 100);
+- hrtimer_forward_now(timer, ns_to_ktime(100000));
++ hrtimer_forward_now(timer, us_to_ktime(100));
+ return HRTIMER_RESTART;
+ }
+ if (pin->wait_usecs > 100) {
+ pin->wait_usecs /= 2;
+ pin->timer_ts = ktime_add_us(ts, pin->wait_usecs);
+ hrtimer_forward_now(timer,
+- ns_to_ktime(pin->wait_usecs * 1000));
++ us_to_ktime(pin->wait_usecs));
+ return HRTIMER_RESTART;
+ }
+ pin->timer_ts = ktime_add_us(ts, pin->wait_usecs);
+ hrtimer_forward_now(timer,
+- ns_to_ktime(pin->wait_usecs * 1000));
++ us_to_ktime(pin->wait_usecs));
+ pin->wait_usecs = 0;
+ return HRTIMER_RESTART;
+ }
+@@ -1020,13 +1020,12 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer)
+ if (!adap->monitor_pin_cnt || usecs <= 150) {
+ pin->wait_usecs = 0;
+ pin->timer_ts = ktime_add_us(ts, usecs);
+- hrtimer_forward_now(timer,
+- ns_to_ktime(usecs * 1000));
++ hrtimer_forward_now(timer, us_to_ktime(usecs));
+ return HRTIMER_RESTART;
+ }
+ pin->wait_usecs = usecs - 100;
+ pin->timer_ts = ktime_add_us(ts, 100);
+- hrtimer_forward_now(timer, ns_to_ktime(100000));
++ hrtimer_forward_now(timer, us_to_ktime(100));
+ return HRTIMER_RESTART;
+ }
+
+--
+2.39.5
+
--- /dev/null
+From dbbe4ee6a2a37eb0da5500ca4556058bf97fcf40 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 24 Feb 2025 14:13:24 +0100
+Subject: media: cx231xx: set device_caps for 417
+
+From: Hans Verkuil <hverkuil@xs4all.nl>
+
+[ Upstream commit a79efc44b51432490538a55b9753a721f7d3ea42 ]
+
+The video_device for the MPEG encoder did not set device_caps.
+
+Add this, otherwise the video device can't be registered (you get a
+WARN_ON instead).
+
+Not seen before since currently 417 support is disabled, but I found
+this while experimenting with it.
+
+Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
+Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/usb/cx231xx/cx231xx-417.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c
+index a4a9781328c50..06d61e52f018c 100644
+--- a/drivers/media/usb/cx231xx/cx231xx-417.c
++++ b/drivers/media/usb/cx231xx/cx231xx-417.c
+@@ -1720,6 +1720,8 @@ static void cx231xx_video_dev_init(
+ vfd->lock = &dev->lock;
+ vfd->release = video_device_release_empty;
+ vfd->ctrl_handler = &dev->mpeg_ctrl_handler.hdl;
++ vfd->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
++ V4L2_CAP_VIDEO_CAPTURE;
+ video_set_drvdata(vfd, dev);
+ if (dev->tuner_type == TUNER_ABSENT) {
+ v4l2_disable_ioctl(vfd, VIDIOC_G_FREQUENCY);
+--
+2.39.5
+
--- /dev/null
+From 955cc49005f44abb8f2ec0154802075071bcfe07 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Feb 2025 12:34:36 +0530
+Subject: media: i2c: imx219: Correct the minimum vblanking value
+
+From: David Plowman <david.plowman@raspberrypi.com>
+
+[ Upstream commit e3b82d49bf676f3c873e642038765eac32ab6d39 ]
+
+The datasheet for this sensor documents the minimum vblanking as being
+32 lines. It does fix some problems with occasional black lines at the
+bottom of images (tested on Raspberry Pi).
+
+Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
+Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Signed-off-by: Jai Luthra <jai.luthra@ideasonboard.com>
+Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/i2c/imx219.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c
+index 64227eb423d43..dd5a8577d7479 100644
+--- a/drivers/media/i2c/imx219.c
++++ b/drivers/media/i2c/imx219.c
+@@ -73,7 +73,7 @@
+ #define IMX219_REG_VTS CCI_REG16(0x0160)
+ #define IMX219_VTS_MAX 0xffff
+
+-#define IMX219_VBLANK_MIN 4
++#define IMX219_VBLANK_MIN 32
+
+ /* HBLANK control - read only */
+ #define IMX219_PPL_DEFAULT 3448
+--
+2.39.5
+
--- /dev/null
+From 588e70f42c037871ce2c659ab03946bffb17c98b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 10 Jan 2025 09:33:33 +0200
+Subject: media: i2c: ov2740: Free control handler on error path
+
+From: Sakari Ailus <sakari.ailus@linux.intel.com>
+
+[ Upstream commit 71dfb2c7548994aad6cb0a316c2601e7144d15a5 ]
+
+The control handler wasn't freed if v4l2_fwnode_device_parse() failed. Do
+that now.
+
+Co-developed-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/i2c/ov2740.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c
+index 9a5d118b87b01..04e93618f408a 100644
+--- a/drivers/media/i2c/ov2740.c
++++ b/drivers/media/i2c/ov2740.c
+@@ -828,8 +828,10 @@ static int ov2740_init_controls(struct ov2740 *ov2740)
+ 0, 0, ov2740_test_pattern_menu);
+
+ ret = v4l2_fwnode_device_parse(&client->dev, &props);
+- if (ret)
++ if (ret) {
++ v4l2_ctrl_handler_free(ctrl_hdlr);
+ return ret;
++ }
+
+ v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &ov2740_ctrl_ops, &props);
+
+--
+2.39.5
+
--- /dev/null
+From 27429774510d80581d42ec24a31cbbdd1bc28ee3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 28 Feb 2025 18:17:31 +0900
+Subject: media: imx335: Set vblank immediately
+
+From: Paul Elder <paul.elder@ideasonboard.com>
+
+[ Upstream commit c0aa40f45fef80b4182704d1bc089cbf8ae8bed0 ]
+
+When the vblank v4l2 control is set, it does not get written to the
+hardware unless exposure is also changed. Change the behavior such that
+the vblank is written immediately when the control is set, as setting
+the vblank without changing the exposure is a valid use case (such as
+for changing the frame rate).
+
+Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
+Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
+Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/i2c/imx335.c | 21 +++++++++++++++------
+ 1 file changed, 15 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/media/i2c/imx335.c b/drivers/media/i2c/imx335.c
+index fcfd1d851bd4a..0beb80b8c4581 100644
+--- a/drivers/media/i2c/imx335.c
++++ b/drivers/media/i2c/imx335.c
+@@ -559,12 +559,14 @@ static int imx335_set_ctrl(struct v4l2_ctrl *ctrl)
+ imx335->vblank,
+ imx335->vblank + imx335->cur_mode->height);
+
+- return __v4l2_ctrl_modify_range(imx335->exp_ctrl,
+- IMX335_EXPOSURE_MIN,
+- imx335->vblank +
+- imx335->cur_mode->height -
+- IMX335_EXPOSURE_OFFSET,
+- 1, IMX335_EXPOSURE_DEFAULT);
++ ret = __v4l2_ctrl_modify_range(imx335->exp_ctrl,
++ IMX335_EXPOSURE_MIN,
++ imx335->vblank +
++ imx335->cur_mode->height -
++ IMX335_EXPOSURE_OFFSET,
++ 1, IMX335_EXPOSURE_DEFAULT);
++ if (ret)
++ return ret;
+ }
+
+ /*
+@@ -575,6 +577,13 @@ static int imx335_set_ctrl(struct v4l2_ctrl *ctrl)
+ return 0;
+
+ switch (ctrl->id) {
++ case V4L2_CID_VBLANK:
++ exposure = imx335->exp_ctrl->val;
++ analog_gain = imx335->again_ctrl->val;
++
++ ret = imx335_update_exp_gain(imx335, exposure, analog_gain);
++
++ break;
+ case V4L2_CID_EXPOSURE:
+ exposure = ctrl->val;
+ analog_gain = imx335->again_ctrl->val;
+--
+2.39.5
+
--- /dev/null
+From f19f43ace03ad7aba554952cb531568ed833448d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Jan 2025 10:01:27 +0530
+Subject: media: qcom: camss: Add default case in vfe_src_pad_code
+
+From: Depeng Shao <quic_depengs@quicinc.com>
+
+[ Upstream commit 2f4204bb00b32eca3391a468d3b37e87feb96fa9 ]
+
+Add a default case in vfe_src_pad_code to get rid of a compile
+warning if a new hw enum is added.
+
+Signed-off-by: Depeng Shao <quic_depengs@quicinc.com>
+Reviewed-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
+Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/platform/qcom/camss/camss-vfe.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
+index 95f6a1ac7eaf5..3c5811c6c028e 100644
+--- a/drivers/media/platform/qcom/camss/camss-vfe.c
++++ b/drivers/media/platform/qcom/camss/camss-vfe.c
+@@ -400,6 +400,10 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,
+ return sink_code;
+ }
+ break;
++ default:
++ WARN(1, "Unsupported HW version: %x\n",
++ vfe->camss->res->version);
++ break;
+ }
+ return 0;
+ }
+--
+2.39.5
+
--- /dev/null
+From 9b0d9278bd9788fd1a1907fa96447a1be52b92ac Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Jan 2025 10:01:28 +0530
+Subject: media: qcom: camss: csid: Only add TPG v4l2 ctrl if TPG hardware is
+ available
+
+From: Depeng Shao <quic_depengs@quicinc.com>
+
+[ Upstream commit 2f1361f862a68063f37362f1beb400e78e289581 ]
+
+There is no CSID TPG on some SoCs, so the v4l2 ctrl in CSID driver
+shouldn't be registered. Checking the supported TPG modes to indicate
+if the TPG hardware exists or not and only registering v4l2 ctrl for
+CSID only when the TPG hardware is present.
+
+Signed-off-by: Depeng Shao <quic_depengs@quicinc.com>
+Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../media/platform/qcom/camss/camss-csid.c | 60 +++++++++++--------
+ 1 file changed, 35 insertions(+), 25 deletions(-)
+
+diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c
+index 858db5d4ca75c..e51f2ed3f0315 100644
+--- a/drivers/media/platform/qcom/camss/camss-csid.c
++++ b/drivers/media/platform/qcom/camss/camss-csid.c
+@@ -683,11 +683,13 @@ static int csid_set_stream(struct v4l2_subdev *sd, int enable)
+ int ret;
+
+ if (enable) {
+- ret = v4l2_ctrl_handler_setup(&csid->ctrls);
+- if (ret < 0) {
+- dev_err(csid->camss->dev,
+- "could not sync v4l2 controls: %d\n", ret);
+- return ret;
++ if (csid->testgen.nmodes != CSID_PAYLOAD_MODE_DISABLED) {
++ ret = v4l2_ctrl_handler_setup(&csid->ctrls);
++ if (ret < 0) {
++ dev_err(csid->camss->dev,
++ "could not sync v4l2 controls: %d\n", ret);
++ return ret;
++ }
+ }
+
+ if (!csid->testgen.enabled &&
+@@ -761,7 +763,8 @@ static void csid_try_format(struct csid_device *csid,
+ break;
+
+ case MSM_CSID_PAD_SRC:
+- if (csid->testgen_mode->cur.val == 0) {
++ if (csid->testgen.nmodes == CSID_PAYLOAD_MODE_DISABLED ||
++ csid->testgen_mode->cur.val == 0) {
+ /* Test generator is disabled, */
+ /* keep pad formats in sync */
+ u32 code = fmt->code;
+@@ -811,7 +814,8 @@ static int csid_enum_mbus_code(struct v4l2_subdev *sd,
+
+ code->code = csid->res->formats->formats[code->index].code;
+ } else {
+- if (csid->testgen_mode->cur.val == 0) {
++ if (csid->testgen.nmodes == CSID_PAYLOAD_MODE_DISABLED ||
++ csid->testgen_mode->cur.val == 0) {
+ struct v4l2_mbus_framefmt *sink_fmt;
+
+ sink_fmt = __csid_get_format(csid, sd_state,
+@@ -1190,7 +1194,8 @@ static int csid_link_setup(struct media_entity *entity,
+
+ /* If test generator is enabled */
+ /* do not allow a link from CSIPHY to CSID */
+- if (csid->testgen_mode->cur.val != 0)
++ if (csid->testgen.nmodes != CSID_PAYLOAD_MODE_DISABLED &&
++ csid->testgen_mode->cur.val != 0)
+ return -EBUSY;
+
+ sd = media_entity_to_v4l2_subdev(remote->entity);
+@@ -1283,24 +1288,27 @@ int msm_csid_register_entity(struct csid_device *csid,
+ MSM_CSID_NAME, csid->id);
+ v4l2_set_subdevdata(sd, csid);
+
+- ret = v4l2_ctrl_handler_init(&csid->ctrls, 1);
+- if (ret < 0) {
+- dev_err(dev, "Failed to init ctrl handler: %d\n", ret);
+- return ret;
+- }
++ if (csid->testgen.nmodes != CSID_PAYLOAD_MODE_DISABLED) {
++ ret = v4l2_ctrl_handler_init(&csid->ctrls, 1);
++ if (ret < 0) {
++ dev_err(dev, "Failed to init ctrl handler: %d\n", ret);
++ return ret;
++ }
+
+- csid->testgen_mode = v4l2_ctrl_new_std_menu_items(&csid->ctrls,
+- &csid_ctrl_ops, V4L2_CID_TEST_PATTERN,
+- csid->testgen.nmodes, 0, 0,
+- csid->testgen.modes);
++ csid->testgen_mode =
++ v4l2_ctrl_new_std_menu_items(&csid->ctrls,
++ &csid_ctrl_ops, V4L2_CID_TEST_PATTERN,
++ csid->testgen.nmodes, 0, 0,
++ csid->testgen.modes);
+
+- if (csid->ctrls.error) {
+- dev_err(dev, "Failed to init ctrl: %d\n", csid->ctrls.error);
+- ret = csid->ctrls.error;
+- goto free_ctrl;
+- }
++ if (csid->ctrls.error) {
++ dev_err(dev, "Failed to init ctrl: %d\n", csid->ctrls.error);
++ ret = csid->ctrls.error;
++ goto free_ctrl;
++ }
+
+- csid->subdev.ctrl_handler = &csid->ctrls;
++ csid->subdev.ctrl_handler = &csid->ctrls;
++ }
+
+ ret = csid_init_formats(sd, NULL);
+ if (ret < 0) {
+@@ -1331,7 +1339,8 @@ int msm_csid_register_entity(struct csid_device *csid,
+ media_cleanup:
+ media_entity_cleanup(&sd->entity);
+ free_ctrl:
+- v4l2_ctrl_handler_free(&csid->ctrls);
++ if (csid->testgen.nmodes != CSID_PAYLOAD_MODE_DISABLED)
++ v4l2_ctrl_handler_free(&csid->ctrls);
+
+ return ret;
+ }
+@@ -1344,7 +1353,8 @@ void msm_csid_unregister_entity(struct csid_device *csid)
+ {
+ v4l2_device_unregister_subdev(&csid->subdev);
+ media_entity_cleanup(&csid->subdev.entity);
+- v4l2_ctrl_handler_free(&csid->ctrls);
++ if (csid->testgen.nmodes != CSID_PAYLOAD_MODE_DISABLED)
++ v4l2_ctrl_handler_free(&csid->ctrls);
+ }
+
+ inline bool csid_is_lite(struct csid_device *csid)
+--
+2.39.5
+
--- /dev/null
+From 929ac089d93fca68ade7bbe89989e57b08d6c133 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Jan 2025 09:57:53 +0100
+Subject: media: stm32: csi: add missing pm_runtime_put on error
+
+From: Alain Volmat <alain.volmat@foss.st.com>
+
+[ Upstream commit f7cd9c94959e7a5b8c4eca33e20bd6ba1b048a64 ]
+
+Within the stm32_csi_start function, pm_runtime_put should
+be called upon error following pm_runtime_get_sync.
+Rework the function error handling by putting a label in
+order to have common error handling for all calls requiring
+pm_runtime_put.
+
+Signed-off-by: Alain Volmat <alain.volmat@foss.st.com>
+Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/platform/st/stm32/stm32-csi.c | 16 +++++++++-------
+ 1 file changed, 9 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/media/platform/st/stm32/stm32-csi.c b/drivers/media/platform/st/stm32/stm32-csi.c
+index a4f8db608cedd..0c776e4a7ce83 100644
+--- a/drivers/media/platform/st/stm32/stm32-csi.c
++++ b/drivers/media/platform/st/stm32/stm32-csi.c
+@@ -499,21 +499,19 @@ static int stm32_csi_start(struct stm32_csi_dev *csidev,
+
+ ret = pm_runtime_get_sync(csidev->dev);
+ if (ret < 0)
+- return ret;
++ goto error_put;
+
+ /* Retrieve CSI2PHY clock rate to compute CCFR value */
+ phy_clk_frate = clk_get_rate(csidev->clks[STM32_CSI_CLK_CSI2PHY].clk);
+ if (!phy_clk_frate) {
+- pm_runtime_put(csidev->dev);
+ dev_err(csidev->dev, "CSI2PHY clock rate invalid (0)\n");
+- return ret;
++ ret = -EINVAL;
++ goto error_put;
+ }
+
+ ret = stm32_csi_setup_lane_merger(csidev);
+- if (ret) {
+- pm_runtime_put(csidev->dev);
+- return ret;
+- }
++ if (ret)
++ goto error_put;
+
+ /* Enable the CSI */
+ writel_relaxed(STM32_CSI_CR_CSIEN, csidev->base + STM32_CSI_CR);
+@@ -569,6 +567,10 @@ static int stm32_csi_start(struct stm32_csi_dev *csidev,
+ writel_relaxed(0, csidev->base + STM32_CSI_PMCR);
+
+ return ret;
++
++error_put:
++ pm_runtime_put(csidev->dev);
++ return ret;
+ }
+
+ static void stm32_csi_stop(struct stm32_csi_dev *csidev)
+--
+2.39.5
+
--- /dev/null
+From 730521f922b1bad822c42750d47065062f398274 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Jan 2025 09:57:55 +0100
+Subject: media: stm32: csi: use ARRAY_SIZE to search D-PHY table
+
+From: Alain Volmat <alain.volmat@foss.st.com>
+
+[ Upstream commit a3a91b6e62be24c5df47a800c367504cb41e502b ]
+
+Within stm32_csi_start, use ARRAY_SIZE loop in order to search
+for the right setting.
+Avoid useless init of lanes_ie / lanes_en.
+
+Signed-off-by: Alain Volmat <alain.volmat@foss.st.com>
+Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/platform/st/stm32/stm32-csi.c | 20 +++++++++++---------
+ 1 file changed, 11 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/media/platform/st/stm32/stm32-csi.c b/drivers/media/platform/st/stm32/stm32-csi.c
+index 48941aae8c9b8..a4f8db608cedd 100644
+--- a/drivers/media/platform/st/stm32/stm32-csi.c
++++ b/drivers/media/platform/st/stm32/stm32-csi.c
+@@ -325,7 +325,6 @@ static const struct stm32_csi_mbps_phy_reg snps_stm32mp25[] = {
+ { .mbps = 2400, .hsfreqrange = 0x47, .osc_freq_target = 442 },
+ { .mbps = 2450, .hsfreqrange = 0x48, .osc_freq_target = 451 },
+ { .mbps = 2500, .hsfreqrange = 0x49, .osc_freq_target = 460 },
+- { /* sentinel */ }
+ };
+
+ static const struct v4l2_mbus_framefmt fmt_default = {
+@@ -444,13 +443,13 @@ static void stm32_csi_phy_reg_write(struct stm32_csi_dev *csidev,
+ static int stm32_csi_start(struct stm32_csi_dev *csidev,
+ struct v4l2_subdev_state *state)
+ {
+- const struct stm32_csi_mbps_phy_reg *phy_regs;
++ const struct stm32_csi_mbps_phy_reg *phy_regs = NULL;
+ struct v4l2_mbus_framefmt *sink_fmt;
+ const struct stm32_csi_fmts *fmt;
+ unsigned long phy_clk_frate;
++ u32 lanes_ie, lanes_en;
+ unsigned int mbps;
+- u32 lanes_ie = 0;
+- u32 lanes_en = 0;
++ unsigned int i;
+ s64 link_freq;
+ int ret;
+ u32 ccfr;
+@@ -474,11 +473,14 @@ static int stm32_csi_start(struct stm32_csi_dev *csidev,
+ mbps = div_s64(link_freq, 500000);
+ dev_dbg(csidev->dev, "Computed Mbps: %u\n", mbps);
+
+- for (phy_regs = snps_stm32mp25; phy_regs->mbps != 0; phy_regs++)
+- if (phy_regs->mbps >= mbps)
++ for (i = 0; i < ARRAY_SIZE(snps_stm32mp25); i++) {
++ if (snps_stm32mp25[i].mbps >= mbps) {
++ phy_regs = &snps_stm32mp25[i];
+ break;
++ }
++ }
+
+- if (!phy_regs->mbps) {
++ if (!phy_regs) {
+ dev_err(csidev->dev, "Unsupported PHY speed (%u Mbps)", mbps);
+ return -ERANGE;
+ }
+@@ -488,8 +490,8 @@ static int stm32_csi_start(struct stm32_csi_dev *csidev,
+ phy_regs->osc_freq_target);
+
+ /* Prepare lanes related configuration bits */
+- lanes_ie |= STM32_CSI_SR1_DL0_ERRORS;
+- lanes_en |= STM32_CSI_PCR_DL0EN;
++ lanes_ie = STM32_CSI_SR1_DL0_ERRORS;
++ lanes_en = STM32_CSI_PCR_DL0EN;
+ if (csidev->num_lanes == 2) {
+ lanes_ie |= STM32_CSI_SR1_DL1_ERRORS;
+ lanes_en |= STM32_CSI_PCR_DL1EN;
+--
+2.39.5
+
--- /dev/null
+From 1ed20d45c9467a92c3d2586ecd8f3afe5dcd2014 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 7 Jan 2025 17:07:01 +0100
+Subject: media: tc358746: improve calculation of the D-PHY timing registers
+
+From: Matthias Fend <matthias.fend@emfend.at>
+
+[ Upstream commit 78d7265e2e1ce349e7f3c6a085f2b66d7b73f4ca ]
+
+When calculating D-PHY registers, using data rates that are not multiples
+of 16 can lead to precision loss in division operations. This can result in
+register values that produce timing violations against the MIPI standard.
+
+An example:
+cfg->hs_clk_rate = 294MHz
+hf_clk = 18
+
+If the desired value in cfg->init is 100us, which is the minimum allowed
+value, then the LINEINITCNT register is calculated as 1799. But since the
+actual clock is 18.375MHz instead of 18MHz, this setting results in a time
+that is shorter than 100us and thus violates the standard. The correct
+value for LINEINITCNT would be 1837.
+
+Improve the precision of calculations by using Hz instead of MHz as unit.
+
+Signed-off-by: Matthias Fend <matthias.fend@emfend.at>
+Reviewed-by: Marco Felsch <m.felsch@pengutronix.de>
+Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/i2c/tc358746.c | 19 +++++++------------
+ 1 file changed, 7 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/media/i2c/tc358746.c b/drivers/media/i2c/tc358746.c
+index 389582420ba78..048a1a381b333 100644
+--- a/drivers/media/i2c/tc358746.c
++++ b/drivers/media/i2c/tc358746.c
+@@ -460,24 +460,20 @@ static int tc358746_apply_misc_config(struct tc358746 *tc358746)
+ return err;
+ }
+
+-/* Use MHz as base so the div needs no u64 */
+-static u32 tc358746_cfg_to_cnt(unsigned int cfg_val,
+- unsigned int clk_mhz,
+- unsigned int time_base)
++static u32 tc358746_cfg_to_cnt(unsigned long cfg_val, unsigned long clk_hz,
++ unsigned long long time_base)
+ {
+- return DIV_ROUND_UP(cfg_val * clk_mhz, time_base);
++ return div64_u64((u64)cfg_val * clk_hz + time_base - 1, time_base);
+ }
+
+-static u32 tc358746_ps_to_cnt(unsigned int cfg_val,
+- unsigned int clk_mhz)
++static u32 tc358746_ps_to_cnt(unsigned long cfg_val, unsigned long clk_hz)
+ {
+- return tc358746_cfg_to_cnt(cfg_val, clk_mhz, USEC_PER_SEC);
++ return tc358746_cfg_to_cnt(cfg_val, clk_hz, PSEC_PER_SEC);
+ }
+
+-static u32 tc358746_us_to_cnt(unsigned int cfg_val,
+- unsigned int clk_mhz)
++static u32 tc358746_us_to_cnt(unsigned long cfg_val, unsigned long clk_hz)
+ {
+- return tc358746_cfg_to_cnt(cfg_val, clk_mhz, 1);
++ return tc358746_cfg_to_cnt(cfg_val, clk_hz, USEC_PER_SEC);
+ }
+
+ static int tc358746_apply_dphy_config(struct tc358746 *tc358746)
+@@ -492,7 +488,6 @@ static int tc358746_apply_dphy_config(struct tc358746 *tc358746)
+
+ /* The hs_byte_clk is also called SYSCLK in the excel sheet */
+ hs_byte_clk = cfg->hs_clk_rate / 8;
+- hs_byte_clk /= HZ_PER_MHZ;
+ hf_clk = hs_byte_clk / 2;
+
+ val = tc358746_us_to_cnt(cfg->init, hf_clk) - 1;
+--
+2.39.5
+
--- /dev/null
+From 63809221d437e74748ee61f6e5d01c257b3ba24b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 9 Dec 2024 16:00:16 +0100
+Subject: media: test-drivers: vivid: don't call schedule in loop
+
+From: Hans Verkuil <hverkuil@xs4all.nl>
+
+[ Upstream commit e4740118b752005cbed339aec9a1d1c43620e0b9 ]
+
+Artem reported that the CPU load was 100% when capturing from
+vivid at low resolution with ffmpeg.
+
+This was caused by:
+
+while (time_is_after_jiffies(cur_jiffies + wait_jiffies) &&
+ !kthread_should_stop())
+ schedule();
+
+If there are no other processes running that can be scheduled,
+then this is basically a busy-loop.
+
+Change it to wait_event_interruptible_timeout() which doesn't
+have that problem.
+
+Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
+Reported-by: Artem S. Tashkinov <aros@gmx.com>
+Closes: https://bugzilla.kernel.org/show_bug.cgi?id=219570
+Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/test-drivers/vivid/vivid-kthread-cap.c | 11 ++++++++---
+ drivers/media/test-drivers/vivid/vivid-kthread-out.c | 11 ++++++++---
+ .../media/test-drivers/vivid/vivid-kthread-touch.c | 11 ++++++++---
+ drivers/media/test-drivers/vivid/vivid-sdr-cap.c | 11 ++++++++---
+ 4 files changed, 32 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/media/test-drivers/vivid/vivid-kthread-cap.c b/drivers/media/test-drivers/vivid/vivid-kthread-cap.c
+index 669bd96da4c79..273e8ed8c2a90 100644
+--- a/drivers/media/test-drivers/vivid/vivid-kthread-cap.c
++++ b/drivers/media/test-drivers/vivid/vivid-kthread-cap.c
+@@ -789,9 +789,14 @@ static int vivid_thread_vid_cap(void *data)
+ next_jiffies_since_start = jiffies_since_start;
+
+ wait_jiffies = next_jiffies_since_start - jiffies_since_start;
+- while (time_is_after_jiffies(cur_jiffies + wait_jiffies) &&
+- !kthread_should_stop())
+- schedule();
++ if (!time_is_after_jiffies(cur_jiffies + wait_jiffies))
++ continue;
++
++ wait_queue_head_t wait;
++
++ init_waitqueue_head(&wait);
++ wait_event_interruptible_timeout(wait, kthread_should_stop(),
++ cur_jiffies + wait_jiffies - jiffies);
+ }
+ dprintk(dev, 1, "Video Capture Thread End\n");
+ return 0;
+diff --git a/drivers/media/test-drivers/vivid/vivid-kthread-out.c b/drivers/media/test-drivers/vivid/vivid-kthread-out.c
+index fac6208b51da8..015a7b166a1e6 100644
+--- a/drivers/media/test-drivers/vivid/vivid-kthread-out.c
++++ b/drivers/media/test-drivers/vivid/vivid-kthread-out.c
+@@ -235,9 +235,14 @@ static int vivid_thread_vid_out(void *data)
+ next_jiffies_since_start = jiffies_since_start;
+
+ wait_jiffies = next_jiffies_since_start - jiffies_since_start;
+- while (time_is_after_jiffies(cur_jiffies + wait_jiffies) &&
+- !kthread_should_stop())
+- schedule();
++ if (!time_is_after_jiffies(cur_jiffies + wait_jiffies))
++ continue;
++
++ wait_queue_head_t wait;
++
++ init_waitqueue_head(&wait);
++ wait_event_interruptible_timeout(wait, kthread_should_stop(),
++ cur_jiffies + wait_jiffies - jiffies);
+ }
+ dprintk(dev, 1, "Video Output Thread End\n");
+ return 0;
+diff --git a/drivers/media/test-drivers/vivid/vivid-kthread-touch.c b/drivers/media/test-drivers/vivid/vivid-kthread-touch.c
+index fa711ee36a3fb..c862689786b69 100644
+--- a/drivers/media/test-drivers/vivid/vivid-kthread-touch.c
++++ b/drivers/media/test-drivers/vivid/vivid-kthread-touch.c
+@@ -135,9 +135,14 @@ static int vivid_thread_touch_cap(void *data)
+ next_jiffies_since_start = jiffies_since_start;
+
+ wait_jiffies = next_jiffies_since_start - jiffies_since_start;
+- while (time_is_after_jiffies(cur_jiffies + wait_jiffies) &&
+- !kthread_should_stop())
+- schedule();
++ if (!time_is_after_jiffies(cur_jiffies + wait_jiffies))
++ continue;
++
++ wait_queue_head_t wait;
++
++ init_waitqueue_head(&wait);
++ wait_event_interruptible_timeout(wait, kthread_should_stop(),
++ cur_jiffies + wait_jiffies - jiffies);
+ }
+ dprintk(dev, 1, "Touch Capture Thread End\n");
+ return 0;
+diff --git a/drivers/media/test-drivers/vivid/vivid-sdr-cap.c b/drivers/media/test-drivers/vivid/vivid-sdr-cap.c
+index 74a91d28c8be9..c633fc2ed664f 100644
+--- a/drivers/media/test-drivers/vivid/vivid-sdr-cap.c
++++ b/drivers/media/test-drivers/vivid/vivid-sdr-cap.c
+@@ -206,9 +206,14 @@ static int vivid_thread_sdr_cap(void *data)
+ next_jiffies_since_start = jiffies_since_start;
+
+ wait_jiffies = next_jiffies_since_start - jiffies_since_start;
+- while (time_is_after_jiffies(cur_jiffies + wait_jiffies) &&
+- !kthread_should_stop())
+- schedule();
++ if (!time_is_after_jiffies(cur_jiffies + wait_jiffies))
++ continue;
++
++ wait_queue_head_t wait;
++
++ init_waitqueue_head(&wait);
++ wait_event_interruptible_timeout(wait, kthread_should_stop(),
++ cur_jiffies + wait_jiffies - jiffies);
+ }
+ dprintk(dev, 1, "SDR Capture Thread End\n");
+ return 0;
+--
+2.39.5
+
--- /dev/null
+From 3ea6d8dfec4f3c5548a24e5dc4daeed3ea8177c5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Feb 2025 11:55:51 +0000
+Subject: media: uvcvideo: Add sanity check to uvc_ioctl_xu_ctrl_map
+
+From: Ricardo Ribalda <ribalda@chromium.org>
+
+[ Upstream commit 990262fdfce24d6055df9711424343d94d829e6a ]
+
+Do not process unknown data types.
+
+Tested-by: Yunke Cao <yunkec@google.com>
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
+Link: https://lore.kernel.org/r/20250203-uvc-roi-v17-15-5900a9fed613@chromium.org
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/usb/uvc/uvc_v4l2.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
+index 93c6cdb238812..75216507cbdcf 100644
+--- a/drivers/media/usb/uvc/uvc_v4l2.c
++++ b/drivers/media/usb/uvc/uvc_v4l2.c
+@@ -108,6 +108,12 @@ static int uvc_ioctl_xu_ctrl_map(struct uvc_video_chain *chain,
+ struct uvc_control_mapping *map;
+ int ret;
+
++ if (xmap->data_type > UVC_CTRL_DATA_TYPE_BITMASK) {
++ uvc_dbg(chain->dev, CONTROL,
++ "Unsupported UVC data type %u\n", xmap->data_type);
++ return -EINVAL;
++ }
++
+ map = kzalloc(sizeof(*map), GFP_KERNEL);
+ if (map == NULL)
+ return -ENOMEM;
+--
+2.39.5
+
--- /dev/null
+From f93ccf5192861c3127b0fe4db039770abce38416 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Feb 2025 11:55:40 +0000
+Subject: media: uvcvideo: Handle uvc menu translation inside uvc_get_le_value
+
+From: Ricardo Ribalda <ribalda@chromium.org>
+
+[ Upstream commit 9109a0b4cb10fd681e9c6e9a4497a6fec5b91c39 ]
+
+map->get() gets a value from an uvc_control in "UVC format" and converts
+it to a value that can be consumed by v4l2.
+
+Instead of using a special get function for V4L2_CTRL_TYPE_MENU, we
+were converting from uvc_get_le_value in two different places.
+
+Move the conversion to uvc_get_le_value().
+
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
+Tested-by: Yunke Cao <yunkec@google.com>
+Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
+Link: https://lore.kernel.org/r/20250203-uvc-roi-v17-4-5900a9fed613@chromium.org
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/usb/uvc/uvc_ctrl.c | 77 +++++++++++++-------------------
+ 1 file changed, 32 insertions(+), 45 deletions(-)
+
+diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
+index 4e58476d305ef..4a55cf78ec526 100644
+--- a/drivers/media/usb/uvc/uvc_ctrl.c
++++ b/drivers/media/usb/uvc/uvc_ctrl.c
+@@ -862,6 +862,25 @@ static inline void uvc_clear_bit(u8 *data, int bit)
+ data[bit >> 3] &= ~(1 << (bit & 7));
+ }
+
++static s32 uvc_menu_to_v4l2_menu(struct uvc_control_mapping *mapping, s32 val)
++{
++ unsigned int i;
++
++ for (i = 0; BIT(i) <= mapping->menu_mask; ++i) {
++ u32 menu_value;
++
++ if (!test_bit(i, &mapping->menu_mask))
++ continue;
++
++ menu_value = uvc_mapping_get_menu_value(mapping, i);
++
++ if (menu_value == val)
++ return i;
++ }
++
++ return val;
++}
++
+ /*
+ * Extract the bit string specified by mapping->offset and mapping->size
+ * from the little-endian data stored at 'data' and return the result as
+@@ -896,6 +915,16 @@ static s32 uvc_get_le_value(struct uvc_control_mapping *mapping,
+ if (mapping->data_type == UVC_CTRL_DATA_TYPE_SIGNED)
+ value |= -(value & (1 << (mapping->size - 1)));
+
++ /* If it is a menu, convert from uvc to v4l2. */
++ if (mapping->v4l2_type != V4L2_CTRL_TYPE_MENU)
++ return value;
++
++ switch (query) {
++ case UVC_GET_CUR:
++ case UVC_GET_DEF:
++ return uvc_menu_to_v4l2_menu(mapping, value);
++ }
++
+ return value;
+ }
+
+@@ -1060,32 +1089,6 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain,
+ return 0;
+ }
+
+-static s32 __uvc_ctrl_get_value(struct uvc_control_mapping *mapping,
+- const u8 *data)
+-{
+- s32 value = mapping->get(mapping, UVC_GET_CUR, data);
+-
+- if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {
+- unsigned int i;
+-
+- for (i = 0; BIT(i) <= mapping->menu_mask; ++i) {
+- u32 menu_value;
+-
+- if (!test_bit(i, &mapping->menu_mask))
+- continue;
+-
+- menu_value = uvc_mapping_get_menu_value(mapping, i);
+-
+- if (menu_value == value) {
+- value = i;
+- break;
+- }
+- }
+- }
+-
+- return value;
+-}
+-
+ static int __uvc_ctrl_load_cur(struct uvc_video_chain *chain,
+ struct uvc_control *ctrl)
+ {
+@@ -1136,8 +1139,8 @@ static int __uvc_ctrl_get(struct uvc_video_chain *chain,
+ if (ret < 0)
+ return ret;
+
+- *value = __uvc_ctrl_get_value(mapping,
+- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
++ *value = mapping->get(mapping, UVC_GET_CUR,
++ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
+
+ return 0;
+ }
+@@ -1287,7 +1290,6 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
+ {
+ struct uvc_control_mapping *master_map = NULL;
+ struct uvc_control *master_ctrl = NULL;
+- unsigned int i;
+
+ memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl));
+ v4l2_ctrl->id = mapping->id;
+@@ -1330,21 +1332,6 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
+ v4l2_ctrl->minimum = ffs(mapping->menu_mask) - 1;
+ v4l2_ctrl->maximum = fls(mapping->menu_mask) - 1;
+ v4l2_ctrl->step = 1;
+-
+- for (i = 0; BIT(i) <= mapping->menu_mask; ++i) {
+- u32 menu_value;
+-
+- if (!test_bit(i, &mapping->menu_mask))
+- continue;
+-
+- menu_value = uvc_mapping_get_menu_value(mapping, i);
+-
+- if (menu_value == v4l2_ctrl->default_value) {
+- v4l2_ctrl->default_value = i;
+- break;
+- }
+- }
+-
+ return 0;
+
+ case V4L2_CTRL_TYPE_BOOLEAN:
+@@ -1630,7 +1617,7 @@ void uvc_ctrl_status_event(struct uvc_video_chain *chain,
+ uvc_ctrl_set_handle(handle, ctrl, NULL);
+
+ list_for_each_entry(mapping, &ctrl->info.mappings, list) {
+- s32 value = __uvc_ctrl_get_value(mapping, data);
++ s32 value = mapping->get(mapping, UVC_GET_CUR, data);
+
+ /*
+ * handle may be NULL here if the device sends auto-update
+--
+2.39.5
+
--- /dev/null
+From 11fb2fba0629459f098d9b5845883a7db5a6697b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 16 Dec 2024 10:48:49 +0200
+Subject: media: v4l: Memset argument to 0 before calling get_mbus_config pad
+ op
+
+From: Sakari Ailus <sakari.ailus@linux.intel.com>
+
+[ Upstream commit 91d6a99acfa5ce9f95ede775074b80f7193bd717 ]
+
+Memset the config argument to get_mbus_config V4L2 sub-device pad
+operation to zero before calling the operation. This ensures the callers
+don't need to bother with it nor the implementations need to set all
+fields that may not be relevant to them.
+
+Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
+Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/v4l2-core/v4l2-subdev.c | 2 ++
+ include/media/v4l2-subdev.h | 4 +++-
+ 2 files changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
+index cde1774c9098d..a3074f469b150 100644
+--- a/drivers/media/v4l2-core/v4l2-subdev.c
++++ b/drivers/media/v4l2-core/v4l2-subdev.c
+@@ -444,6 +444,8 @@ static int call_enum_dv_timings(struct v4l2_subdev *sd,
+ static int call_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad,
+ struct v4l2_mbus_config *config)
+ {
++ memset(config, 0, sizeof(*config));
++
+ return check_pad(sd, pad) ? :
+ sd->ops->pad->get_mbus_config(sd, pad, config);
+ }
+diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
+index 2f2200875b038..57f2bcb4eb16c 100644
+--- a/include/media/v4l2-subdev.h
++++ b/include/media/v4l2-subdev.h
+@@ -822,7 +822,9 @@ struct v4l2_subdev_state {
+ * possible configuration from the remote end, likely calling
+ * this operation as close as possible to stream on time. The
+ * operation shall fail if the pad index it has been called on
+- * is not valid or in case of unrecoverable failures.
++ * is not valid or in case of unrecoverable failures. The
++ * config argument has been memset to 0 just before calling
++ * the op.
+ *
+ * @set_routing: Enable or disable data connection routes described in the
+ * subdevice routing table. Subdevs that implement this operation
+--
+2.39.5
+
--- /dev/null
+From 3be4e488b5b483386cb72e98cffa5d1a1f8573fc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Mar 2025 15:12:03 +0100
+Subject: mei: vsc: Use struct vsc_tp_packet as vsc-tp tx_buf and rx_buf type
+
+From: Hans de Goede <hdegoede@redhat.com>
+
+[ Upstream commit f88c0c72ffb014e5eba676ee337c4eb3b1d6a119 ]
+
+vsc_tp.tx_buf and vsc_tp.rx_buf point to a struct vsc_tp_packet, use
+the correct type instead of "void *" and use sizeof(*ptr) when allocating
+memory for these buffers.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Reviewed-by: Alexander Usyskin <alexander.usyskin@intel.com>
+Reviewed-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Link: https://lore.kernel.org/r/20250318141203.94342-3-hdegoede@redhat.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/misc/mei/vsc-tp.c | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/misc/mei/vsc-tp.c b/drivers/misc/mei/vsc-tp.c
+index fa553d4914b6e..da26a080916c5 100644
+--- a/drivers/misc/mei/vsc-tp.c
++++ b/drivers/misc/mei/vsc-tp.c
+@@ -71,8 +71,8 @@ struct vsc_tp {
+ u32 seq;
+
+ /* command buffer */
+- void *tx_buf;
+- void *rx_buf;
++ struct vsc_tp_packet *tx_buf;
++ struct vsc_tp_packet *rx_buf;
+
+ atomic_t assert_cnt;
+ wait_queue_head_t xfer_wait;
+@@ -164,7 +164,7 @@ static int vsc_tp_xfer_helper(struct vsc_tp *tp, struct vsc_tp_packet *pkt,
+ {
+ int ret, offset = 0, cpy_len, src_len, dst_len = sizeof(struct vsc_tp_packet_hdr);
+ int next_xfer_len = VSC_TP_PACKET_SIZE(pkt) + VSC_TP_XFER_TIMEOUT_BYTES;
+- u8 *src, *crc_src, *rx_buf = tp->rx_buf;
++ u8 *src, *crc_src, *rx_buf = (u8 *)tp->rx_buf;
+ int count_down = VSC_TP_MAX_XFER_COUNT;
+ u32 recv_crc = 0, crc = ~0;
+ struct vsc_tp_packet_hdr ack;
+@@ -324,7 +324,7 @@ int vsc_tp_rom_xfer(struct vsc_tp *tp, const void *obuf, void *ibuf, size_t len)
+ guard(mutex)(&tp->mutex);
+
+ /* rom xfer is big endian */
+- cpu_to_be32_array(tp->tx_buf, obuf, words);
++ cpu_to_be32_array((u32 *)tp->tx_buf, obuf, words);
+
+ ret = read_poll_timeout(gpiod_get_value_cansleep, ret,
+ !ret, VSC_TP_ROM_XFER_POLL_DELAY_US,
+@@ -340,7 +340,7 @@ int vsc_tp_rom_xfer(struct vsc_tp *tp, const void *obuf, void *ibuf, size_t len)
+ return ret;
+
+ if (ibuf)
+- be32_to_cpu_array(ibuf, tp->rx_buf, words);
++ be32_to_cpu_array(ibuf, (u32 *)tp->rx_buf, words);
+
+ return ret;
+ }
+@@ -494,11 +494,11 @@ static int vsc_tp_probe(struct spi_device *spi)
+ if (!tp)
+ return -ENOMEM;
+
+- tp->tx_buf = devm_kzalloc(dev, VSC_TP_MAX_XFER_SIZE, GFP_KERNEL);
++ tp->tx_buf = devm_kzalloc(dev, sizeof(*tp->tx_buf), GFP_KERNEL);
+ if (!tp->tx_buf)
+ return -ENOMEM;
+
+- tp->rx_buf = devm_kzalloc(dev, VSC_TP_MAX_XFER_SIZE, GFP_KERNEL);
++ tp->rx_buf = devm_kzalloc(dev, sizeof(*tp->rx_buf), GFP_KERNEL);
+ if (!tp->rx_buf)
+ return -ENOMEM;
+
+--
+2.39.5
+
--- /dev/null
+From 6a7a84a63bd8faa5baf17d1432d9303367c763ee Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Feb 2025 09:58:32 -0600
+Subject: mfd: axp20x: AXP717: Add AXP717_TS_PIN_CFG to writeable regs
+
+From: Chris Morgan <macromorgan@hotmail.com>
+
+[ Upstream commit bfad07fe298bfba0c7ddab87c5b5325970203a1e ]
+
+Add AXP717_TS_PIN_CFG (register 0x50) to the table of writeable
+registers so that the temperature sensor can be configured by the
+battery driver.
+
+Signed-off-by: Chris Morgan <macromorgan@hotmail.com>
+Link: https://lore.kernel.org/r/20250204155835.161973-3-macroalpha82@gmail.com
+Signed-off-by: Lee Jones <lee@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/mfd/axp20x.c | 1 +
+ include/linux/mfd/axp20x.h | 1 +
+ 2 files changed, 2 insertions(+)
+
+diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
+index cff56deba24f0..e9914e8a29a33 100644
+--- a/drivers/mfd/axp20x.c
++++ b/drivers/mfd/axp20x.c
+@@ -224,6 +224,7 @@ static const struct regmap_range axp717_writeable_ranges[] = {
+ regmap_reg_range(AXP717_VSYS_V_POWEROFF, AXP717_VSYS_V_POWEROFF),
+ regmap_reg_range(AXP717_IRQ0_EN, AXP717_IRQ4_EN),
+ regmap_reg_range(AXP717_IRQ0_STATE, AXP717_IRQ4_STATE),
++ regmap_reg_range(AXP717_TS_PIN_CFG, AXP717_TS_PIN_CFG),
+ regmap_reg_range(AXP717_ICC_CHG_SET, AXP717_CV_CHG_SET),
+ regmap_reg_range(AXP717_DCDC_OUTPUT_CONTROL, AXP717_CPUSLDO_CONTROL),
+ regmap_reg_range(AXP717_ADC_CH_EN_CONTROL, AXP717_ADC_CH_EN_CONTROL),
+diff --git a/include/linux/mfd/axp20x.h b/include/linux/mfd/axp20x.h
+index c3df0e615fbf4..3c5aecf1d4b5b 100644
+--- a/include/linux/mfd/axp20x.h
++++ b/include/linux/mfd/axp20x.h
+@@ -137,6 +137,7 @@ enum axp20x_variants {
+ #define AXP717_IRQ2_STATE 0x4a
+ #define AXP717_IRQ3_STATE 0x4b
+ #define AXP717_IRQ4_STATE 0x4c
++#define AXP717_TS_PIN_CFG 0x50
+ #define AXP717_ICC_CHG_SET 0x62
+ #define AXP717_ITERM_CHG_SET 0x63
+ #define AXP717_CV_CHG_SET 0x64
+--
+2.39.5
+
--- /dev/null
+From bb7af46c73c6233bbc8b6098fbc3d2755df3daa9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 12 Feb 2025 19:45:24 +0100
+Subject: mfd: syscon: Add check for invalid resource size
+
+From: Eder Zulian <ezulian@redhat.com>
+
+[ Upstream commit ba09916efb29f80e438a54e634970209ce12750f ]
+
+Add a consistency check to avoid assigning an invalid value to
+max_register due to a possible DT misconfiguration.
+
+Suggested-by: Mark Langsdorf <mlangsdo@redhat.com>
+Signed-off-by: Eder Zulian <ezulian@redhat.com>
+Link: https://lore.kernel.org/r/20250212184524.585882-1-ezulian@redhat.com
+Signed-off-by: Lee Jones <lee@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/mfd/syscon.c | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c
+index aa4a9940b569a..ae71a2710bed8 100644
+--- a/drivers/mfd/syscon.c
++++ b/drivers/mfd/syscon.c
+@@ -47,6 +47,7 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_res)
+ struct regmap_config syscon_config = syscon_regmap_config;
+ struct resource res;
+ struct reset_control *reset;
++ resource_size_t res_size;
+
+ WARN_ON(!mutex_is_locked(&syscon_list_lock));
+
+@@ -96,6 +97,12 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_res)
+ }
+ }
+
++ res_size = resource_size(&res);
++ if (res_size < reg_io_width) {
++ ret = -EFAULT;
++ goto err_regmap;
++ }
++
+ syscon_config.name = kasprintf(GFP_KERNEL, "%pOFn@%pa", np, &res.start);
+ if (!syscon_config.name) {
+ ret = -ENOMEM;
+@@ -103,7 +110,7 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_res)
+ }
+ syscon_config.reg_stride = reg_io_width;
+ syscon_config.val_bits = reg_io_width * 8;
+- syscon_config.max_register = resource_size(&res) - reg_io_width;
++ syscon_config.max_register = res_size - reg_io_width;
+ if (!syscon_config.max_register)
+ syscon_config.max_register_is_0 = true;
+
+--
+2.39.5
+
--- /dev/null
+From 3b4ee60d88a6e416400d0a771283d6a9d3a17a84 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Feb 2025 11:37:23 -0600
+Subject: mfd: tps65219: Remove TPS65219_REG_TI_DEV_ID check
+
+From: Shree Ramamoorthy <s-ramamoorthy@ti.com>
+
+[ Upstream commit 76b58d5111fdcffce615beb71520bc7a6f1742c9 ]
+
+The chipid macro/variable and regmap_read function call is not needed
+because the TPS65219_REG_TI_DEV_ID register value is not a consistent value
+across TPS65219 PMIC config versions. Reading from the DEV_ID register
+without a consistent value to compare it to isn't useful. There isn't a
+way to verify the match data ID is the same ID read from the DEV_ID device
+register. 0xF0 isn't a DEV_ID value consistent across TPS65219 NVM
+configurations.
+
+For TPS65215, there is a consistent value in bits 5-0 of the DEV_ID
+register. However, there are other error checks in place within probe()
+that apply to both PMICs rather than keeping this isolated check for one
+PMIC.
+
+Signed-off-by: Shree Ramamoorthy <s-ramamoorthy@ti.com>
+Link: https://lore.kernel.org/r/20250206173725.386720-4-s-ramamoorthy@ti.com
+Signed-off-by: Lee Jones <lee@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/mfd/tps65219.c | 7 -------
+ 1 file changed, 7 deletions(-)
+
+diff --git a/drivers/mfd/tps65219.c b/drivers/mfd/tps65219.c
+index 081c5a30b04a2..4aca922658e34 100644
+--- a/drivers/mfd/tps65219.c
++++ b/drivers/mfd/tps65219.c
+@@ -221,7 +221,6 @@ static const struct regmap_irq_chip tps65219_irq_chip = {
+ static int tps65219_probe(struct i2c_client *client)
+ {
+ struct tps65219 *tps;
+- unsigned int chipid;
+ bool pwr_button;
+ int ret;
+
+@@ -246,12 +245,6 @@ static int tps65219_probe(struct i2c_client *client)
+ if (ret)
+ return ret;
+
+- ret = regmap_read(tps->regmap, TPS65219_REG_TI_DEV_ID, &chipid);
+- if (ret) {
+- dev_err(tps->dev, "Failed to read device ID: %d\n", ret);
+- return ret;
+- }
+-
+ ret = devm_mfd_add_devices(tps->dev, PLATFORM_DEVID_AUTO,
+ tps65219_cells, ARRAY_SIZE(tps65219_cells),
+ NULL, 0, regmap_irq_get_domain(tps->irq_data));
+--
+2.39.5
+
--- /dev/null
+From 389bcb990935a18c9eadb6294e5de4744576f886 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jan 2025 13:32:48 +0100
+Subject: MIPS: pm-cps: Use per-CPU variables as per-CPU, not per-core
+
+From: Paul Burton <paulburton@kernel.org>
+
+[ Upstream commit 00a134fc2bb4a5f8fada58cf7ff4259149691d64 ]
+
+The pm-cps code has up until now used per-CPU variables indexed by core,
+rather than CPU number, in order to share data amongst sibling CPUs (ie.
+VPs/threads in a core). This works fine for single cluster systems, but
+with multi-cluster systems a core number is no longer unique in the
+system, leading to sharing between CPUs that are not actually siblings.
+
+Avoid this issue by using per-CPU variables as they are more generally
+used - ie. access them using CPU numbers rather than core numbers.
+Sharing between siblings is then accomplished by:
+ - Assigning the same pointer to entries for each sibling CPU for the
+ nc_asm_enter & ready_count variables, which allow this by virtue of
+ being per-CPU pointers.
+
+ - Indexing by the first CPU set in a CPUs cpu_sibling_map in the case
+ of pm_barrier, for which we can't use the previous approach because
+ the per-CPU variable is not a pointer.
+
+Signed-off-by: Paul Burton <paulburton@kernel.org>
+Signed-off-by: Dragan Mladjenovic <dragan.mladjenovic@syrmia.com>
+Signed-off-by: Aleksandar Rikalo <arikalo@gmail.com>
+Tested-by: Serge Semin <fancer.lancer@gmail.com>
+Tested-by: Gregory CLEMENT <gregory.clement@bootlin.com>
+Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/mips/kernel/pm-cps.c | 30 +++++++++++++++++-------------
+ 1 file changed, 17 insertions(+), 13 deletions(-)
+
+diff --git a/arch/mips/kernel/pm-cps.c b/arch/mips/kernel/pm-cps.c
+index d09ca77e624d7..9369a8dc385e2 100644
+--- a/arch/mips/kernel/pm-cps.c
++++ b/arch/mips/kernel/pm-cps.c
+@@ -57,10 +57,7 @@ static DEFINE_PER_CPU_ALIGNED(u32*, ready_count);
+ /* Indicates online CPUs coupled with the current CPU */
+ static DEFINE_PER_CPU_ALIGNED(cpumask_t, online_coupled);
+
+-/*
+- * Used to synchronize entry to deep idle states. Actually per-core rather
+- * than per-CPU.
+- */
++/* Used to synchronize entry to deep idle states */
+ static DEFINE_PER_CPU_ALIGNED(atomic_t, pm_barrier);
+
+ /* Saved CPU state across the CPS_PM_POWER_GATED state */
+@@ -112,9 +109,10 @@ int cps_pm_enter_state(enum cps_pm_state state)
+ cps_nc_entry_fn entry;
+ struct core_boot_config *core_cfg;
+ struct vpe_boot_config *vpe_cfg;
++ atomic_t *barrier;
+
+ /* Check that there is an entry function for this state */
+- entry = per_cpu(nc_asm_enter, core)[state];
++ entry = per_cpu(nc_asm_enter, cpu)[state];
+ if (!entry)
+ return -EINVAL;
+
+@@ -150,7 +148,7 @@ int cps_pm_enter_state(enum cps_pm_state state)
+ smp_mb__after_atomic();
+
+ /* Create a non-coherent mapping of the core ready_count */
+- core_ready_count = per_cpu(ready_count, core);
++ core_ready_count = per_cpu(ready_count, cpu);
+ nc_addr = kmap_noncoherent(virt_to_page(core_ready_count),
+ (unsigned long)core_ready_count);
+ nc_addr += ((unsigned long)core_ready_count & ~PAGE_MASK);
+@@ -158,7 +156,8 @@ int cps_pm_enter_state(enum cps_pm_state state)
+
+ /* Ensure ready_count is zero-initialised before the assembly runs */
+ WRITE_ONCE(*nc_core_ready_count, 0);
+- coupled_barrier(&per_cpu(pm_barrier, core), online);
++ barrier = &per_cpu(pm_barrier, cpumask_first(&cpu_sibling_map[cpu]));
++ coupled_barrier(barrier, online);
+
+ /* Run the generated entry code */
+ left = entry(online, nc_core_ready_count);
+@@ -629,12 +628,14 @@ static void *cps_gen_entry_code(unsigned cpu, enum cps_pm_state state)
+
+ static int cps_pm_online_cpu(unsigned int cpu)
+ {
+- enum cps_pm_state state;
+- unsigned core = cpu_core(&cpu_data[cpu]);
++ unsigned int sibling, core;
+ void *entry_fn, *core_rc;
++ enum cps_pm_state state;
++
++ core = cpu_core(&cpu_data[cpu]);
+
+ for (state = CPS_PM_NC_WAIT; state < CPS_PM_STATE_COUNT; state++) {
+- if (per_cpu(nc_asm_enter, core)[state])
++ if (per_cpu(nc_asm_enter, cpu)[state])
+ continue;
+ if (!test_bit(state, state_support))
+ continue;
+@@ -646,16 +647,19 @@ static int cps_pm_online_cpu(unsigned int cpu)
+ clear_bit(state, state_support);
+ }
+
+- per_cpu(nc_asm_enter, core)[state] = entry_fn;
++ for_each_cpu(sibling, &cpu_sibling_map[cpu])
++ per_cpu(nc_asm_enter, sibling)[state] = entry_fn;
+ }
+
+- if (!per_cpu(ready_count, core)) {
++ if (!per_cpu(ready_count, cpu)) {
+ core_rc = kmalloc(sizeof(u32), GFP_KERNEL);
+ if (!core_rc) {
+ pr_err("Failed allocate core %u ready_count\n", core);
+ return -ENOMEM;
+ }
+- per_cpu(ready_count, core) = core_rc;
++
++ for_each_cpu(sibling, &cpu_sibling_map[cpu])
++ per_cpu(ready_count, sibling) = core_rc;
+ }
+
+ return 0;
+--
+2.39.5
+
--- /dev/null
+From df17265e941ed7fd5e5b9f2e8038f4081a8fe2ed Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 9 Jun 2020 10:54:35 +0800
+Subject: MIPS: Use arch specific syscall name match function
+
+From: Bibo Mao <maobibo@loongson.cn>
+
+[ Upstream commit 756276ce78d5624dc814f9d99f7d16c8fd51076e ]
+
+On MIPS system, most of the syscall function name begin with prefix
+sys_. Some syscalls are special such as clone/fork, function name of
+these begin with __sys_. Since scratch registers need be saved in
+stack when these system calls happens.
+
+With ftrace system call method, system call functions are declared with
+SYSCALL_DEFINEx, metadata of the system call symbol name begins with
+sys_. Here mips specific function arch_syscall_match_sym_name is used to
+compare function name between sys_call_table[] and metadata of syscall
+symbol.
+
+Signed-off-by: Bibo Mao <maobibo@loongson.cn>
+Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/mips/include/asm/ftrace.h | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+diff --git a/arch/mips/include/asm/ftrace.h b/arch/mips/include/asm/ftrace.h
+index dc025888f6d28..b41fc10446688 100644
+--- a/arch/mips/include/asm/ftrace.h
++++ b/arch/mips/include/asm/ftrace.h
+@@ -91,4 +91,20 @@ void prepare_ftrace_return(unsigned long *parent_ra_addr, unsigned long self_ra,
+
+ #endif /* __ASSEMBLY__ */
+ #endif /* CONFIG_FUNCTION_TRACER */
++
++#ifdef CONFIG_FTRACE_SYSCALLS
++#ifndef __ASSEMBLY__
++/*
++ * Some syscall entry functions on mips start with "__sys_" (fork and clone,
++ * for instance). We should also match the sys_ variant with those.
++ */
++#define ARCH_HAS_SYSCALL_MATCH_SYM_NAME
++static inline bool arch_syscall_match_sym_name(const char *sym,
++ const char *name)
++{
++ return !strcmp(sym, name) ||
++ (!strncmp(sym, "__sys_", 6) && !strcmp(sym + 6, name + 4));
++}
++#endif /* __ASSEMBLY__ */
++#endif /* CONFIG_FTRACE_SYSCALLS */
+ #endif /* _ASM_MIPS_FTRACE_H */
+--
+2.39.5
+
--- /dev/null
+From 490832036da12ad8968bd1998b4be593a19e6b14 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 23 Jan 2025 13:01:48 +0100
+Subject: misc: pci_endpoint_test: Give disabled BARs a distinct error code
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Niklas Cassel <cassel@kernel.org>
+
+[ Upstream commit 7e80bbef1d697dbce7a39cfad0df770880fe3f29 ]
+
+The current code returns -ENOMEM if test->bar[barno] is NULL.
+
+There can be two reasons why test->bar[barno] is NULL:
+
+ 1) The pci_ioremap_bar() call in pci_endpoint_test_probe() failed.
+ 2) The BAR was skipped, because it is disabled by the endpoint.
+
+Many PCI endpoint controller drivers will disable all BARs in their
+init function. A disabled BAR will have a size of 0.
+
+A PCI endpoint function driver will be able to enable any BAR that
+is not marked as BAR_RESERVED (which means that the BAR should not
+be touched by the EPF driver).
+
+Thus, perform check if the size is 0, before checking if
+test->bar[barno] is NULL, such that we can return different errors.
+
+This will allow the selftests to return SKIP instead of FAIL for
+disabled BARs.
+
+Signed-off-by: Niklas Cassel <cassel@kernel.org>
+Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+Link: https://lore.kernel.org/r/20250123120147.3603409-3-cassel@kernel.org
+Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+[kwilczynski: commit log]
+Signed-off-by: Krzysztof Wilczyński <kwilczynski@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/misc/pci_endpoint_test.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
+index 4c0f37ad0281b..8a7e860c06812 100644
+--- a/drivers/misc/pci_endpoint_test.c
++++ b/drivers/misc/pci_endpoint_test.c
+@@ -295,11 +295,13 @@ static int pci_endpoint_test_bar(struct pci_endpoint_test *test,
+ struct pci_dev *pdev = test->pdev;
+ int buf_size;
+
++ bar_size = pci_resource_len(pdev, barno);
++ if (!bar_size)
++ return -ENODATA;
++
+ if (!test->bar[barno])
+ return -ENOMEM;
+
+- bar_size = pci_resource_len(pdev, barno);
+-
+ if (barno == test->test_reg_bar)
+ bar_size = 0x4;
+
+--
+2.39.5
+
--- /dev/null
+From a12bbab84a13269ad1251ba69c4c1550cb310419 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 19 Feb 2025 00:17:49 +0530
+Subject: mmc: dw_mmc: add exynos7870 DW MMC support
+
+From: Kaustabh Chakraborty <kauschluss@disroot.org>
+
+[ Upstream commit 7cbe799ac10fd8be85af5e0615c4337f81e575f3 ]
+
+Add support for Exynos7870 DW MMC controllers, for both SMU and non-SMU
+variants. These controllers require a quirk to access 64-bit FIFO in 32-bit
+accesses (DW_MMC_QUIRK_FIFO64_32).
+
+Signed-off-by: Kaustabh Chakraborty <kauschluss@disroot.org>
+Link: https://lore.kernel.org/r/20250219-exynos7870-mmc-v2-3-b4255a3e39ed@disroot.org
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/mmc/host/dw_mmc-exynos.c | 41 +++++++++++++++++++++++++++++++-
+ 1 file changed, 40 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
+index 53d32d0f2709e..e3548408ca392 100644
+--- a/drivers/mmc/host/dw_mmc-exynos.c
++++ b/drivers/mmc/host/dw_mmc-exynos.c
+@@ -27,6 +27,8 @@ enum dw_mci_exynos_type {
+ DW_MCI_TYPE_EXYNOS5420_SMU,
+ DW_MCI_TYPE_EXYNOS7,
+ DW_MCI_TYPE_EXYNOS7_SMU,
++ DW_MCI_TYPE_EXYNOS7870,
++ DW_MCI_TYPE_EXYNOS7870_SMU,
+ DW_MCI_TYPE_ARTPEC8,
+ };
+
+@@ -69,6 +71,12 @@ static struct dw_mci_exynos_compatible {
+ }, {
+ .compatible = "samsung,exynos7-dw-mshc-smu",
+ .ctrl_type = DW_MCI_TYPE_EXYNOS7_SMU,
++ }, {
++ .compatible = "samsung,exynos7870-dw-mshc",
++ .ctrl_type = DW_MCI_TYPE_EXYNOS7870,
++ }, {
++ .compatible = "samsung,exynos7870-dw-mshc-smu",
++ .ctrl_type = DW_MCI_TYPE_EXYNOS7870_SMU,
+ }, {
+ .compatible = "axis,artpec8-dw-mshc",
+ .ctrl_type = DW_MCI_TYPE_ARTPEC8,
+@@ -85,6 +93,8 @@ static inline u8 dw_mci_exynos_get_ciu_div(struct dw_mci *host)
+ return EXYNOS4210_FIXED_CIU_CLK_DIV;
+ else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 ||
++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU ||
+ priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
+ return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL64)) + 1;
+ else
+@@ -100,7 +110,8 @@ static void dw_mci_exynos_config_smu(struct dw_mci *host)
+ * set for non-ecryption mode at this time.
+ */
+ if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS5420_SMU ||
+- priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) {
++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU) {
+ mci_writel(host, MPSBEGIN0, 0);
+ mci_writel(host, MPSEND0, SDMMC_ENDING_SEC_NR_MAX);
+ mci_writel(host, MPSCTRL0, SDMMC_MPSCTRL_SECURE_WRITE_BIT |
+@@ -126,6 +137,12 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host)
+ DQS_CTRL_GET_RD_DELAY(priv->saved_strobe_ctrl);
+ }
+
++ if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 ||
++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU) {
++ /* Quirk needed for certain Exynos SoCs */
++ host->quirks |= DW_MMC_QUIRK_FIFO64_32;
++ }
++
+ if (priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) {
+ /* Quirk needed for the ARTPEC-8 SoC */
+ host->quirks |= DW_MMC_QUIRK_EXTENDED_TMOUT;
+@@ -143,6 +160,8 @@ static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing)
+
+ if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 ||
++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU ||
+ priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
+ clksel = mci_readl(host, CLKSEL64);
+ else
+@@ -152,6 +171,8 @@ static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing)
+
+ if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 ||
++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU ||
+ priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
+ mci_writel(host, CLKSEL64, clksel);
+ else
+@@ -222,6 +243,8 @@ static int dw_mci_exynos_resume_noirq(struct device *dev)
+
+ if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 ||
++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU ||
+ priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
+ clksel = mci_readl(host, CLKSEL64);
+ else
+@@ -230,6 +253,8 @@ static int dw_mci_exynos_resume_noirq(struct device *dev)
+ if (clksel & SDMMC_CLKSEL_WAKEUP_INT) {
+ if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 ||
++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU ||
+ priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
+ mci_writel(host, CLKSEL64, clksel);
+ else
+@@ -409,6 +434,8 @@ static inline u8 dw_mci_exynos_get_clksmpl(struct dw_mci *host)
+
+ if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 ||
++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU ||
+ priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
+ return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL64));
+ else
+@@ -422,6 +449,8 @@ static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample)
+
+ if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 ||
++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU ||
+ priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
+ clksel = mci_readl(host, CLKSEL64);
+ else
+@@ -429,6 +458,8 @@ static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample)
+ clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample);
+ if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 ||
++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU ||
+ priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
+ mci_writel(host, CLKSEL64, clksel);
+ else
+@@ -443,6 +474,8 @@ static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host)
+
+ if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 ||
++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU ||
+ priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
+ clksel = mci_readl(host, CLKSEL64);
+ else
+@@ -453,6 +486,8 @@ static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host)
+
+ if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 ||
++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU ||
+ priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
+ mci_writel(host, CLKSEL64, clksel);
+ else
+@@ -632,6 +667,10 @@ static const struct of_device_id dw_mci_exynos_match[] = {
+ .data = &exynos_drv_data, },
+ { .compatible = "samsung,exynos7-dw-mshc-smu",
+ .data = &exynos_drv_data, },
++ { .compatible = "samsung,exynos7870-dw-mshc",
++ .data = &exynos_drv_data, },
++ { .compatible = "samsung,exynos7870-dw-mshc-smu",
++ .data = &exynos_drv_data, },
+ { .compatible = "axis,artpec8-dw-mshc",
+ .data = &artpec_drv_data, },
+ {},
+--
+2.39.5
+
--- /dev/null
+From 8e4d98a534311eef32572adbc84918ede7a03cd6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 14 Mar 2025 14:50:21 -0500
+Subject: mmc: host: Wait for Vdd to settle on card power off
+
+From: Erick Shepherd <erick.shepherd@ni.com>
+
+[ Upstream commit 31e75ed964582257f59156ce6a42860e1ae4cc39 ]
+
+The SD spec version 6.0 section 6.4.1.5 requires that Vdd must be
+lowered to less than 0.5V for a minimum of 1 ms when powering off a
+card. Increase wait to 15 ms so that voltage has time to drain down
+to 0.5V and cards can power off correctly. Issues with voltage drain
+time were only observed on Apollo Lake and Bay Trail host controllers
+so this fix is limited to those devices.
+
+Signed-off-by: Erick Shepherd <erick.shepherd@ni.com>
+Acked-by: Adrian Hunter <adrian.hunter@intel.com>
+Link: https://lore.kernel.org/r/20250314195021.1588090-1-erick.shepherd@ni.com
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/mmc/host/sdhci-pci-core.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c
+index 1f0bd723f0112..13a84b9309e06 100644
+--- a/drivers/mmc/host/sdhci-pci-core.c
++++ b/drivers/mmc/host/sdhci-pci-core.c
+@@ -610,8 +610,12 @@ static void sdhci_intel_set_power(struct sdhci_host *host, unsigned char mode,
+
+ sdhci_set_power(host, mode, vdd);
+
+- if (mode == MMC_POWER_OFF)
++ if (mode == MMC_POWER_OFF) {
++ if (slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_APL_SD ||
++ slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BYT_SD)
++ usleep_range(15000, 17500);
+ return;
++ }
+
+ /*
+ * Bus power might not enable after D3 -> D0 transition due to the
+--
+2.39.5
+
--- /dev/null
+From 7c984b26b26153d97008ff9b74d5c41cc3f7416a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Feb 2025 15:46:45 -0600
+Subject: mmc: sdhci: Disable SD card clock before changing parameters
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Erick Shepherd <erick.shepherd@ni.com>
+
+[ Upstream commit fb3bbc46c94f261b6156ee863c1b06c84cf157dc ]
+
+Per the SD Host Controller Simplified Specification v4.20 §3.2.3, change
+the SD card clock parameters only after first disabling the external card
+clock. Doing this fixes a spurious clock pulse on Baytrail and Apollo Lake
+SD controllers which otherwise breaks voltage switching with a specific
+Swissbit SD card.
+
+Signed-off-by: Kyle Roeschley <kyle.roeschley@ni.com>
+Signed-off-by: Brad Mouring <brad.mouring@ni.com>
+Signed-off-by: Erick Shepherd <erick.shepherd@ni.com>
+Acked-by: Adrian Hunter <adrian.hunter@intel.com>
+Link: https://lore.kernel.org/r/20250211214645.469279-1-erick.shepherd@ni.com
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/mmc/host/sdhci.c | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
+index f4a7733a8ad22..5f91b44891f9b 100644
+--- a/drivers/mmc/host/sdhci.c
++++ b/drivers/mmc/host/sdhci.c
+@@ -2065,10 +2065,15 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
+
+ host->mmc->actual_clock = 0;
+
+- sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
++ clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
++ if (clk & SDHCI_CLOCK_CARD_EN)
++ sdhci_writew(host, clk & ~SDHCI_CLOCK_CARD_EN,
++ SDHCI_CLOCK_CONTROL);
+
+- if (clock == 0)
++ if (clock == 0) {
++ sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
+ return;
++ }
+
+ clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock);
+ sdhci_enable_clk(host, clk);
+--
+2.39.5
+
--- /dev/null
+From e1241a635e77a6c6f15110a13eef5daa4cc8874f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 7 Feb 2025 14:59:20 +0100
+Subject: mptcp: pm: userspace: flags: clearer msg if no remote addr
+
+From: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+
+[ Upstream commit 58b21309f97b08b6b9814d1ee1419249eba9ef08 ]
+
+Since its introduction in commit 892f396c8e68 ("mptcp: netlink: issue
+MP_PRIO signals from userspace PMs"), it was mandatory to specify the
+remote address, because of the 'if (rem->addr.family == AF_UNSPEC)'
+check done later one.
+
+In theory, this attribute can be optional, but it sounds better to be
+precise to avoid sending the MP_PRIO on the wrong subflow, e.g. if there
+are multiple subflows attached to the same local ID. This can be relaxed
+later on if there is a need to act on multiple subflows with one
+command.
+
+For the moment, the check to see if attr_rem is NULL can be removed,
+because mptcp_pm_parse_entry() will do this check as well, no need to do
+that differently here.
+
+Reviewed-by: Geliang Tang <geliang@kernel.org>
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/mptcp/pm_userspace.c | 8 +++-----
+ 1 file changed, 3 insertions(+), 5 deletions(-)
+
+diff --git a/net/mptcp/pm_userspace.c b/net/mptcp/pm_userspace.c
+index 940ca94c88634..cd220742d2493 100644
+--- a/net/mptcp/pm_userspace.c
++++ b/net/mptcp/pm_userspace.c
+@@ -583,11 +583,9 @@ int mptcp_userspace_pm_set_flags(struct sk_buff *skb, struct genl_info *info)
+ if (ret < 0)
+ goto set_flags_err;
+
+- if (attr_rem) {
+- ret = mptcp_pm_parse_entry(attr_rem, info, false, &rem);
+- if (ret < 0)
+- goto set_flags_err;
+- }
++ ret = mptcp_pm_parse_entry(attr_rem, info, false, &rem);
++ if (ret < 0)
++ goto set_flags_err;
+
+ if (loc.addr.family == AF_UNSPEC ||
+ rem.addr.family == AF_UNSPEC) {
+--
+2.39.5
+
--- /dev/null
+From cb74d0847afe9e6a8ccbafdefe2088d55ab31929 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 25 Feb 2025 21:15:09 +0100
+Subject: net: ethernet: mtk_ppe_offload: Allow QinQ, double ETH_P_8021Q only
+
+From: Eric Woudstra <ericwouds@gmail.com>
+
+[ Upstream commit 7fe0353606d77a32c4c7f2814833dd1c043ebdd2 ]
+
+mtk_foe_entry_set_vlan() in mtk_ppe.c already supports double vlan
+tagging, but mtk_flow_offload_replace() in mtk_ppe_offload.c only allows
+for 1 vlan tag, optionally in combination with pppoe and dsa tags.
+
+However, mtk_foe_entry_set_vlan() only allows for setting the vlan id.
+The protocol cannot be set, it is always ETH_P_8021Q, for inner and outer
+tag. This patch adds QinQ support to mtk_flow_offload_replace(), only in
+the case that both inner and outer tags are ETH_P_8021Q.
+
+Only PPPoE-in-Q (as before) and Q-in-Q are allowed. A combination
+of PPPoE and Q-in-Q is not allowed.
+
+Signed-off-by: Eric Woudstra <ericwouds@gmail.com>
+Link: https://patch.msgid.link/20250225201509.20843-1-ericwouds@gmail.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../net/ethernet/mediatek/mtk_ppe_offload.c | 22 +++++++++----------
+ 1 file changed, 11 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+index f20bb390df3ad..c855fb799ce14 100644
+--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
++++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+@@ -34,8 +34,10 @@ struct mtk_flow_data {
+ u16 vlan_in;
+
+ struct {
+- u16 id;
+- __be16 proto;
++ struct {
++ u16 id;
++ __be16 proto;
++ } vlans[2];
+ u8 num;
+ } vlan;
+ struct {
+@@ -349,18 +351,19 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f,
+ case FLOW_ACTION_CSUM:
+ break;
+ case FLOW_ACTION_VLAN_PUSH:
+- if (data.vlan.num == 1 ||
++ if (data.vlan.num + data.pppoe.num == 2 ||
+ act->vlan.proto != htons(ETH_P_8021Q))
+ return -EOPNOTSUPP;
+
+- data.vlan.id = act->vlan.vid;
+- data.vlan.proto = act->vlan.proto;
++ data.vlan.vlans[data.vlan.num].id = act->vlan.vid;
++ data.vlan.vlans[data.vlan.num].proto = act->vlan.proto;
+ data.vlan.num++;
+ break;
+ case FLOW_ACTION_VLAN_POP:
+ break;
+ case FLOW_ACTION_PPPOE_PUSH:
+- if (data.pppoe.num == 1)
++ if (data.pppoe.num == 1 ||
++ data.vlan.num == 2)
+ return -EOPNOTSUPP;
+
+ data.pppoe.sid = act->pppoe.sid;
+@@ -450,12 +453,9 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f,
+ if (offload_type == MTK_PPE_PKT_TYPE_BRIDGE)
+ foe.bridge.vlan = data.vlan_in;
+
+- if (data.vlan.num == 1) {
+- if (data.vlan.proto != htons(ETH_P_8021Q))
+- return -EOPNOTSUPP;
++ for (i = 0; i < data.vlan.num; i++)
++ mtk_foe_entry_set_vlan(eth, &foe, data.vlan.vlans[i].id);
+
+- mtk_foe_entry_set_vlan(eth, &foe, data.vlan.id);
+- }
+ if (data.pppoe.num == 1)
+ mtk_foe_entry_set_pppoe(eth, &foe, data.pppoe.sid);
+
+--
+2.39.5
+
--- /dev/null
+From 73beb4826f12949227b87e9c9a5ec4a6191da179 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Mar 2025 08:46:57 +0100
+Subject: net: ethernet: ti: cpsw_new: populate netdev of_node
+
+From: Alexander Sverdlin <alexander.sverdlin@siemens.com>
+
+[ Upstream commit 7ff1c88fc89688c27f773ba956f65f0c11367269 ]
+
+So that of_find_net_device_by_node() can find CPSW ports and other DSA
+switches can be stacked downstream. Tested in conjunction with KSZ8873.
+
+Reviewed-by: Siddharth Vadapalli <s-vadapalli@ti.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Alexander Sverdlin <alexander.sverdlin@siemens.com>
+Link: https://patch.msgid.link/20250303074703.1758297-1-alexander.sverdlin@siemens.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/ti/cpsw_new.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/net/ethernet/ti/cpsw_new.c b/drivers/net/ethernet/ti/cpsw_new.c
+index cec0a90659d94..66713bc931741 100644
+--- a/drivers/net/ethernet/ti/cpsw_new.c
++++ b/drivers/net/ethernet/ti/cpsw_new.c
+@@ -1418,6 +1418,7 @@ static int cpsw_create_ports(struct cpsw_common *cpsw)
+ ndev->netdev_ops = &cpsw_netdev_ops;
+ ndev->ethtool_ops = &cpsw_ethtool_ops;
+ SET_NETDEV_DEV(ndev, dev);
++ ndev->dev.of_node = slave_data->slave_node;
+
+ if (!napi_ndev) {
+ /* CPSW Host port CPDMA interface is shared between
+--
+2.39.5
+
--- /dev/null
+From 845cdfd025cb2eac5c949cecf90e9470493a1662 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Feb 2025 15:53:28 -0800
+Subject: net: ethtool: prevent flow steering to RSS contexts which don't exist
+
+From: Jakub Kicinski <kuba@kernel.org>
+
+[ Upstream commit de7f7582dff292832fbdeaeff34e6b2ee6f9f95f ]
+
+Since commit 42dc431f5d0e ("ethtool: rss: prevent rss ctx deletion
+when in use") we prevent removal of RSS contexts pointed to by
+existing flow rules. Core should also prevent creation of rules
+which point to RSS context which don't exist in the first place.
+
+Reviewed-by: Joe Damato <jdamato@fastly.com>
+Link: https://patch.msgid.link/20250206235334.1425329-2-kuba@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ethtool/ioctl.c | 12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
+index 1c3ba2247776b..0d3a70a18884f 100644
+--- a/net/ethtool/ioctl.c
++++ b/net/ethtool/ioctl.c
+@@ -993,10 +993,14 @@ static noinline_for_stack int ethtool_set_rxnfc(struct net_device *dev,
+ return rc;
+
+ /* Nonzero ring with RSS only makes sense if NIC adds them together */
+- if (cmd == ETHTOOL_SRXCLSRLINS && info.fs.flow_type & FLOW_RSS &&
+- !ops->cap_rss_rxnfc_adds &&
+- ethtool_get_flow_spec_ring(info.fs.ring_cookie))
+- return -EINVAL;
++ if (cmd == ETHTOOL_SRXCLSRLINS && info.fs.flow_type & FLOW_RSS) {
++ if (!ops->cap_rss_rxnfc_adds &&
++ ethtool_get_flow_spec_ring(info.fs.ring_cookie))
++ return -EINVAL;
++
++ if (!xa_load(&dev->ethtool->rss_ctx, info.rss_context))
++ return -EINVAL;
++ }
+
+ if (cmd == ETHTOOL_SRXFH && ops->get_rxfh) {
+ struct ethtool_rxfh_param rxfh = {};
+--
+2.39.5
+
--- /dev/null
+From 05c210bcafb4eb6a1de9d2a3134f5dca5a50598d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 7 Feb 2025 13:12:55 +0100
+Subject: net: fec: Refactor MAC reset to function
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Csókás, Bence <csokas.bence@prolan.hu>
+
+[ Upstream commit 67800d296191d0a9bde0a7776f99ca1ddfa0fc26 ]
+
+The core is reset both in `fec_restart()` (called on link-up) and
+`fec_stop()` (going to sleep, driver remove etc.). These two functions
+had their separate implementations, which was at first only a register
+write and a `udelay()` (and the accompanying block comment). However,
+since then we got soft-reset (MAC disable) and Wake-on-LAN support, which
+meant that these implementations diverged, often causing bugs.
+
+For instance, as of now, `fec_stop()` does not check for
+`FEC_QUIRK_NO_HARD_RESET`, meaning the MII/RMII mode is cleared on eg.
+a PM power-down event; and `fec_restart()` missed the refactor renaming
+the "magic" constant `1` to `FEC_ECR_RESET`.
+
+To harmonize current implementations, and eliminate this source of
+potential future bugs, refactor implementation to a common function.
+
+Reviewed-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
+Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Signed-off-by: Csókás, Bence <csokas.bence@prolan.hu>
+Link: https://patch.msgid.link/20250207121255.161146-2-csokas.bence@prolan.hu
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/freescale/fec_main.c | 52 +++++++++++------------
+ 1 file changed, 25 insertions(+), 27 deletions(-)
+
+diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
+index c5d5fa8d7dfdd..17e9bddb9ddd5 100644
+--- a/drivers/net/ethernet/freescale/fec_main.c
++++ b/drivers/net/ethernet/freescale/fec_main.c
+@@ -1098,6 +1098,29 @@ static void fec_enet_enable_ring(struct net_device *ndev)
+ }
+ }
+
++/* Whack a reset. We should wait for this.
++ * For i.MX6SX SOC, enet use AXI bus, we use disable MAC
++ * instead of reset MAC itself.
++ */
++static void fec_ctrl_reset(struct fec_enet_private *fep, bool allow_wol)
++{
++ u32 val;
++
++ if (!allow_wol || !(fep->wol_flag & FEC_WOL_FLAG_SLEEP_ON)) {
++ if (fep->quirks & FEC_QUIRK_HAS_MULTI_QUEUES ||
++ ((fep->quirks & FEC_QUIRK_NO_HARD_RESET) && fep->link)) {
++ writel(0, fep->hwp + FEC_ECNTRL);
++ } else {
++ writel(FEC_ECR_RESET, fep->hwp + FEC_ECNTRL);
++ udelay(10);
++ }
++ } else {
++ val = readl(fep->hwp + FEC_ECNTRL);
++ val |= (FEC_ECR_MAGICEN | FEC_ECR_SLEEP);
++ writel(val, fep->hwp + FEC_ECNTRL);
++ }
++}
++
+ /*
+ * This function is called to start or restart the FEC during a link
+ * change, transmit timeout, or to reconfigure the FEC. The network
+@@ -1114,17 +1137,7 @@ fec_restart(struct net_device *ndev)
+ if (fep->bufdesc_ex)
+ fec_ptp_save_state(fep);
+
+- /* Whack a reset. We should wait for this.
+- * For i.MX6SX SOC, enet use AXI bus, we use disable MAC
+- * instead of reset MAC itself.
+- */
+- if (fep->quirks & FEC_QUIRK_HAS_MULTI_QUEUES ||
+- ((fep->quirks & FEC_QUIRK_NO_HARD_RESET) && fep->link)) {
+- writel(0, fep->hwp + FEC_ECNTRL);
+- } else {
+- writel(1, fep->hwp + FEC_ECNTRL);
+- udelay(10);
+- }
++ fec_ctrl_reset(fep, false);
+
+ /*
+ * enet-mac reset will reset mac address registers too,
+@@ -1378,22 +1391,7 @@ fec_stop(struct net_device *ndev)
+ if (fep->bufdesc_ex)
+ fec_ptp_save_state(fep);
+
+- /* Whack a reset. We should wait for this.
+- * For i.MX6SX SOC, enet use AXI bus, we use disable MAC
+- * instead of reset MAC itself.
+- */
+- if (!(fep->wol_flag & FEC_WOL_FLAG_SLEEP_ON)) {
+- if (fep->quirks & FEC_QUIRK_HAS_MULTI_QUEUES) {
+- writel(0, fep->hwp + FEC_ECNTRL);
+- } else {
+- writel(FEC_ECR_RESET, fep->hwp + FEC_ECNTRL);
+- udelay(10);
+- }
+- } else {
+- val = readl(fep->hwp + FEC_ECNTRL);
+- val |= (FEC_ECR_MAGICEN | FEC_ECR_SLEEP);
+- writel(val, fep->hwp + FEC_ECNTRL);
+- }
++ fec_ctrl_reset(fep, true);
+ writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
+ writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
+
+--
+2.39.5
+
--- /dev/null
+From ca77c9d14a7ce2b3f171996f86fc7788c192f69b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Feb 2025 14:48:25 +0000
+Subject: net: flush_backlog() small changes
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit cbe08724c18078564abefbf6591078a7c98e5e0f ]
+
+Add READ_ONCE() around reads of skb->dev->reg_state, because
+this field can be changed from other threads/cpus.
+
+Instead of calling dev_kfree_skb_irq() and kfree_skb()
+while interrupts are masked and locks held,
+use a temporary list and use __skb_queue_purge_reason()
+
+Use SKB_DROP_REASON_DEV_READY drop reason to better
+describe why these skbs are dropped.
+
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Reviewed-by: Jason Xing <kerneljasonxing@gmail.com>
+Link: https://patch.msgid.link/20250204144825.316785-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/core/dev.c | 12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+diff --git a/net/core/dev.c b/net/core/dev.c
+index 2f7f5fd9ffec7..77306b522966c 100644
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -6187,16 +6187,18 @@ EXPORT_SYMBOL(netif_receive_skb_list);
+ static void flush_backlog(struct work_struct *work)
+ {
+ struct sk_buff *skb, *tmp;
++ struct sk_buff_head list;
+ struct softnet_data *sd;
+
++ __skb_queue_head_init(&list);
+ local_bh_disable();
+ sd = this_cpu_ptr(&softnet_data);
+
+ backlog_lock_irq_disable(sd);
+ skb_queue_walk_safe(&sd->input_pkt_queue, skb, tmp) {
+- if (skb->dev->reg_state == NETREG_UNREGISTERING) {
++ if (READ_ONCE(skb->dev->reg_state) == NETREG_UNREGISTERING) {
+ __skb_unlink(skb, &sd->input_pkt_queue);
+- dev_kfree_skb_irq(skb);
++ __skb_queue_tail(&list, skb);
+ rps_input_queue_head_incr(sd);
+ }
+ }
+@@ -6204,14 +6206,16 @@ static void flush_backlog(struct work_struct *work)
+
+ local_lock_nested_bh(&softnet_data.process_queue_bh_lock);
+ skb_queue_walk_safe(&sd->process_queue, skb, tmp) {
+- if (skb->dev->reg_state == NETREG_UNREGISTERING) {
++ if (READ_ONCE(skb->dev->reg_state) == NETREG_UNREGISTERING) {
+ __skb_unlink(skb, &sd->process_queue);
+- kfree_skb(skb);
++ __skb_queue_tail(&list, skb);
+ rps_input_queue_head_incr(sd);
+ }
+ }
+ local_unlock_nested_bh(&softnet_data.process_queue_bh_lock);
+ local_bh_enable();
++
++ __skb_queue_purge_reason(&list, SKB_DROP_REASON_DEV_READY);
+ }
+
+ static bool flush_required(int cpu)
+--
+2.39.5
+
--- /dev/null
+From b80009ffcba8c94bbcc8ed2e480ed237506bf1af Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 7 Mar 2025 18:16:59 +0200
+Subject: net: hsr: Fix PRP duplicate detection
+
+From: Jaakko Karrenpalo <jkarrenpalo@gmail.com>
+
+[ Upstream commit 05fd00e5e7b1ac60d264f72423fba38cc382b447 ]
+
+Add PRP specific function for handling duplicate
+packets. This is needed because of potential
+L2 802.1p prioritization done by network switches.
+
+The L2 prioritization can re-order the PRP packets
+from a node causing the existing implementation to
+discard the frame(s) that have been received 'late'
+because the sequence number is before the previous
+received packet. This can happen if the node is
+sending multiple frames back-to-back with different
+priority.
+
+Signed-off-by: Jaakko Karrenpalo <jkarrenpalo@gmail.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20250307161700.1045-1-jkarrenpalo@gmail.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/hsr/hsr_device.c | 2 +
+ net/hsr/hsr_forward.c | 4 +-
+ net/hsr/hsr_framereg.c | 95 ++++++++++++++++++++++++++++++++++++++++--
+ net/hsr/hsr_framereg.h | 8 +++-
+ net/hsr/hsr_main.h | 2 +
+ 5 files changed, 104 insertions(+), 7 deletions(-)
+
+diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c
+index b6fb18469439a..2c43776b7c4fb 100644
+--- a/net/hsr/hsr_device.c
++++ b/net/hsr/hsr_device.c
+@@ -616,6 +616,7 @@ static struct hsr_proto_ops hsr_ops = {
+ .drop_frame = hsr_drop_frame,
+ .fill_frame_info = hsr_fill_frame_info,
+ .invalid_dan_ingress_frame = hsr_invalid_dan_ingress_frame,
++ .register_frame_out = hsr_register_frame_out,
+ };
+
+ static struct hsr_proto_ops prp_ops = {
+@@ -626,6 +627,7 @@ static struct hsr_proto_ops prp_ops = {
+ .fill_frame_info = prp_fill_frame_info,
+ .handle_san_frame = prp_handle_san_frame,
+ .update_san_info = prp_update_san_info,
++ .register_frame_out = prp_register_frame_out,
+ };
+
+ void hsr_dev_setup(struct net_device *dev)
+diff --git a/net/hsr/hsr_forward.c b/net/hsr/hsr_forward.c
+index a4bacf1985558..c67c0d35921de 100644
+--- a/net/hsr/hsr_forward.c
++++ b/net/hsr/hsr_forward.c
+@@ -536,8 +536,8 @@ static void hsr_forward_do(struct hsr_frame_info *frame)
+ * Also for SAN, this shouldn't be done.
+ */
+ if (!frame->is_from_san &&
+- hsr_register_frame_out(port, frame->node_src,
+- frame->sequence_nr))
++ hsr->proto_ops->register_frame_out &&
++ hsr->proto_ops->register_frame_out(port, frame))
+ continue;
+
+ if (frame->is_supervision && port->type == HSR_PT_MASTER &&
+diff --git a/net/hsr/hsr_framereg.c b/net/hsr/hsr_framereg.c
+index 73bc6f659812f..85991fab7db58 100644
+--- a/net/hsr/hsr_framereg.c
++++ b/net/hsr/hsr_framereg.c
+@@ -35,6 +35,7 @@ static bool seq_nr_after(u16 a, u16 b)
+
+ #define seq_nr_before(a, b) seq_nr_after((b), (a))
+ #define seq_nr_before_or_eq(a, b) (!seq_nr_after((a), (b)))
++#define PRP_DROP_WINDOW_LEN 32768
+
+ bool hsr_addr_is_redbox(struct hsr_priv *hsr, unsigned char *addr)
+ {
+@@ -176,8 +177,11 @@ static struct hsr_node *hsr_add_node(struct hsr_priv *hsr,
+ new_node->time_in[i] = now;
+ new_node->time_out[i] = now;
+ }
+- for (i = 0; i < HSR_PT_PORTS; i++)
++ for (i = 0; i < HSR_PT_PORTS; i++) {
+ new_node->seq_out[i] = seq_out;
++ new_node->seq_expected[i] = seq_out + 1;
++ new_node->seq_start[i] = seq_out + 1;
++ }
+
+ if (san && hsr->proto_ops->handle_san_frame)
+ hsr->proto_ops->handle_san_frame(san, rx_port, new_node);
+@@ -482,9 +486,11 @@ void hsr_register_frame_in(struct hsr_node *node, struct hsr_port *port,
+ * 0 otherwise, or
+ * negative error code on error
+ */
+-int hsr_register_frame_out(struct hsr_port *port, struct hsr_node *node,
+- u16 sequence_nr)
++int hsr_register_frame_out(struct hsr_port *port, struct hsr_frame_info *frame)
+ {
++ struct hsr_node *node = frame->node_src;
++ u16 sequence_nr = frame->sequence_nr;
++
+ spin_lock_bh(&node->seq_out_lock);
+ if (seq_nr_before_or_eq(sequence_nr, node->seq_out[port->type]) &&
+ time_is_after_jiffies(node->time_out[port->type] +
+@@ -499,6 +505,89 @@ int hsr_register_frame_out(struct hsr_port *port, struct hsr_node *node,
+ return 0;
+ }
+
++/* Adaptation of the PRP duplicate discard algorithm described in wireshark
++ * wiki (https://wiki.wireshark.org/PRP)
++ *
++ * A drop window is maintained for both LANs with start sequence set to the
++ * first sequence accepted on the LAN that has not been seen on the other LAN,
++ * and expected sequence set to the latest received sequence number plus one.
++ *
++ * When a frame is received on either LAN it is compared against the received
++ * frames on the other LAN. If it is outside the drop window of the other LAN
++ * the frame is accepted and the drop window is updated.
++ * The drop window for the other LAN is reset.
++ *
++ * 'port' is the outgoing interface
++ * 'frame' is the frame to be sent
++ *
++ * Return:
++ * 1 if frame can be shown to have been sent recently on this interface,
++ * 0 otherwise
++ */
++int prp_register_frame_out(struct hsr_port *port, struct hsr_frame_info *frame)
++{
++ enum hsr_port_type other_port;
++ enum hsr_port_type rcv_port;
++ struct hsr_node *node;
++ u16 sequence_diff;
++ u16 sequence_exp;
++ u16 sequence_nr;
++
++ /* out-going frames are always in order
++ * and can be checked the same way as for HSR
++ */
++ if (frame->port_rcv->type == HSR_PT_MASTER)
++ return hsr_register_frame_out(port, frame);
++
++ /* for PRP we should only forward frames from the slave ports
++ * to the master port
++ */
++ if (port->type != HSR_PT_MASTER)
++ return 1;
++
++ node = frame->node_src;
++ sequence_nr = frame->sequence_nr;
++ sequence_exp = sequence_nr + 1;
++ rcv_port = frame->port_rcv->type;
++ other_port = rcv_port == HSR_PT_SLAVE_A ? HSR_PT_SLAVE_B :
++ HSR_PT_SLAVE_A;
++
++ spin_lock_bh(&node->seq_out_lock);
++ if (time_is_before_jiffies(node->time_out[port->type] +
++ msecs_to_jiffies(HSR_ENTRY_FORGET_TIME)) ||
++ (node->seq_start[rcv_port] == node->seq_expected[rcv_port] &&
++ node->seq_start[other_port] == node->seq_expected[other_port])) {
++ /* the node hasn't been sending for a while
++ * or both drop windows are empty, forward the frame
++ */
++ node->seq_start[rcv_port] = sequence_nr;
++ } else if (seq_nr_before(sequence_nr, node->seq_expected[other_port]) &&
++ seq_nr_before_or_eq(node->seq_start[other_port], sequence_nr)) {
++ /* drop the frame, update the drop window for the other port
++ * and reset our drop window
++ */
++ node->seq_start[other_port] = sequence_exp;
++ node->seq_expected[rcv_port] = sequence_exp;
++ node->seq_start[rcv_port] = node->seq_expected[rcv_port];
++ spin_unlock_bh(&node->seq_out_lock);
++ return 1;
++ }
++
++ /* update the drop window for the port where this frame was received
++ * and clear the drop window for the other port
++ */
++ node->seq_start[other_port] = node->seq_expected[other_port];
++ node->seq_expected[rcv_port] = sequence_exp;
++ sequence_diff = sequence_exp - node->seq_start[rcv_port];
++ if (sequence_diff > PRP_DROP_WINDOW_LEN)
++ node->seq_start[rcv_port] = sequence_exp - PRP_DROP_WINDOW_LEN;
++
++ node->time_out[port->type] = jiffies;
++ node->seq_out[port->type] = sequence_nr;
++ spin_unlock_bh(&node->seq_out_lock);
++ return 0;
++}
++
+ static struct hsr_port *get_late_port(struct hsr_priv *hsr,
+ struct hsr_node *node)
+ {
+diff --git a/net/hsr/hsr_framereg.h b/net/hsr/hsr_framereg.h
+index 993fa950d8144..b04948659d84d 100644
+--- a/net/hsr/hsr_framereg.h
++++ b/net/hsr/hsr_framereg.h
+@@ -44,8 +44,7 @@ void hsr_addr_subst_dest(struct hsr_node *node_src, struct sk_buff *skb,
+
+ void hsr_register_frame_in(struct hsr_node *node, struct hsr_port *port,
+ u16 sequence_nr);
+-int hsr_register_frame_out(struct hsr_port *port, struct hsr_node *node,
+- u16 sequence_nr);
++int hsr_register_frame_out(struct hsr_port *port, struct hsr_frame_info *frame);
+
+ void hsr_prune_nodes(struct timer_list *t);
+ void hsr_prune_proxy_nodes(struct timer_list *t);
+@@ -73,6 +72,8 @@ void prp_update_san_info(struct hsr_node *node, bool is_sup);
+ bool hsr_is_node_in_db(struct list_head *node_db,
+ const unsigned char addr[ETH_ALEN]);
+
++int prp_register_frame_out(struct hsr_port *port, struct hsr_frame_info *frame);
++
+ struct hsr_node {
+ struct list_head mac_list;
+ /* Protect R/W access to seq_out */
+@@ -89,6 +90,9 @@ struct hsr_node {
+ bool san_b;
+ u16 seq_out[HSR_PT_PORTS];
+ bool removed;
++ /* PRP specific duplicate handling */
++ u16 seq_expected[HSR_PT_PORTS];
++ u16 seq_start[HSR_PT_PORTS];
+ struct rcu_head rcu_head;
+ };
+
+diff --git a/net/hsr/hsr_main.h b/net/hsr/hsr_main.h
+index 7561845b8bf6f..1bc47b17a2968 100644
+--- a/net/hsr/hsr_main.h
++++ b/net/hsr/hsr_main.h
+@@ -175,6 +175,8 @@ struct hsr_proto_ops {
+ struct hsr_frame_info *frame);
+ bool (*invalid_dan_ingress_frame)(__be16 protocol);
+ void (*update_san_info)(struct hsr_node *node, bool is_sup);
++ int (*register_frame_out)(struct hsr_port *port,
++ struct hsr_frame_info *frame);
+ };
+
+ struct hsr_self_node {
+--
+2.39.5
+
--- /dev/null
+From 129b0146292d5954901c021d23751a6ec6d1128e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 19 Feb 2025 20:50:33 +0800
+Subject: net: ipv6: Init tunnel link-netns before registering dev
+
+From: Xiao Liang <shaw.leon@gmail.com>
+
+[ Upstream commit db014522f35606031d8ac58b4aed6b1ed84f03d1 ]
+
+Currently some IPv6 tunnel drivers set tnl->net to dev_net(dev) in
+ndo_init(), which is called in register_netdevice(). However, it lacks
+the context of link-netns when we enable cross-net tunnels at device
+registration time.
+
+Let's move the init of tunnel link-netns before register_netdevice().
+
+ip6_gre has already initialized netns, so just remove the redundant
+assignment.
+
+Signed-off-by: Xiao Liang <shaw.leon@gmail.com>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Link: https://patch.msgid.link/20250219125039.18024-8-shaw.leon@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/ip6_gre.c | 2 --
+ net/ipv6/ip6_tunnel.c | 3 ++-
+ net/ipv6/ip6_vti.c | 3 ++-
+ net/ipv6/sit.c | 8 +++++---
+ 4 files changed, 9 insertions(+), 7 deletions(-)
+
+diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
+index 235808cfec705..68e9a41eed491 100644
+--- a/net/ipv6/ip6_gre.c
++++ b/net/ipv6/ip6_gre.c
+@@ -1498,7 +1498,6 @@ static int ip6gre_tunnel_init_common(struct net_device *dev)
+ tunnel = netdev_priv(dev);
+
+ tunnel->dev = dev;
+- tunnel->net = dev_net(dev);
+ strcpy(tunnel->parms.name, dev->name);
+
+ ret = dst_cache_init(&tunnel->dst_cache, GFP_KERNEL);
+@@ -1882,7 +1881,6 @@ static int ip6erspan_tap_init(struct net_device *dev)
+ tunnel = netdev_priv(dev);
+
+ tunnel->dev = dev;
+- tunnel->net = dev_net(dev);
+ strcpy(tunnel->parms.name, dev->name);
+
+ ret = dst_cache_init(&tunnel->dst_cache, GFP_KERNEL);
+diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
+index 48fd53b989726..5350c9bb2319b 100644
+--- a/net/ipv6/ip6_tunnel.c
++++ b/net/ipv6/ip6_tunnel.c
+@@ -1878,7 +1878,6 @@ ip6_tnl_dev_init_gen(struct net_device *dev)
+ int t_hlen;
+
+ t->dev = dev;
+- t->net = dev_net(dev);
+
+ ret = dst_cache_init(&t->dst_cache, GFP_KERNEL);
+ if (ret)
+@@ -1940,6 +1939,7 @@ static int __net_init ip6_fb_tnl_dev_init(struct net_device *dev)
+ struct net *net = dev_net(dev);
+ struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
+
++ t->net = net;
+ t->parms.proto = IPPROTO_IPV6;
+
+ rcu_assign_pointer(ip6n->tnls_wc[0], t);
+@@ -2013,6 +2013,7 @@ static int ip6_tnl_newlink(struct net *src_net, struct net_device *dev,
+ int err;
+
+ nt = netdev_priv(dev);
++ nt->net = net;
+
+ if (ip_tunnel_netlink_encap_parms(data, &ipencap)) {
+ err = ip6_tnl_encap_setup(nt, &ipencap);
+diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c
+index 590737c275379..0123504691443 100644
+--- a/net/ipv6/ip6_vti.c
++++ b/net/ipv6/ip6_vti.c
+@@ -925,7 +925,6 @@ static inline int vti6_dev_init_gen(struct net_device *dev)
+ struct ip6_tnl *t = netdev_priv(dev);
+
+ t->dev = dev;
+- t->net = dev_net(dev);
+ netdev_hold(dev, &t->dev_tracker, GFP_KERNEL);
+ netdev_lockdep_set_classes(dev);
+ return 0;
+@@ -958,6 +957,7 @@ static int __net_init vti6_fb_tnl_dev_init(struct net_device *dev)
+ struct net *net = dev_net(dev);
+ struct vti6_net *ip6n = net_generic(net, vti6_net_id);
+
++ t->net = net;
+ t->parms.proto = IPPROTO_IPV6;
+
+ rcu_assign_pointer(ip6n->tnls_wc[0], t);
+@@ -1008,6 +1008,7 @@ static int vti6_newlink(struct net *src_net, struct net_device *dev,
+ vti6_netlink_parms(data, &nt->parms);
+
+ nt->parms.proto = IPPROTO_IPV6;
++ nt->net = net;
+
+ if (vti6_locate(net, &nt->parms, 0))
+ return -EEXIST;
+diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
+index 39bd8951bfca1..3c15a0ae228e2 100644
+--- a/net/ipv6/sit.c
++++ b/net/ipv6/sit.c
+@@ -269,6 +269,7 @@ static struct ip_tunnel *ipip6_tunnel_locate(struct net *net,
+
+ nt = netdev_priv(dev);
+
++ nt->net = net;
+ nt->parms = *parms;
+ if (ipip6_tunnel_create(dev) < 0)
+ goto failed_free;
+@@ -1449,7 +1450,6 @@ static int ipip6_tunnel_init(struct net_device *dev)
+ int err;
+
+ tunnel->dev = dev;
+- tunnel->net = dev_net(dev);
+ strcpy(tunnel->parms.name, dev->name);
+
+ ipip6_tunnel_bind_dev(dev);
+@@ -1563,6 +1563,7 @@ static int ipip6_newlink(struct net *src_net, struct net_device *dev,
+ int err;
+
+ nt = netdev_priv(dev);
++ nt->net = net;
+
+ if (ip_tunnel_netlink_encap_parms(data, &ipencap)) {
+ err = ip_tunnel_encap_setup(nt, &ipencap);
+@@ -1858,6 +1859,9 @@ static int __net_init sit_init_net(struct net *net)
+ */
+ sitn->fb_tunnel_dev->netns_local = true;
+
++ t = netdev_priv(sitn->fb_tunnel_dev);
++ t->net = net;
++
+ err = register_netdev(sitn->fb_tunnel_dev);
+ if (err)
+ goto err_reg_dev;
+@@ -1865,8 +1869,6 @@ static int __net_init sit_init_net(struct net *net)
+ ipip6_tunnel_clone_6rd(sitn->fb_tunnel_dev, sitn);
+ ipip6_fb_tunnel_init(sitn->fb_tunnel_dev);
+
+- t = netdev_priv(sitn->fb_tunnel_dev);
+-
+ strcpy(t->parms.name, sitn->fb_tunnel_dev->name);
+ return 0;
+
+--
+2.39.5
+
--- /dev/null
+From 0eae065450be2ef104c0dc82bac62985379ba2ec Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 20 Jan 2025 09:27:14 -0800
+Subject: net/mana: fix warning in the writer of client oob
+
+From: Konstantin Taranov <kotaranov@microsoft.com>
+
+[ Upstream commit 5ec7e1c86c441c46a374577bccd9488abea30037 ]
+
+Do not warn on missing pad_data when oob is in sgl.
+
+Signed-off-by: Konstantin Taranov <kotaranov@microsoft.com>
+Link: https://patch.msgid.link/1737394039-28772-9-git-send-email-kotaranov@linux.microsoft.com
+Reviewed-by: Shiraz Saleem <shirazsaleem@microsoft.com>
+Reviewed-by: Long Li <longli@microsoft.com>
+Signed-off-by: Leon Romanovsky <leon@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/microsoft/mana/gdma_main.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c
+index 638ef64d639f3..f412e17b0d505 100644
+--- a/drivers/net/ethernet/microsoft/mana/gdma_main.c
++++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c
+@@ -1047,7 +1047,7 @@ static u32 mana_gd_write_client_oob(const struct gdma_wqe_request *wqe_req,
+ header->inline_oob_size_div4 = client_oob_size / sizeof(u32);
+
+ if (oob_in_sgl) {
+- WARN_ON_ONCE(!pad_data || wqe_req->num_sge < 2);
++ WARN_ON_ONCE(wqe_req->num_sge < 2);
+
+ header->client_oob_in_sgl = 1;
+
+--
+2.39.5
+
--- /dev/null
+From 8766c43a2a807b13d42dbdb37c90118ca506d6a1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 10 Feb 2025 09:45:05 -0800
+Subject: net/mlx4_core: Avoid impossible mlx4_db_alloc() order value
+
+From: Kees Cook <kees@kernel.org>
+
+[ Upstream commit 4a6f18f28627e121bd1f74b5fcc9f945d6dbeb1e ]
+
+GCC can see that the value range for "order" is capped, but this leads
+it to consider that it might be negative, leading to a false positive
+warning (with GCC 15 with -Warray-bounds -fdiagnostics-details):
+
+../drivers/net/ethernet/mellanox/mlx4/alloc.c:691:47: error: array subscript -1 is below array bounds of 'long unsigned int *[2]' [-Werror=array-bounds=]
+ 691 | i = find_first_bit(pgdir->bits[o], MLX4_DB_PER_PAGE >> o);
+ | ~~~~~~~~~~~^~~
+ 'mlx4_alloc_db_from_pgdir': events 1-2
+ 691 | i = find_first_bit(pgdir->bits[o], MLX4_DB_PER_PAGE >> o); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | | | | | (2) out of array bounds here
+ | (1) when the condition is evaluated to true In file included from ../drivers/net/ethernet/mellanox/mlx4/mlx4.h:53,
+ from ../drivers/net/ethernet/mellanox/mlx4/alloc.c:42:
+../include/linux/mlx4/device.h:664:33: note: while referencing 'bits'
+ 664 | unsigned long *bits[2];
+ | ^~~~
+
+Switch the argument to unsigned int, which removes the compiler needing
+to consider negative values.
+
+Signed-off-by: Kees Cook <kees@kernel.org>
+Link: https://patch.msgid.link/20250210174504.work.075-kees@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mellanox/mlx4/alloc.c | 6 +++---
+ include/linux/mlx4/device.h | 2 +-
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx4/alloc.c b/drivers/net/ethernet/mellanox/mlx4/alloc.c
+index b330020dc0d67..f2bded847e61d 100644
+--- a/drivers/net/ethernet/mellanox/mlx4/alloc.c
++++ b/drivers/net/ethernet/mellanox/mlx4/alloc.c
+@@ -682,9 +682,9 @@ static struct mlx4_db_pgdir *mlx4_alloc_db_pgdir(struct device *dma_device)
+ }
+
+ static int mlx4_alloc_db_from_pgdir(struct mlx4_db_pgdir *pgdir,
+- struct mlx4_db *db, int order)
++ struct mlx4_db *db, unsigned int order)
+ {
+- int o;
++ unsigned int o;
+ int i;
+
+ for (o = order; o <= 1; ++o) {
+@@ -712,7 +712,7 @@ static int mlx4_alloc_db_from_pgdir(struct mlx4_db_pgdir *pgdir,
+ return 0;
+ }
+
+-int mlx4_db_alloc(struct mlx4_dev *dev, struct mlx4_db *db, int order)
++int mlx4_db_alloc(struct mlx4_dev *dev, struct mlx4_db *db, unsigned int order)
+ {
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ struct mlx4_db_pgdir *pgdir;
+diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h
+index 27f42f713c891..86f0f2a25a3d6 100644
+--- a/include/linux/mlx4/device.h
++++ b/include/linux/mlx4/device.h
+@@ -1135,7 +1135,7 @@ int mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
+ int mlx4_buf_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
+ struct mlx4_buf *buf);
+
+-int mlx4_db_alloc(struct mlx4_dev *dev, struct mlx4_db *db, int order);
++int mlx4_db_alloc(struct mlx4_dev *dev, struct mlx4_db *db, unsigned int order);
+ void mlx4_db_free(struct mlx4_dev *dev, struct mlx4_db *db);
+
+ int mlx4_alloc_hwq_res(struct mlx4_dev *dev, struct mlx4_hwq_resources *wqres,
+--
+2.39.5
+
--- /dev/null
+From 894796f40c339ca5060f7d2f7254bb0a4d299ef3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 13 Feb 2025 11:46:38 +0200
+Subject: net/mlx5: Apply rate-limiting to high temperature warning
+
+From: Shahar Shitrit <shshitrit@nvidia.com>
+
+[ Upstream commit 9dd3d5d258aceb37bdf09c8b91fa448f58ea81f0 ]
+
+Wrap the high temperature warning in a temperature event with
+a call to net_ratelimit() to prevent flooding the kernel log
+with repeated warning messages when temperature exceeds the
+threshold multiple times within a short duration.
+
+Signed-off-by: Shahar Shitrit <shshitrit@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Reviewed-by: Mateusz Polchlopek <mateusz.polchlopek@intel.com>
+Link: https://patch.msgid.link/20250213094641.226501-2-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mellanox/mlx5/core/events.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/events.c b/drivers/net/ethernet/mellanox/mlx5/core/events.c
+index cd8d107f7d9e3..fc6e56305cbbc 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/events.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/events.c
+@@ -169,9 +169,10 @@ static int temp_warn(struct notifier_block *nb, unsigned long type, void *data)
+ value_lsb &= 0x1;
+ value_msb = be64_to_cpu(eqe->data.temp_warning.sensor_warning_msb);
+
+- mlx5_core_warn(events->dev,
+- "High temperature on sensors with bit set %llx %llx",
+- value_msb, value_lsb);
++ if (net_ratelimit())
++ mlx5_core_warn(events->dev,
++ "High temperature on sensors with bit set %llx %llx",
++ value_msb, value_lsb);
+
+ return NOTIFY_OK;
+ }
+--
+2.39.5
+
--- /dev/null
+From d482bef9ee8e9465d672e40ac3cded961e789e0c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Feb 2025 14:25:40 +0200
+Subject: net/mlx5: Avoid report two health errors on same syndrome
+
+From: Moshe Shemesh <moshe@nvidia.com>
+
+[ Upstream commit b5d7b2f04ebcff740f44ef4d295b3401aeb029f4 ]
+
+In case health counter has not increased for few polling intervals, miss
+counter will reach max misses threshold and health report will be
+triggered for FW health reporter. In case syndrome found on same health
+poll another health report will be triggered.
+
+Avoid two health reports on same syndrome by marking this syndrome as
+already known.
+
+Signed-off-by: Moshe Shemesh <moshe@nvidia.com>
+Reviewed-by: Shahar Shitrit <shshitrit@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mellanox/mlx5/core/health.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c
+index a6329ca2d9bff..52c8035547be5 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/health.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c
+@@ -799,6 +799,7 @@ static void poll_health(struct timer_list *t)
+ health->prev = count;
+ if (health->miss_counter == MAX_MISSES) {
+ mlx5_core_err(dev, "device's health compromised - reached miss count\n");
++ health->synd = ioread8(&h->synd);
+ print_health_info(dev);
+ queue_work(health->wq, &health->report_work);
+ }
+--
+2.39.5
+
--- /dev/null
+From f9e3263d6695e7ebd6d5a2458383be396d953ede Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 19 Feb 2025 10:58:08 +0200
+Subject: net/mlx5: Change POOL_NEXT_SIZE define value and make it global
+
+From: Patrisious Haddad <phaddad@nvidia.com>
+
+[ Upstream commit 80df31f384b4146a62a01b3d4beb376cc7b9a89e ]
+
+Change POOL_NEXT_SIZE define value from 0 to BIT(30), since this define
+is used to request the available maximum sized flow table, and zero doesn't
+make sense for it, whereas some places in the driver use zero explicitly
+expecting the smallest table size possible but instead due to this
+define they end up allocating the biggest table size unawarely.
+
+In addition move the definition to "include/linux/mlx5/fs.h" to expose the
+define to IB driver as well, while appropriately renaming it.
+
+Signed-off-by: Patrisious Haddad <phaddad@nvidia.com>
+Reviewed-by: Maor Gottlieb <maorg@nvidia.com>
+Reviewed-by: Mark Bloch <mbloch@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/20250219085808.349923-3-tariqt@nvidia.com
+Signed-off-by: Leon Romanovsky <leon@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mellanox/mlx5/core/esw/legacy.c | 2 +-
+ drivers/net/ethernet/mellanox/mlx5/core/fs_ft_pool.c | 6 ++++--
+ drivers/net/ethernet/mellanox/mlx5/core/fs_ft_pool.h | 2 --
+ drivers/net/ethernet/mellanox/mlx5/core/lib/fs_chains.c | 3 ++-
+ include/linux/mlx5/fs.h | 2 ++
+ 5 files changed, 9 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/legacy.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/legacy.c
+index 45183de424f3d..76382626ad41d 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/esw/legacy.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/legacy.c
+@@ -96,7 +96,7 @@ static int esw_create_legacy_fdb_table(struct mlx5_eswitch *esw)
+ if (!flow_group_in)
+ return -ENOMEM;
+
+- ft_attr.max_fte = POOL_NEXT_SIZE;
++ ft_attr.max_fte = MLX5_FS_MAX_POOL_SIZE;
+ ft_attr.prio = LEGACY_FDB_PRIO;
+ fdb = mlx5_create_flow_table(root_ns, &ft_attr);
+ if (IS_ERR(fdb)) {
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_ft_pool.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_ft_pool.c
+index c14590acc7726..f6abfd00d7e68 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_ft_pool.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_ft_pool.c
+@@ -50,10 +50,12 @@ mlx5_ft_pool_get_avail_sz(struct mlx5_core_dev *dev, enum fs_flow_table_type tab
+ int i, found_i = -1;
+
+ for (i = ARRAY_SIZE(FT_POOLS) - 1; i >= 0; i--) {
+- if (dev->priv.ft_pool->ft_left[i] && FT_POOLS[i] >= desired_size &&
++ if (dev->priv.ft_pool->ft_left[i] &&
++ (FT_POOLS[i] >= desired_size ||
++ desired_size == MLX5_FS_MAX_POOL_SIZE) &&
+ FT_POOLS[i] <= max_ft_size) {
+ found_i = i;
+- if (desired_size != POOL_NEXT_SIZE)
++ if (desired_size != MLX5_FS_MAX_POOL_SIZE)
+ break;
+ }
+ }
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_ft_pool.h b/drivers/net/ethernet/mellanox/mlx5/core/fs_ft_pool.h
+index 25f4274b372b5..173e312db7204 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_ft_pool.h
++++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_ft_pool.h
+@@ -7,8 +7,6 @@
+ #include <linux/mlx5/driver.h>
+ #include "fs_core.h"
+
+-#define POOL_NEXT_SIZE 0
+-
+ int mlx5_ft_pool_init(struct mlx5_core_dev *dev);
+ void mlx5_ft_pool_destroy(struct mlx5_core_dev *dev);
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/fs_chains.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/fs_chains.c
+index 711d14dea2485..d313cb7f0ed88 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/fs_chains.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/fs_chains.c
+@@ -161,7 +161,8 @@ mlx5_chains_create_table(struct mlx5_fs_chains *chains,
+ ft_attr.flags |= (MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT |
+ MLX5_FLOW_TABLE_TUNNEL_EN_DECAP);
+
+- sz = (chain == mlx5_chains_get_nf_ft_chain(chains)) ? FT_TBL_SZ : POOL_NEXT_SIZE;
++ sz = (chain == mlx5_chains_get_nf_ft_chain(chains)) ?
++ FT_TBL_SZ : MLX5_FS_MAX_POOL_SIZE;
+ ft_attr.max_fte = sz;
+
+ /* We use chains_default_ft(chains) as the table's next_ft till
+diff --git a/include/linux/mlx5/fs.h b/include/linux/mlx5/fs.h
+index 2a69d9d71276d..01cb72d68c231 100644
+--- a/include/linux/mlx5/fs.h
++++ b/include/linux/mlx5/fs.h
+@@ -40,6 +40,8 @@
+
+ #define MLX5_SET_CFG(p, f, v) MLX5_SET(create_flow_group_in, p, f, v)
+
++#define MLX5_FS_MAX_POOL_SIZE BIT(30)
++
+ enum mlx5_flow_destination_type {
+ MLX5_FLOW_DESTINATION_TYPE_NONE,
+ MLX5_FLOW_DESTINATION_TYPE_VPORT,
+--
+2.39.5
+
--- /dev/null
+From 1db593b5993f4cae52fe73069849089607d66e43 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 9 Feb 2025 12:17:15 +0200
+Subject: net/mlx5: Extend Ethtool loopback selftest to support non-linear SKB
+
+From: Alexei Lazar <alazar@nvidia.com>
+
+[ Upstream commit 95b9606b15bb3ce1198d28d2393dd0e1f0a5f3e9 ]
+
+Current loopback test validation ignores non-linear SKB case in
+the SKB access, which can lead to failures in scenarios such as
+when HW GRO is enabled.
+Linearize the SKB so both cases will be handled.
+
+Signed-off-by: Alexei Lazar <alazar@nvidia.com>
+Reviewed-by: Dragos Tatulea <dtatulea@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/20250209101716.112774-15-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c b/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c
+index 1d60465cc2ca4..2f7a543feca62 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c
+@@ -166,6 +166,9 @@ mlx5e_test_loopback_validate(struct sk_buff *skb,
+ struct udphdr *udph;
+ struct iphdr *iph;
+
++ if (skb_linearize(skb))
++ goto out;
++
+ /* We are only going to peek, no need to clone the SKB */
+ if (MLX5E_TEST_PKT_SIZE - ETH_HLEN > skb_headlen(skb))
+ goto out;
+--
+2.39.5
+
--- /dev/null
+From fcd6556f31f0e513fdba3e09a42efaed43ca5037 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 13 Feb 2025 11:46:40 +0200
+Subject: net/mlx5: Modify LSB bitmask in temperature event to include only the
+ first bit
+
+From: Shahar Shitrit <shshitrit@nvidia.com>
+
+[ Upstream commit 633f16d7e07c129a36b882c05379e01ce5bdb542 ]
+
+In the sensor_count field of the MTEWE register, bits 1-62 are
+supported only for unmanaged switches, not for NICs, and bit 63
+is reserved for internal use.
+
+To prevent confusing output that may include set bits that are
+not relevant to NIC sensors, we update the bitmask to retain only
+the first bit, which corresponds to the sensor ASIC.
+
+Signed-off-by: Shahar Shitrit <shshitrit@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Reviewed-by: Mateusz Polchlopek <mateusz.polchlopek@intel.com>
+Link: https://patch.msgid.link/20250213094641.226501-4-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mellanox/mlx5/core/events.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/events.c b/drivers/net/ethernet/mellanox/mlx5/core/events.c
+index d91ea53eb394d..cd8d107f7d9e3 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/events.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/events.c
+@@ -163,6 +163,10 @@ static int temp_warn(struct notifier_block *nb, unsigned long type, void *data)
+ u64 value_msb;
+
+ value_lsb = be64_to_cpu(eqe->data.temp_warning.sensor_warning_lsb);
++ /* bit 1-63 are not supported for NICs,
++ * hence read only bit 0 (asic) from lsb.
++ */
++ value_lsb &= 0x1;
+ value_msb = be64_to_cpu(eqe->data.temp_warning.sensor_warning_msb);
+
+ mlx5_core_warn(events->dev,
+--
+2.39.5
+
--- /dev/null
+From a6f75385517e1301967fa0924396a8853f308606 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 10 Mar 2025 23:26:55 +0200
+Subject: net/mlx5: Preserve rate settings when creating a rate node
+
+From: Carolina Jubran <cjubran@nvidia.com>
+
+[ Upstream commit f88c349c75e3784a3f5463f5b403ff28dd823782 ]
+
+Modify `esw_qos_create_node_sched_elem()` to receive max_rate and
+bw_share values while maintaining the previous configuration.
+
+This change is essential for the upcoming patch that will modify rate
+nodes and requires the existing settings to be preserved unless
+explicitly changed.
+
+Signed-off-by: Carolina Jubran <cjubran@nvidia.com>
+Reviewed-by: Dragos Tatulea <dtatulea@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/1741642016-44918-4-git-send-email-tariqt@nvidia.com
+Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c | 13 +++++++++----
+ 1 file changed, 9 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c
+index 823c1ba456cd1..803bacf2a95e6 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c
+@@ -305,8 +305,9 @@ static int esw_qos_set_node_min_rate(struct mlx5_esw_sched_node *node,
+ return 0;
+ }
+
+-static int esw_qos_create_node_sched_elem(struct mlx5_core_dev *dev, u32 parent_element_id,
+- u32 *tsar_ix)
++static int
++esw_qos_create_node_sched_elem(struct mlx5_core_dev *dev, u32 parent_element_id,
++ u32 max_rate, u32 bw_share, u32 *tsar_ix)
+ {
+ u32 tsar_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {};
+ void *attr;
+@@ -323,6 +324,8 @@ static int esw_qos_create_node_sched_elem(struct mlx5_core_dev *dev, u32 parent_
+ SCHEDULING_CONTEXT_ELEMENT_TYPE_TSAR);
+ MLX5_SET(scheduling_context, tsar_ctx, parent_element_id,
+ parent_element_id);
++ MLX5_SET(scheduling_context, tsar_ctx, max_average_bw, max_rate);
++ MLX5_SET(scheduling_context, tsar_ctx, bw_share, bw_share);
+ attr = MLX5_ADDR_OF(scheduling_context, tsar_ctx, element_attributes);
+ MLX5_SET(tsar_element, attr, tsar_type, TSAR_ELEMENT_TSAR_TYPE_DWRR);
+
+@@ -396,7 +399,8 @@ __esw_qos_create_vports_sched_node(struct mlx5_eswitch *esw, struct mlx5_esw_sch
+ u32 tsar_ix;
+ int err;
+
+- err = esw_qos_create_node_sched_elem(esw->dev, esw->qos.root_tsar_ix, &tsar_ix);
++ err = esw_qos_create_node_sched_elem(esw->dev, esw->qos.root_tsar_ix, 0,
++ 0, &tsar_ix);
+ if (err) {
+ NL_SET_ERR_MSG_MOD(extack, "E-Switch create TSAR for node failed");
+ return ERR_PTR(err);
+@@ -463,7 +467,8 @@ static int esw_qos_create(struct mlx5_eswitch *esw, struct netlink_ext_ack *exta
+ if (!MLX5_CAP_GEN(dev, qos) || !MLX5_CAP_QOS(dev, esw_scheduling))
+ return -EOPNOTSUPP;
+
+- err = esw_qos_create_node_sched_elem(esw->dev, 0, &esw->qos.root_tsar_ix);
++ err = esw_qos_create_node_sched_elem(esw->dev, 0, 0, 0,
++ &esw->qos.root_tsar_ix);
+ if (err) {
+ esw_warn(dev, "E-Switch create root TSAR failed (%d)\n", err);
+ return err;
+--
+2.39.5
+
--- /dev/null
+From a1db918b63c891afe350c9fc7c6d09ae46061fc0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 9 Feb 2025 12:17:16 +0200
+Subject: net/mlx5: XDP, Enable TX side XDP multi-buffer support
+
+From: Alexei Lazar <alazar@nvidia.com>
+
+[ Upstream commit 1a9304859b3a4119579524c293b902a8927180f3 ]
+
+In XDP scenarios, fragmented packets can occur if the MTU is larger
+than the page size, even when the packet size fits within the linear
+part.
+If XDP multi-buffer support is disabled, the fragmented part won't be
+handled in the TX flow, leading to packet drops.
+
+Since XDP multi-buffer support is always available, this commit removes
+the conditional check for enabling it.
+This ensures that XDP multi-buffer support is always enabled,
+regardless of the `is_xdp_mb` parameter, and guarantees the handling of
+fragmented packets in such scenarios.
+
+Signed-off-by: Alexei Lazar <alazar@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/20250209101716.112774-16-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mellanox/mlx5/core/en.h | 1 -
+ .../ethernet/mellanox/mlx5/core/en/params.c | 1 -
+ .../ethernet/mellanox/mlx5/core/en/params.h | 1 -
+ .../mellanox/mlx5/core/en/reporter_tx.c | 1 -
+ .../net/ethernet/mellanox/mlx5/core/en/xdp.c | 49 ++++++++-----------
+ .../net/ethernet/mellanox/mlx5/core/en_main.c | 29 -----------
+ 6 files changed, 21 insertions(+), 61 deletions(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h
+index 979fc56205e1f..8f9ec48ecc06d 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en.h
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h
+@@ -386,7 +386,6 @@ enum {
+ MLX5E_SQ_STATE_VLAN_NEED_L2_INLINE,
+ MLX5E_SQ_STATE_PENDING_XSK_TX,
+ MLX5E_SQ_STATE_PENDING_TLS_RX_RESYNC,
+- MLX5E_SQ_STATE_XDP_MULTIBUF,
+ MLX5E_NUM_SQ_STATES, /* Must be kept last */
+ };
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/params.c b/drivers/net/ethernet/mellanox/mlx5/core/en/params.c
+index 31eb99f09c63c..8c4d710e85675 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en/params.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/params.c
+@@ -1242,7 +1242,6 @@ void mlx5e_build_xdpsq_param(struct mlx5_core_dev *mdev,
+ mlx5e_build_sq_param_common(mdev, param);
+ MLX5_SET(wq, wq, log_wq_sz, params->log_sq_size);
+ param->is_mpw = MLX5E_GET_PFLAG(params, MLX5E_PFLAG_XDP_TX_MPWQE);
+- param->is_xdp_mb = !mlx5e_rx_is_linear_skb(mdev, params, xsk);
+ mlx5e_build_tx_cq_param(mdev, params, ¶m->cqp);
+ }
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/params.h b/drivers/net/ethernet/mellanox/mlx5/core/en/params.h
+index 3f8986f9d8629..bd5877acc5b1e 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en/params.h
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/params.h
+@@ -33,7 +33,6 @@ struct mlx5e_sq_param {
+ struct mlx5_wq_param wq;
+ bool is_mpw;
+ bool is_tls;
+- bool is_xdp_mb;
+ u16 stop_room;
+ };
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
+index c8adf309ecad0..dbd9482359e1e 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
+@@ -16,7 +16,6 @@ static const char * const sq_sw_state_type_name[] = {
+ [MLX5E_SQ_STATE_VLAN_NEED_L2_INLINE] = "vlan_need_l2_inline",
+ [MLX5E_SQ_STATE_PENDING_XSK_TX] = "pending_xsk_tx",
+ [MLX5E_SQ_STATE_PENDING_TLS_RX_RESYNC] = "pending_tls_rx_resync",
+- [MLX5E_SQ_STATE_XDP_MULTIBUF] = "xdp_multibuf",
+ };
+
+ static int mlx5e_wait_for_sq_flush(struct mlx5e_txqsq *sq)
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
+index 94b2916620873..7a6cc0f4002ea 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
+@@ -546,6 +546,7 @@ mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd,
+ bool inline_ok;
+ bool linear;
+ u16 pi;
++ int i;
+
+ struct mlx5e_xdpsq_stats *stats = sq->stats;
+
+@@ -612,41 +613,33 @@ mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd,
+
+ cseg->opmod_idx_opcode = cpu_to_be32((sq->pc << 8) | MLX5_OPCODE_SEND);
+
+- if (test_bit(MLX5E_SQ_STATE_XDP_MULTIBUF, &sq->state)) {
+- int i;
+-
+- memset(&cseg->trailer, 0, sizeof(cseg->trailer));
+- memset(eseg, 0, sizeof(*eseg) - sizeof(eseg->trailer));
+-
+- eseg->inline_hdr.sz = cpu_to_be16(inline_hdr_sz);
++ memset(&cseg->trailer, 0, sizeof(cseg->trailer));
++ memset(eseg, 0, sizeof(*eseg) - sizeof(eseg->trailer));
+
+- for (i = 0; i < num_frags; i++) {
+- skb_frag_t *frag = &xdptxdf->sinfo->frags[i];
+- dma_addr_t addr;
++ eseg->inline_hdr.sz = cpu_to_be16(inline_hdr_sz);
+
+- addr = xdptxdf->dma_arr ? xdptxdf->dma_arr[i] :
+- page_pool_get_dma_addr(skb_frag_page(frag)) +
+- skb_frag_off(frag);
++ for (i = 0; i < num_frags; i++) {
++ skb_frag_t *frag = &xdptxdf->sinfo->frags[i];
++ dma_addr_t addr;
+
+- dseg->addr = cpu_to_be64(addr);
+- dseg->byte_count = cpu_to_be32(skb_frag_size(frag));
+- dseg->lkey = sq->mkey_be;
+- dseg++;
+- }
++ addr = xdptxdf->dma_arr ? xdptxdf->dma_arr[i] :
++ page_pool_get_dma_addr(skb_frag_page(frag)) +
++ skb_frag_off(frag);
+
+- cseg->qpn_ds = cpu_to_be32((sq->sqn << 8) | ds_cnt);
++ dseg->addr = cpu_to_be64(addr);
++ dseg->byte_count = cpu_to_be32(skb_frag_size(frag));
++ dseg->lkey = sq->mkey_be;
++ dseg++;
++ }
+
+- sq->db.wqe_info[pi] = (struct mlx5e_xdp_wqe_info) {
+- .num_wqebbs = num_wqebbs,
+- .num_pkts = 1,
+- };
++ cseg->qpn_ds = cpu_to_be32((sq->sqn << 8) | ds_cnt);
+
+- sq->pc += num_wqebbs;
+- } else {
+- cseg->fm_ce_se = 0;
++ sq->db.wqe_info[pi] = (struct mlx5e_xdp_wqe_info) {
++ .num_wqebbs = num_wqebbs,
++ .num_pkts = 1,
++ };
+
+- sq->pc++;
+- }
++ sq->pc += num_wqebbs;
+
+ xsk_tx_metadata_request(meta, &mlx5e_xsk_tx_metadata_ops, eseg);
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+index 5c5168bdacb90..b0748e46b1ac4 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+@@ -2023,41 +2023,12 @@ int mlx5e_open_xdpsq(struct mlx5e_channel *c, struct mlx5e_params *params,
+ csp.min_inline_mode = sq->min_inline_mode;
+ set_bit(MLX5E_SQ_STATE_ENABLED, &sq->state);
+
+- if (param->is_xdp_mb)
+- set_bit(MLX5E_SQ_STATE_XDP_MULTIBUF, &sq->state);
+-
+ err = mlx5e_create_sq_rdy(c->mdev, param, &csp, 0, &sq->sqn);
+ if (err)
+ goto err_free_xdpsq;
+
+ mlx5e_set_xmit_fp(sq, param->is_mpw);
+
+- if (!param->is_mpw && !test_bit(MLX5E_SQ_STATE_XDP_MULTIBUF, &sq->state)) {
+- unsigned int ds_cnt = MLX5E_TX_WQE_EMPTY_DS_COUNT + 1;
+- unsigned int inline_hdr_sz = 0;
+- int i;
+-
+- if (sq->min_inline_mode != MLX5_INLINE_MODE_NONE) {
+- inline_hdr_sz = MLX5E_XDP_MIN_INLINE;
+- ds_cnt++;
+- }
+-
+- /* Pre initialize fixed WQE fields */
+- for (i = 0; i < mlx5_wq_cyc_get_size(&sq->wq); i++) {
+- struct mlx5e_tx_wqe *wqe = mlx5_wq_cyc_get_wqe(&sq->wq, i);
+- struct mlx5_wqe_ctrl_seg *cseg = &wqe->ctrl;
+- struct mlx5_wqe_eth_seg *eseg = &wqe->eth;
+-
+- sq->db.wqe_info[i] = (struct mlx5e_xdp_wqe_info) {
+- .num_wqebbs = 1,
+- .num_pkts = 1,
+- };
+-
+- cseg->qpn_ds = cpu_to_be32((sq->sqn << 8) | ds_cnt);
+- eseg->inline_hdr.sz = cpu_to_be16(inline_hdr_sz);
+- }
+- }
+-
+ return 0;
+
+ err_free_xdpsq:
+--
+2.39.5
+
--- /dev/null
+From 984b87e77bc29631de3bf705d750dd1f257db26b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 20 Feb 2025 23:39:53 +0200
+Subject: net/mlx5e: Add correct match to check IPSec syndromes for switchdev
+ mode
+
+From: Jianbo Liu <jianbol@nvidia.com>
+
+[ Upstream commit 85e4a808af2545fefaf18c8fe50071b06fcbdabc ]
+
+In commit dddb49b63d86 ("net/mlx5e: Add IPsec and ASO syndromes check
+in HW"), IPSec and ASO syndromes checks after decryption for the
+specified ASO object were added. But they are correct only for eswith
+in legacy mode. For switchdev mode, metadata register c1 is used to
+save the mapped id (not ASO object id). So, need to change the match
+accordingly for the check rules in status table.
+
+Signed-off-by: Jianbo Liu <jianbol@nvidia.com>
+Reviewed-by: Leon Romanovsky <leonro@nvidia.com>
+Reviewed-by: Patrisious Haddad <phaddad@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/20250220213959.504304-4-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../mellanox/mlx5/core/en_accel/ipsec_fs.c | 28 ++++++++++++++-----
+ .../mellanox/mlx5/core/esw/ipsec_fs.c | 13 +++++++++
+ .../mellanox/mlx5/core/esw/ipsec_fs.h | 5 ++++
+ include/linux/mlx5/eswitch.h | 2 ++
+ 4 files changed, 41 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c
+index e7b64679f1219..3cf44fbdf5ee6 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c
+@@ -165,6 +165,25 @@ static void ipsec_rx_status_pass_destroy(struct mlx5e_ipsec *ipsec,
+ #endif
+ }
+
++static void ipsec_rx_rule_add_match_obj(struct mlx5e_ipsec_sa_entry *sa_entry,
++ struct mlx5e_ipsec_rx *rx,
++ struct mlx5_flow_spec *spec)
++{
++ struct mlx5e_ipsec *ipsec = sa_entry->ipsec;
++
++ if (rx == ipsec->rx_esw) {
++ mlx5_esw_ipsec_rx_rule_add_match_obj(sa_entry, spec);
++ } else {
++ MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
++ misc_parameters_2.metadata_reg_c_2);
++ MLX5_SET(fte_match_param, spec->match_value,
++ misc_parameters_2.metadata_reg_c_2,
++ sa_entry->ipsec_obj_id | BIT(31));
++
++ spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_2;
++ }
++}
++
+ static int rx_add_rule_drop_auth_trailer(struct mlx5e_ipsec_sa_entry *sa_entry,
+ struct mlx5e_ipsec_rx *rx)
+ {
+@@ -200,11 +219,8 @@ static int rx_add_rule_drop_auth_trailer(struct mlx5e_ipsec_sa_entry *sa_entry,
+
+ MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, misc_parameters_2.ipsec_syndrome);
+ MLX5_SET(fte_match_param, spec->match_value, misc_parameters_2.ipsec_syndrome, 1);
+- MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, misc_parameters_2.metadata_reg_c_2);
+- MLX5_SET(fte_match_param, spec->match_value,
+- misc_parameters_2.metadata_reg_c_2,
+- sa_entry->ipsec_obj_id | BIT(31));
+ spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS_2;
++ ipsec_rx_rule_add_match_obj(sa_entry, rx, spec);
+ rule = mlx5_add_flow_rules(ft, spec, &flow_act, &dest, 1);
+ if (IS_ERR(rule)) {
+ err = PTR_ERR(rule);
+@@ -281,10 +297,8 @@ static int rx_add_rule_drop_replay(struct mlx5e_ipsec_sa_entry *sa_entry, struct
+
+ MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, misc_parameters_2.metadata_reg_c_4);
+ MLX5_SET(fte_match_param, spec->match_value, misc_parameters_2.metadata_reg_c_4, 1);
+- MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, misc_parameters_2.metadata_reg_c_2);
+- MLX5_SET(fte_match_param, spec->match_value, misc_parameters_2.metadata_reg_c_2,
+- sa_entry->ipsec_obj_id | BIT(31));
+ spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS_2;
++ ipsec_rx_rule_add_match_obj(sa_entry, rx, spec);
+ rule = mlx5_add_flow_rules(ft, spec, &flow_act, &dest, 1);
+ if (IS_ERR(rule)) {
+ err = PTR_ERR(rule);
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/ipsec_fs.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/ipsec_fs.c
+index ed977ae75fab8..4bba2884c1c05 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/esw/ipsec_fs.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/ipsec_fs.c
+@@ -85,6 +85,19 @@ int mlx5_esw_ipsec_rx_setup_modify_header(struct mlx5e_ipsec_sa_entry *sa_entry,
+ return err;
+ }
+
++void mlx5_esw_ipsec_rx_rule_add_match_obj(struct mlx5e_ipsec_sa_entry *sa_entry,
++ struct mlx5_flow_spec *spec)
++{
++ MLX5_SET(fte_match_param, spec->match_criteria,
++ misc_parameters_2.metadata_reg_c_1,
++ ESW_IPSEC_RX_MAPPED_ID_MATCH_MASK);
++ MLX5_SET(fte_match_param, spec->match_value,
++ misc_parameters_2.metadata_reg_c_1,
++ sa_entry->rx_mapped_id << ESW_ZONE_ID_BITS);
++
++ spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_2;
++}
++
+ void mlx5_esw_ipsec_rx_id_mapping_remove(struct mlx5e_ipsec_sa_entry *sa_entry)
+ {
+ struct mlx5e_ipsec *ipsec = sa_entry->ipsec;
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/ipsec_fs.h b/drivers/net/ethernet/mellanox/mlx5/core/esw/ipsec_fs.h
+index ac9c65b89166e..514c15258b1d1 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/esw/ipsec_fs.h
++++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/ipsec_fs.h
+@@ -20,6 +20,8 @@ int mlx5_esw_ipsec_rx_ipsec_obj_id_search(struct mlx5e_priv *priv, u32 id,
+ void mlx5_esw_ipsec_tx_create_attr_set(struct mlx5e_ipsec *ipsec,
+ struct mlx5e_ipsec_tx_create_attr *attr);
+ void mlx5_esw_ipsec_restore_dest_uplink(struct mlx5_core_dev *mdev);
++void mlx5_esw_ipsec_rx_rule_add_match_obj(struct mlx5e_ipsec_sa_entry *sa_entry,
++ struct mlx5_flow_spec *spec);
+ #else
+ static inline void mlx5_esw_ipsec_rx_create_attr_set(struct mlx5e_ipsec *ipsec,
+ struct mlx5e_ipsec_rx_create_attr *attr) {}
+@@ -48,5 +50,8 @@ static inline void mlx5_esw_ipsec_tx_create_attr_set(struct mlx5e_ipsec *ipsec,
+ struct mlx5e_ipsec_tx_create_attr *attr) {}
+
+ static inline void mlx5_esw_ipsec_restore_dest_uplink(struct mlx5_core_dev *mdev) {}
++static inline void
++mlx5_esw_ipsec_rx_rule_add_match_obj(struct mlx5e_ipsec_sa_entry *sa_entry,
++ struct mlx5_flow_spec *spec) {}
+ #endif /* CONFIG_MLX5_ESWITCH */
+ #endif /* __MLX5_ESW_IPSEC_FS_H__ */
+diff --git a/include/linux/mlx5/eswitch.h b/include/linux/mlx5/eswitch.h
+index df73a2ccc9af3..67256e776566c 100644
+--- a/include/linux/mlx5/eswitch.h
++++ b/include/linux/mlx5/eswitch.h
+@@ -147,6 +147,8 @@ u32 mlx5_eswitch_get_vport_metadata_for_set(struct mlx5_eswitch *esw,
+
+ /* reuse tun_opts for the mapped ipsec obj id when tun_id is 0 (invalid) */
+ #define ESW_IPSEC_RX_MAPPED_ID_MASK GENMASK(ESW_TUN_OPTS_BITS - 1, 0)
++#define ESW_IPSEC_RX_MAPPED_ID_MATCH_MASK \
++ GENMASK(31 - ESW_RESERVED_BITS, ESW_ZONE_ID_BITS)
+
+ u8 mlx5_eswitch_mode(const struct mlx5_core_dev *dev);
+ u16 mlx5_eswitch_get_total_vports(const struct mlx5_core_dev *dev);
+--
+2.39.5
+
--- /dev/null
+From 81be469372b609c2204aa87520afc63f6e11ee5b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Feb 2025 23:35:16 +0200
+Subject: net/mlx5e: Avoid WARN_ON when configuring MQPRIO with HTB offload
+ enabled
+
+From: Carolina Jubran <cjubran@nvidia.com>
+
+[ Upstream commit 689805dcc474c2accb5cffbbcea1c06ee4a54570 ]
+
+When attempting to enable MQPRIO while HTB offload is already
+configured, the driver currently returns `-EINVAL` and triggers a
+`WARN_ON`, leading to an unnecessary call trace.
+
+Update the code to handle this case more gracefully by returning
+`-EOPNOTSUPP` instead, while also providing a helpful user message.
+
+Signed-off-by: Carolina Jubran <cjubran@nvidia.com>
+Reviewed-by: Yael Chemla <ychemla@nvidia.com>
+Reviewed-by: Cosmin Ratiu <cratiu@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+index b0748e46b1ac4..ca56740f6d2f9 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+@@ -3787,8 +3787,11 @@ static int mlx5e_setup_tc_mqprio(struct mlx5e_priv *priv,
+ /* MQPRIO is another toplevel qdisc that can't be attached
+ * simultaneously with the offloaded HTB.
+ */
+- if (WARN_ON(mlx5e_selq_is_htb_enabled(&priv->selq)))
+- return -EINVAL;
++ if (mlx5e_selq_is_htb_enabled(&priv->selq)) {
++ NL_SET_ERR_MSG_MOD(mqprio->extack,
++ "MQPRIO cannot be configured when HTB offload is enabled.");
++ return -EOPNOTSUPP;
++ }
+
+ switch (mqprio->mode) {
+ case TC_MQPRIO_MODE_DCB:
+--
+2.39.5
+
--- /dev/null
+From 136415b75883fd2ee71b4950c752bc2e2800c0b1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 9 Feb 2025 12:17:08 +0200
+Subject: net/mlx5e: reduce rep rxq depth to 256 for ECPF
+
+From: William Tu <witu@nvidia.com>
+
+[ Upstream commit b9cc8f9d700867aaa77aedddfea85e53d5e5d584 ]
+
+By experiments, a single queue representor netdev consumes kernel
+memory around 2.8MB, and 1.8MB out of the 2.8MB is due to page
+pool for the RXQ. Scaling to a thousand representors consumes 2.8GB,
+which becomes a memory pressure issue for embedded devices such as
+BlueField-2 16GB / BlueField-3 32GB memory.
+
+Since representor netdevs mostly handles miss traffic, and ideally,
+most of the traffic will be offloaded, reduce the default non-uplink
+rep netdev's RXQ default depth from 1024 to 256 if mdev is ecpf eswitch
+manager. This saves around 1MB of memory per regular RQ,
+(1024 - 256) * 2KB, allocated from page pool.
+
+With rxq depth of 256, the netlink page pool tool reports
+$./tools/net/ynl/cli.py --spec Documentation/netlink/specs/netdev.yaml \
+ --dump page-pool-get
+ {'id': 277,
+ 'ifindex': 9,
+ 'inflight': 128,
+ 'inflight-mem': 786432,
+ 'napi-id': 775}]
+
+This is due to mtu 1500 + headroom consumes half pages, so 256 rxq
+entries consumes around 128 pages (thus create a page pool with
+size 128), shown above at inflight.
+
+Note that each netdev has multiple types of RQs, including
+Regular RQ, XSK, PTP, Drop, Trap RQ. Since non-uplink representor
+only supports regular rq, this patch only changes the regular RQ's
+default depth.
+
+Signed-off-by: William Tu <witu@nvidia.com>
+Reviewed-by: Bodong Wang <bodong@nvidia.com>
+Reviewed-by: Saeed Mahameed <saeedm@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Reviewed-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
+Link: https://patch.msgid.link/20250209101716.112774-8-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
+index 6667ec26e079b..07f38f472a279 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
+@@ -65,6 +65,7 @@
+ #define MLX5E_REP_PARAMS_DEF_LOG_SQ_SIZE \
+ max(0x7, MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE)
+ #define MLX5E_REP_PARAMS_DEF_NUM_CHANNELS 1
++#define MLX5E_REP_PARAMS_DEF_LOG_RQ_SIZE 0x8
+
+ static const char mlx5e_rep_driver_name[] = "mlx5e_rep";
+
+@@ -855,6 +856,8 @@ static void mlx5e_build_rep_params(struct net_device *netdev)
+
+ /* RQ */
+ mlx5e_build_rq_params(mdev, params);
++ if (!mlx5e_is_uplink_rep(priv) && mlx5_core_is_ecpf(mdev))
++ params->log_rq_mtu_frames = MLX5E_REP_PARAMS_DEF_LOG_RQ_SIZE;
+
+ /* If netdev is already registered (e.g. move from nic profile to uplink,
+ * RTNL lock must be held before triggering netdev notifiers.
+--
+2.39.5
+
--- /dev/null
+From 520fb38905a8e646a6abf84c0ae7e32000499b08 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 9 Feb 2025 12:17:07 +0200
+Subject: net/mlx5e: reduce the max log mpwrq sz for ECPF and reps
+
+From: William Tu <witu@nvidia.com>
+
+[ Upstream commit e1d68ea58c7e9ebacd9ad7a99b25a3578fa62182 ]
+
+For the ECPF and representors, reduce the max MPWRQ size from 256KB (18)
+to 128KB (17). This prepares the later patch for saving representor
+memory.
+
+With Striding RQ, there is a minimum of 4 MPWQEs. So with 128KB of max
+MPWRQ size, the minimal memory is 4 * 128KB = 512KB. When creating page
+pool, consider 1500 mtu, the minimal page pool size will be 512KB/4KB =
+128 pages = 256 rx ring entries (2 entries per page).
+
+Before this patch, setting RX ringsize (ethtool -G rx) to 256 causes
+driver to allocate page pool size more than it needs due to max MPWRQ
+is 256KB (18). Ex: 4 * 256KB = 1MB, 1MB/4KB = 256 pages, but actually
+128 pages is good enough. Reducing the max MPWRQ to 128KB fixes the
+limitation.
+
+Signed-off-by: William Tu <witu@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Reviewed-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
+Link: https://patch.msgid.link/20250209101716.112774-7-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mellanox/mlx5/core/en.h | 2 --
+ .../net/ethernet/mellanox/mlx5/core/en/params.c | 15 +++++++++++----
+ 2 files changed, 11 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h
+index 8f9ec48ecc06d..769e683f24883 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en.h
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h
+@@ -95,8 +95,6 @@ struct page_pool;
+ #define MLX5_MPWRQ_DEF_LOG_STRIDE_SZ(mdev) \
+ MLX5_MPWRQ_LOG_STRIDE_SZ(mdev, order_base_2(MLX5E_RX_MAX_HEAD))
+
+-#define MLX5_MPWRQ_MAX_LOG_WQE_SZ 18
+-
+ /* Keep in sync with mlx5e_mpwrq_log_wqe_sz.
+ * These are theoretical maximums, which can be further restricted by
+ * capabilities. These values are used for static resource allocations and
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/params.c b/drivers/net/ethernet/mellanox/mlx5/core/en/params.c
+index 8c4d710e85675..58ec5e44aa7ad 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en/params.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/params.c
+@@ -10,6 +10,9 @@
+ #include <net/page_pool/types.h>
+ #include <net/xdp_sock_drv.h>
+
++#define MLX5_MPWRQ_MAX_LOG_WQE_SZ 18
++#define MLX5_REP_MPWRQ_MAX_LOG_WQE_SZ 17
++
+ static u8 mlx5e_mpwrq_min_page_shift(struct mlx5_core_dev *mdev)
+ {
+ u8 min_page_shift = MLX5_CAP_GEN_2(mdev, log_min_mkey_entity_size);
+@@ -103,18 +106,22 @@ u8 mlx5e_mpwrq_log_wqe_sz(struct mlx5_core_dev *mdev, u8 page_shift,
+ enum mlx5e_mpwrq_umr_mode umr_mode)
+ {
+ u8 umr_entry_size = mlx5e_mpwrq_umr_entry_size(umr_mode);
+- u8 max_pages_per_wqe, max_log_mpwqe_size;
++ u8 max_pages_per_wqe, max_log_wqe_size_calc;
++ u8 max_log_wqe_size_cap;
+ u16 max_wqe_size;
+
+ /* Keep in sync with MLX5_MPWRQ_MAX_PAGES_PER_WQE. */
+ max_wqe_size = mlx5e_get_max_sq_aligned_wqebbs(mdev) * MLX5_SEND_WQE_BB;
+ max_pages_per_wqe = ALIGN_DOWN(max_wqe_size - sizeof(struct mlx5e_umr_wqe),
+ MLX5_UMR_FLEX_ALIGNMENT) / umr_entry_size;
+- max_log_mpwqe_size = ilog2(max_pages_per_wqe) + page_shift;
++ max_log_wqe_size_calc = ilog2(max_pages_per_wqe) + page_shift;
++
++ WARN_ON_ONCE(max_log_wqe_size_calc < MLX5E_ORDER2_MAX_PACKET_MTU);
+
+- WARN_ON_ONCE(max_log_mpwqe_size < MLX5E_ORDER2_MAX_PACKET_MTU);
++ max_log_wqe_size_cap = mlx5_core_is_ecpf(mdev) ?
++ MLX5_REP_MPWRQ_MAX_LOG_WQE_SZ : MLX5_MPWRQ_MAX_LOG_WQE_SZ;
+
+- return min_t(u8, max_log_mpwqe_size, MLX5_MPWRQ_MAX_LOG_WQE_SZ);
++ return min_t(u8, max_log_wqe_size_calc, max_log_wqe_size_cap);
+ }
+
+ u8 mlx5e_mpwrq_pages_per_wqe(struct mlx5_core_dev *mdev, u8 page_shift,
+--
+2.39.5
+
--- /dev/null
+From 48303af4e778c6afef9da761f76969baa5635f77 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 9 Feb 2025 12:17:09 +0200
+Subject: net/mlx5e: set the tx_queue_len for pfifo_fast
+
+From: William Tu <witu@nvidia.com>
+
+[ Upstream commit a38cc5706fb9f7dc4ee3a443f61de13ce1e410ed ]
+
+By default, the mq netdev creates a pfifo_fast qdisc. On a
+system with 16 core, the pfifo_fast with 3 bands consumes
+16 * 3 * 8 (size of pointer) * 1024 (default tx queue len)
+= 393KB. The patch sets the tx qlen to representor default
+value, 128 (1<<MLX5E_REP_PARAMS_DEF_LOG_SQ_SIZE), which
+consumes 16 * 3 * 8 * 128 = 49KB, saving 344KB for each
+representor at ECPF.
+
+Signed-off-by: William Tu <witu@nvidia.com>
+Reviewed-by: Daniel Jurgens <danielj@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Reviewed-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
+Link: https://patch.msgid.link/20250209101716.112774-9-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
+index fdff9fd8a89ec..6667ec26e079b 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
+@@ -886,6 +886,8 @@ static void mlx5e_build_rep_netdev(struct net_device *netdev,
+ netdev->ethtool_ops = &mlx5e_rep_ethtool_ops;
+
+ netdev->watchdog_timeo = 15 * HZ;
++ if (mlx5_core_is_ecpf(mdev))
++ netdev->tx_queue_len = 1 << MLX5E_REP_PARAMS_DEF_LOG_SQ_SIZE;
+
+ #if IS_ENABLED(CONFIG_MLX5_CLS_ACT)
+ netdev->hw_features |= NETIF_F_HW_TC;
+--
+2.39.5
+
--- /dev/null
+From e2a0adfa0868fc06ac92ec364d80d72fa142efe0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 19 Mar 2025 21:23:18 +0200
+Subject: net/mlx5e: Use right API to free bitmap memory
+
+From: Mark Zhang <markzhang@nvidia.com>
+
+[ Upstream commit cac48eb6d383ee4f037e320608efa5dec029e26a ]
+
+Use bitmap_free() to free memory allocated with bitmap_zalloc_node().
+This fixes memtrack error:
+ mtl rsc inconsistency: memtrack_free: .../drivers/net/ethernet/mellanox/mlx5/core/en_main.c::466: kfree for unknown address=0xFFFF0000CA3619E8, device=0x0
+
+Signed-off-by: Mark Zhang <markzhang@nvidia.com>
+Reviewed-by: Maher Sanalla <msanalla@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
+Link: https://patch.msgid.link/1742412199-159596-3-git-send-email-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+index 01f6a60308cb7..5c5168bdacb90 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+@@ -359,7 +359,7 @@ static int mlx5e_rq_shampo_hd_info_alloc(struct mlx5e_rq *rq, int node)
+ return 0;
+
+ err_nomem:
+- kvfree(shampo->bitmap);
++ bitmap_free(shampo->bitmap);
+ kvfree(shampo->pages);
+
+ return -ENOMEM;
+@@ -367,7 +367,7 @@ static int mlx5e_rq_shampo_hd_info_alloc(struct mlx5e_rq *rq, int node)
+
+ static void mlx5e_rq_shampo_hd_info_free(struct mlx5e_rq *rq)
+ {
+- kvfree(rq->mpwqe.shampo->bitmap);
++ bitmap_free(rq->mpwqe.shampo->bitmap);
+ kvfree(rq->mpwqe.shampo->pages);
+ }
+
+--
+2.39.5
+
--- /dev/null
+From 88e115fd81bf2c9243f959067c3fa20a1934296d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Feb 2025 14:56:37 -0800
+Subject: net: page_pool: avoid false positive warning if NAPI was never added
+
+From: Jakub Kicinski <kuba@kernel.org>
+
+[ Upstream commit c1e00bc4be06cacee6307cedb9b55bbaddb5044d ]
+
+We expect NAPI to be in disabled state when page pool is torn down.
+But it is also legal if the NAPI is completely uninitialized.
+
+Reviewed-by: Mina Almasry <almasrymina@google.com>
+Link: https://patch.msgid.link/20250206225638.1387810-4-kuba@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/core/dev.h | 12 ++++++++++++
+ net/core/page_pool.c | 7 ++-----
+ 2 files changed, 14 insertions(+), 5 deletions(-)
+
+diff --git a/net/core/dev.h b/net/core/dev.h
+index a5b166bbd169a..caa13e431a6bc 100644
+--- a/net/core/dev.h
++++ b/net/core/dev.h
+@@ -299,6 +299,18 @@ void xdp_do_check_flushed(struct napi_struct *napi);
+ static inline void xdp_do_check_flushed(struct napi_struct *napi) { }
+ #endif
+
++/* Best effort check that NAPI is not idle (can't be scheduled to run) */
++static inline void napi_assert_will_not_race(const struct napi_struct *napi)
++{
++ /* uninitialized instance, can't race */
++ if (!napi->poll_list.next)
++ return;
++
++ /* SCHED bit is set on disabled instances */
++ WARN_ON(!test_bit(NAPI_STATE_SCHED, &napi->state));
++ WARN_ON(READ_ONCE(napi->list_owner) != -1);
++}
++
+ void kick_defer_list_purge(struct softnet_data *sd, unsigned int cpu);
+
+ #define XMIT_RECURSION_LIMIT 8
+diff --git a/net/core/page_pool.c b/net/core/page_pool.c
+index ede82c610936e..cca51aa2e876f 100644
+--- a/net/core/page_pool.c
++++ b/net/core/page_pool.c
+@@ -25,6 +25,7 @@
+
+ #include <trace/events/page_pool.h>
+
++#include "dev.h"
+ #include "mp_dmabuf_devmem.h"
+ #include "netmem_priv.h"
+ #include "page_pool_priv.h"
+@@ -1146,11 +1147,7 @@ void page_pool_disable_direct_recycling(struct page_pool *pool)
+ if (!pool->p.napi)
+ return;
+
+- /* To avoid races with recycling and additional barriers make sure
+- * pool and NAPI are unlinked when NAPI is disabled.
+- */
+- WARN_ON(!test_bit(NAPI_STATE_SCHED, &pool->p.napi->state));
+- WARN_ON(READ_ONCE(pool->p.napi->list_owner) != -1);
++ napi_assert_will_not_race(pool->p.napi);
+
+ mutex_lock(&page_pools_lock);
+ WRITE_ONCE(pool->p.napi, NULL);
+--
+2.39.5
+
--- /dev/null
+From 380e3cc8821631c385db6d35ecb6769fd8d99c70 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 28 Feb 2025 17:43:19 +0200
+Subject: net: phy: nxp-c45-tja11xx: add match_phy_device to TJA1103/TJA1104
+
+From: Andrei Botila <andrei.botila@oss.nxp.com>
+
+[ Upstream commit a06a868a0cd96bc51401cdea897313a3f6ad01a0 ]
+
+Add .match_phy_device for the existing TJAs to differentiate between
+TJA1103 and TJA1104.
+TJA1103 and TJA1104 share the same PHY_ID but TJA1104 has MACsec
+capabilities while TJA1103 doesn't.
+
+Signed-off-by: Andrei Botila <andrei.botila@oss.nxp.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Link: https://patch.msgid.link/20250228154320.2979000-2-andrei.botila@oss.nxp.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/phy/nxp-c45-tja11xx.c | 54 +++++++++++++++++++++++++++++--
+ 1 file changed, 52 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/phy/nxp-c45-tja11xx.c b/drivers/net/phy/nxp-c45-tja11xx.c
+index e9fc54517449c..16e1c13ae2f8d 100644
+--- a/drivers/net/phy/nxp-c45-tja11xx.c
++++ b/drivers/net/phy/nxp-c45-tja11xx.c
+@@ -1,6 +1,6 @@
+ // SPDX-License-Identifier: GPL-2.0
+ /* NXP C45 PHY driver
+- * Copyright 2021-2023 NXP
++ * Copyright 2021-2025 NXP
+ * Author: Radu Pirea <radu-nicolae.pirea@oss.nxp.com>
+ */
+
+@@ -19,6 +19,8 @@
+
+ #include "nxp-c45-tja11xx.h"
+
++#define PHY_ID_MASK GENMASK(31, 4)
++/* Same id: TJA1103, TJA1104 */
+ #define PHY_ID_TJA_1103 0x001BB010
+ #define PHY_ID_TJA_1120 0x001BB031
+
+@@ -1956,6 +1958,30 @@ static void tja1120_nmi_handler(struct phy_device *phydev,
+ }
+ }
+
++static int nxp_c45_macsec_ability(struct phy_device *phydev)
++{
++ bool macsec_ability;
++ int phy_abilities;
++
++ phy_abilities = phy_read_mmd(phydev, MDIO_MMD_VEND1,
++ VEND1_PORT_ABILITIES);
++ macsec_ability = !!(phy_abilities & MACSEC_ABILITY);
++
++ return macsec_ability;
++}
++
++static int tja1103_match_phy_device(struct phy_device *phydev)
++{
++ return phy_id_compare(phydev->phy_id, PHY_ID_TJA_1103, PHY_ID_MASK) &&
++ !nxp_c45_macsec_ability(phydev);
++}
++
++static int tja1104_match_phy_device(struct phy_device *phydev)
++{
++ return phy_id_compare(phydev->phy_id, PHY_ID_TJA_1103, PHY_ID_MASK) &&
++ nxp_c45_macsec_ability(phydev);
++}
++
+ static const struct nxp_c45_regmap tja1120_regmap = {
+ .vend1_ptp_clk_period = 0x1020,
+ .vend1_event_msg_filt = 0x9010,
+@@ -2026,7 +2052,6 @@ static const struct nxp_c45_phy_data tja1120_phy_data = {
+
+ static struct phy_driver nxp_c45_driver[] = {
+ {
+- PHY_ID_MATCH_MODEL(PHY_ID_TJA_1103),
+ .name = "NXP C45 TJA1103",
+ .get_features = nxp_c45_get_features,
+ .driver_data = &tja1103_phy_data,
+@@ -2048,6 +2073,31 @@ static struct phy_driver nxp_c45_driver[] = {
+ .get_sqi = nxp_c45_get_sqi,
+ .get_sqi_max = nxp_c45_get_sqi_max,
+ .remove = nxp_c45_remove,
++ .match_phy_device = tja1103_match_phy_device,
++ },
++ {
++ .name = "NXP C45 TJA1104",
++ .get_features = nxp_c45_get_features,
++ .driver_data = &tja1103_phy_data,
++ .probe = nxp_c45_probe,
++ .soft_reset = nxp_c45_soft_reset,
++ .config_aneg = genphy_c45_config_aneg,
++ .config_init = nxp_c45_config_init,
++ .config_intr = tja1103_config_intr,
++ .handle_interrupt = nxp_c45_handle_interrupt,
++ .read_status = genphy_c45_read_status,
++ .suspend = genphy_c45_pma_suspend,
++ .resume = genphy_c45_pma_resume,
++ .get_sset_count = nxp_c45_get_sset_count,
++ .get_strings = nxp_c45_get_strings,
++ .get_stats = nxp_c45_get_stats,
++ .cable_test_start = nxp_c45_cable_test_start,
++ .cable_test_get_status = nxp_c45_cable_test_get_status,
++ .set_loopback = genphy_c45_loopback,
++ .get_sqi = nxp_c45_get_sqi,
++ .get_sqi_max = nxp_c45_get_sqi_max,
++ .remove = nxp_c45_remove,
++ .match_phy_device = tja1104_match_phy_device,
+ },
+ {
+ PHY_ID_MATCH_MODEL(PHY_ID_TJA_1120),
+--
+2.39.5
+
--- /dev/null
+From dafdfabb39ba3801a53e173db7f7043177b9ffdb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Feb 2025 20:15:17 +0800
+Subject: net: phylink: use pl->link_interface in phylink_expects_phy()
+
+From: Choong Yong Liang <yong.liang.choong@linux.intel.com>
+
+[ Upstream commit b63263555eaafbf9ab1a82f2020bbee872d83759 ]
+
+The phylink_expects_phy() function allows MAC drivers to check if they are
+expecting a PHY to attach. The checking condition in phylink_expects_phy()
+aims to achieve the same result as the checking condition in
+phylink_attach_phy().
+
+However, the checking condition in phylink_expects_phy() uses
+pl->link_config.interface, while phylink_attach_phy() uses
+pl->link_interface.
+
+Initially, both pl->link_interface and pl->link_config.interface are set
+to SGMII, and pl->cfg_link_an_mode is set to MLO_AN_INBAND.
+
+When the interface switches from SGMII to 2500BASE-X,
+pl->link_config.interface is updated by phylink_major_config().
+At this point, pl->cfg_link_an_mode remains MLO_AN_INBAND, and
+pl->link_config.interface is set to 2500BASE-X.
+Subsequently, when the STMMAC interface is taken down
+administratively and brought back up, it is blocked by
+phylink_expects_phy().
+
+Since phylink_expects_phy() and phylink_attach_phy() aim to achieve the
+same result, phylink_expects_phy() should check pl->link_interface,
+which never changes, instead of pl->link_config.interface, which is
+updated by phylink_major_config().
+
+Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Signed-off-by: Choong Yong Liang <yong.liang.choong@linux.intel.com>
+Link: https://patch.msgid.link/20250227121522.1802832-2-yong.liang.choong@linux.intel.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/phy/phylink.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
+index 5be48eb810abb..8c4dfe9dc7650 100644
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -2074,7 +2074,7 @@ bool phylink_expects_phy(struct phylink *pl)
+ {
+ if (pl->cfg_link_an_mode == MLO_AN_FIXED ||
+ (pl->cfg_link_an_mode == MLO_AN_INBAND &&
+- phy_interface_mode_is_8023z(pl->link_config.interface)))
++ phy_interface_mode_is_8023z(pl->link_interface)))
+ return false;
+ return true;
+ }
+--
+2.39.5
+
--- /dev/null
+From ec49b24cc60acb617863681c81531cbee7910242 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 19 Feb 2025 09:45:27 +0100
+Subject: net: pktgen: fix access outside of user given buffer in
+ pktgen_thread_write()
+
+From: Peter Seiderer <ps.report@gmx.net>
+
+[ Upstream commit 425e64440ad0a2f03bdaf04be0ae53dededbaa77 ]
+
+Honour the user given buffer size for the strn_len() calls (otherwise
+strn_len() will access memory outside of the user given buffer).
+
+Signed-off-by: Peter Seiderer <ps.report@gmx.net>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20250219084527.20488-8-ps.report@gmx.net
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/core/pktgen.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/net/core/pktgen.c b/net/core/pktgen.c
+index 6ea34c95179f4..d3a76e81dd886 100644
+--- a/net/core/pktgen.c
++++ b/net/core/pktgen.c
+@@ -1898,8 +1898,8 @@ static ssize_t pktgen_thread_write(struct file *file,
+ i = len;
+
+ /* Read variable name */
+-
+- len = strn_len(&user_buffer[i], sizeof(name) - 1);
++ max = min(sizeof(name) - 1, count - i);
++ len = strn_len(&user_buffer[i], max);
+ if (len < 0)
+ return len;
+
+@@ -1929,7 +1929,8 @@ static ssize_t pktgen_thread_write(struct file *file,
+ if (!strcmp(name, "add_device")) {
+ char f[32];
+ memset(f, 0, 32);
+- len = strn_len(&user_buffer[i], sizeof(f) - 1);
++ max = min(sizeof(f) - 1, count - i);
++ len = strn_len(&user_buffer[i], max);
+ if (len < 0) {
+ ret = len;
+ goto out;
+--
+2.39.5
+
--- /dev/null
+From 16a7d534f34a0c3efb7bc04bc1a1aa1b5136a027 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Feb 2025 14:56:00 +0100
+Subject: net: pktgen: fix mpls maximum labels list parsing
+
+From: Peter Seiderer <ps.report@gmx.net>
+
+[ Upstream commit 2b15a0693f70d1e8119743ee89edbfb1271b3ea8 ]
+
+Fix mpls maximum labels list parsing up to MAX_MPLS_LABELS entries (instead
+of up to MAX_MPLS_LABELS - 1).
+
+Addresses the following:
+
+ $ echo "mpls 00000f00,00000f01,00000f02,00000f03,00000f04,00000f05,00000f06,00000f07,00000f08,00000f09,00000f0a,00000f0b,00000f0c,00000f0d,00000f0e,00000f0f" > /proc/net/pktgen/lo\@0
+ -bash: echo: write error: Argument list too long
+
+Signed-off-by: Peter Seiderer <ps.report@gmx.net>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/core/pktgen.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/net/core/pktgen.c b/net/core/pktgen.c
+index 82b6a2c3c141f..6ea34c95179f4 100644
+--- a/net/core/pktgen.c
++++ b/net/core/pktgen.c
+@@ -898,6 +898,10 @@ static ssize_t get_labels(const char __user *buffer, struct pktgen_dev *pkt_dev)
+ pkt_dev->nr_labels = 0;
+ do {
+ __u32 tmp;
++
++ if (n >= MAX_MPLS_LABELS)
++ return -E2BIG;
++
+ len = hex32_arg(&buffer[i], 8, &tmp);
+ if (len <= 0)
+ return len;
+@@ -909,8 +913,6 @@ static ssize_t get_labels(const char __user *buffer, struct pktgen_dev *pkt_dev)
+ return -EFAULT;
+ i++;
+ n++;
+- if (n >= MAX_MPLS_LABELS)
+- return -E2BIG;
+ } while (c == ',');
+
+ pkt_dev->nr_labels = n;
+--
+2.39.5
+
--- /dev/null
+From cbcdcb81b6ed3296cc78cf7750bb4fa244293937 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Mar 2025 20:43:04 +0800
+Subject: net/smc: use the correct ndev to find pnetid by pnetid table
+
+From: Guangguan Wang <guangguan.wang@linux.alibaba.com>
+
+[ Upstream commit bfc6c67ec2d64d0ca4e5cc3e1ac84298a10b8d62 ]
+
+When using smc_pnet in SMC, it will only search the pnetid in the
+base_ndev of the netdev hierarchy(both HW PNETID and User-defined
+sw pnetid). This may not work for some scenarios when using SMC in
+container on cloud environment.
+In container, there have choices of different container network,
+such as directly using host network, virtual network IPVLAN, veth,
+etc. Different choices of container network have different netdev
+hierarchy. Examples of netdev hierarchy show below. (eth0 and eth1
+in host below is the netdev directly related to the physical device).
+ _______________________________
+ | _________________ |
+ | |POD | |
+ | | | |
+ | | eth0_________ | |
+ | |____| |__| |
+ | | | |
+ | | | |
+ | eth1|base_ndev| eth0_______ |
+ | | | | RDMA ||
+ | host |_________| |_______||
+ ---------------------------------
+ netdev hierarchy if directly using host network
+ ________________________________
+ | _________________ |
+ | |POD __________ | |
+ | | |upper_ndev| | |
+ | |eth0|__________| | |
+ | |_______|_________| |
+ | |lower netdev |
+ | __|______ |
+ | eth1| | eth0_______ |
+ | |base_ndev| | RDMA ||
+ | host |_________| |_______||
+ ---------------------------------
+ netdev hierarchy if using IPVLAN
+ _______________________________
+ | _____________________ |
+ | |POD _________ | |
+ | | |base_ndev|| |
+ | |eth0(veth)|_________|| |
+ | |____________|________| |
+ | |pairs |
+ | _______|_ |
+ | | | eth0_______ |
+ | veth|base_ndev| | RDMA ||
+ | |_________| |_______||
+ | _________ |
+ | eth1|base_ndev| |
+ | host |_________| |
+ ---------------------------------
+ netdev hierarchy if using veth
+Due to some reasons, the eth1 in host is not RDMA attached netdevice,
+pnetid is needed to map the eth1(in host) with RDMA device so that POD
+can do SMC-R. Because the eth1(in host) is managed by CNI plugin(such
+as Terway, network management plugin in container environment), and in
+cloud environment the eth(in host) can dynamically be inserted by CNI
+when POD create and dynamically be removed by CNI when POD destroy and
+no POD related to the eth(in host) anymore. It is hard to config the
+pnetid to the eth1(in host). But it is easy to config the pnetid to the
+netdevice which can be seen in POD. When do SMC-R, both the container
+directly using host network and the container using veth network can
+successfully match the RDMA device, because the configured pnetid netdev
+is a base_ndev. But the container using IPVLAN can not successfully
+match the RDMA device and 0x03030000 fallback happens, because the
+configured pnetid netdev is not a base_ndev. Additionally, if config
+pnetid to the eth1(in host) also can not work for matching RDMA device
+when using veth network and doing SMC-R in POD.
+
+To resolve the problems list above, this patch extends to search user
+-defined sw pnetid in the clc handshake ndev when no pnetid can be found
+in the base_ndev, and the base_ndev take precedence over ndev for backward
+compatibility. This patch also can unify the pnetid setup of different
+network choices list above in container(Config user-defined sw pnetid in
+the netdevice can be seen in POD).
+
+Signed-off-by: Guangguan Wang <guangguan.wang@linux.alibaba.com>
+Reviewed-by: Wenjia Zhang <wenjia@linux.ibm.com>
+Reviewed-by: Halil Pasic <pasic@linux.ibm.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/smc/smc_pnet.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/net/smc/smc_pnet.c b/net/smc/smc_pnet.c
+index 716808f374a8d..b391c2ef463f2 100644
+--- a/net/smc/smc_pnet.c
++++ b/net/smc/smc_pnet.c
+@@ -1079,14 +1079,16 @@ static void smc_pnet_find_roce_by_pnetid(struct net_device *ndev,
+ struct smc_init_info *ini)
+ {
+ u8 ndev_pnetid[SMC_MAX_PNETID_LEN];
++ struct net_device *base_ndev;
+ struct net *net;
+
+- ndev = pnet_find_base_ndev(ndev);
++ base_ndev = pnet_find_base_ndev(ndev);
+ net = dev_net(ndev);
+- if (smc_pnetid_by_dev_port(ndev->dev.parent, ndev->dev_port,
++ if (smc_pnetid_by_dev_port(base_ndev->dev.parent, base_ndev->dev_port,
+ ndev_pnetid) &&
++ smc_pnet_find_ndev_pnetid_by_table(base_ndev, ndev_pnetid) &&
+ smc_pnet_find_ndev_pnetid_by_table(ndev, ndev_pnetid)) {
+- smc_pnet_find_rdma_dev(ndev, ini);
++ smc_pnet_find_rdma_dev(base_ndev, ini);
+ return; /* pnetid could not be determined */
+ }
+ _smc_pnet_find_roce_by_pnetid(ndev_pnetid, ini, NULL, net);
+--
+2.39.5
+
--- /dev/null
+From 91580649a46bd64ecebd715ec96da81348ed220a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 21 Feb 2025 14:18:18 +0900
+Subject: net: stmmac: Correct usage of maximum queue number macros
+
+From: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
+
+[ Upstream commit 352bc4513ec3907db71cb5674fb93a76fc341ca9 ]
+
+The maximum numbers of each Rx and Tx queues are defined by
+MTL_MAX_RX_QUEUES and MTL_MAX_TX_QUEUES respectively.
+
+There are some places where Rx and Tx are used in reverse. There is no
+issue when the Tx and Rx macros have the same value, but should correct
+usage of macros for maximum queue number to keep consistency and prevent
+unexpected mistakes.
+
+Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Reviewed-by: Huacai Chen <chenhuacai@kernel.org>
+Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
+Link: https://patch.msgid.link/20250221051818.4163678-1-hayashi.kunihiko@socionext.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/stmicro/stmmac/common.h | 4 ++--
+ drivers/net/ethernet/stmicro/stmmac/stmmac.h | 7 +++----
+ 2 files changed, 5 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
+index e25db747a81a5..c660eb933f24b 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/common.h
++++ b/drivers/net/ethernet/stmicro/stmmac/common.h
+@@ -101,8 +101,8 @@ struct stmmac_rxq_stats {
+ /* Updates on each CPU protected by not allowing nested irqs. */
+ struct stmmac_pcpu_stats {
+ struct u64_stats_sync syncp;
+- u64_stats_t rx_normal_irq_n[MTL_MAX_TX_QUEUES];
+- u64_stats_t tx_normal_irq_n[MTL_MAX_RX_QUEUES];
++ u64_stats_t rx_normal_irq_n[MTL_MAX_RX_QUEUES];
++ u64_stats_t tx_normal_irq_n[MTL_MAX_TX_QUEUES];
+ };
+
+ /* Extra statistic and debug information exposed by ethtool */
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+index f05cae103d836..dae279ee2c280 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+@@ -257,7 +257,7 @@ struct stmmac_priv {
+ /* Frequently used values are kept adjacent for cache effect */
+ u32 tx_coal_frames[MTL_MAX_TX_QUEUES];
+ u32 tx_coal_timer[MTL_MAX_TX_QUEUES];
+- u32 rx_coal_frames[MTL_MAX_TX_QUEUES];
++ u32 rx_coal_frames[MTL_MAX_RX_QUEUES];
+
+ int hwts_tx_en;
+ bool tx_path_in_lpi_mode;
+@@ -265,8 +265,7 @@ struct stmmac_priv {
+ int sph;
+ int sph_cap;
+ u32 sarc_type;
+-
+- u32 rx_riwt[MTL_MAX_TX_QUEUES];
++ u32 rx_riwt[MTL_MAX_RX_QUEUES];
+ int hwts_rx_en;
+
+ void __iomem *ioaddr;
+@@ -343,7 +342,7 @@ struct stmmac_priv {
+ char int_name_sfty[IFNAMSIZ + 10];
+ char int_name_sfty_ce[IFNAMSIZ + 10];
+ char int_name_sfty_ue[IFNAMSIZ + 10];
+- char int_name_rx_irq[MTL_MAX_TX_QUEUES][IFNAMSIZ + 14];
++ char int_name_rx_irq[MTL_MAX_RX_QUEUES][IFNAMSIZ + 14];
+ char int_name_tx_irq[MTL_MAX_TX_QUEUES][IFNAMSIZ + 18];
+
+ #ifdef CONFIG_DEBUG_FS
+--
+2.39.5
+
--- /dev/null
+From 3ab4f7a18b95085c7dfcd17f11867332fd3e768c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 10 Feb 2025 21:43:28 +0800
+Subject: net: stmmac: dwmac-loongson: Set correct {tx,rx}_fifo_size
+
+From: Huacai Chen <chenhuacai@loongson.cn>
+
+[ Upstream commit 8dbf0c7556454b52af91bae305ca71500c31495c ]
+
+Now for dwmac-loongson {tx,rx}_fifo_size are uninitialised, which means
+zero. This means dwmac-loongson doesn't support changing MTU because in
+stmmac_change_mtu() it requires the fifo size be no less than MTU. Thus,
+set the correct tx_fifo_size and rx_fifo_size for it (16KB multiplied by
+queue counts).
+
+Here {tx,rx}_fifo_size is initialised with the initial value (also the
+maximum value) of {tx,rx}_queues_to_use. So it will keep as 16KB if we
+don't change the queue count, and will be larger than 16KB if we change
+(decrease) the queue count. However stmmac_change_mtu() still work well
+with current logic (MTU cannot be larger than 16KB for stmmac).
+
+Note: the Fixes tag picked here is the oldest commit and key commit of
+the dwmac-loongson series "stmmac: Add Loongson platform support".
+
+Acked-by: Yanteng Si <si.yanteng@linux.dev>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Signed-off-by: Chong Qiao <qiaochong@loongson.cn>
+Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
+Link: https://patch.msgid.link/20250210134328.2755328-1-chenhuacai@loongson.cn
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c
+index ab7c2750c1042..702ea5a00b56d 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c
+@@ -590,6 +590,9 @@ static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id
+ if (ret)
+ goto err_disable_device;
+
++ plat->tx_fifo_size = SZ_16K * plat->tx_queues_to_use;
++ plat->rx_fifo_size = SZ_16K * plat->rx_queues_to_use;
++
+ if (dev_of_node(&pdev->dev))
+ ret = loongson_dwmac_dt_config(pdev, plat, &res);
+ else
+--
+2.39.5
+
--- /dev/null
+From 545dbeee5fc5d5c812a5c3511b979cade807e337 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 8 Mar 2025 21:37:14 +0000
+Subject: net: stmmac: dwmac-rk: Validate GRF and peripheral GRF during probe
+
+From: Jonas Karlman <jonas@kwiboo.se>
+
+[ Upstream commit 247e84f66a3d1946193d739fec5dc3d69833fd00 ]
+
+All Rockchip GMAC variants typically write to GRF regs to control e.g.
+interface mode, speed and MAC rx/tx delay. Newer SoCs such as RK3576 and
+RK3588 use a mix of GRF and peripheral GRF regs. These syscon regmaps is
+located with help of a rockchip,grf and rockchip,php-grf phandle.
+
+However, validating the rockchip,grf and rockchip,php-grf syscon regmap
+is deferred until e.g. interface mode or speed is configured, inside the
+individual SoC specific operations.
+
+Change to validate the rockchip,grf and rockchip,php-grf syscon regmap
+at probe time to simplify all SoC specific operations.
+
+This should not introduce any backward compatibility issues as all
+GMAC nodes have been added together with a rockchip,grf phandle (and
+rockchip,php-grf where required) in their initial commit.
+
+Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20250308213720.2517944-3-jonas@kwiboo.se
+Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../net/ethernet/stmicro/stmmac/dwmac-rk.c | 21 +++++++++++++++++--
+ 1 file changed, 19 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+index a4dc89e23a68e..a33be23121b35 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+@@ -33,6 +33,7 @@ struct rk_gmac_ops {
+ void (*set_clock_selection)(struct rk_priv_data *bsp_priv, bool input,
+ bool enable);
+ void (*integrated_phy_powerup)(struct rk_priv_data *bsp_priv);
++ bool php_grf_required;
+ bool regs_valid;
+ u32 regs[];
+ };
+@@ -1254,6 +1255,7 @@ static const struct rk_gmac_ops rk3576_ops = {
+ .set_rgmii_speed = rk3576_set_gmac_speed,
+ .set_rmii_speed = rk3576_set_gmac_speed,
+ .set_clock_selection = rk3576_set_clock_selection,
++ .php_grf_required = true,
+ .regs_valid = true,
+ .regs = {
+ 0x2a220000, /* gmac0 */
+@@ -1401,6 +1403,7 @@ static const struct rk_gmac_ops rk3588_ops = {
+ .set_rgmii_speed = rk3588_set_gmac_speed,
+ .set_rmii_speed = rk3588_set_gmac_speed,
+ .set_clock_selection = rk3588_set_clock_selection,
++ .php_grf_required = true,
+ .regs_valid = true,
+ .regs = {
+ 0xfe1b0000, /* gmac0 */
+@@ -1812,8 +1815,22 @@ static struct rk_priv_data *rk_gmac_setup(struct platform_device *pdev,
+
+ bsp_priv->grf = syscon_regmap_lookup_by_phandle(dev->of_node,
+ "rockchip,grf");
+- bsp_priv->php_grf = syscon_regmap_lookup_by_phandle(dev->of_node,
+- "rockchip,php-grf");
++ if (IS_ERR(bsp_priv->grf)) {
++ dev_err_probe(dev, PTR_ERR(bsp_priv->grf),
++ "failed to lookup rockchip,grf\n");
++ return ERR_CAST(bsp_priv->grf);
++ }
++
++ if (ops->php_grf_required) {
++ bsp_priv->php_grf =
++ syscon_regmap_lookup_by_phandle(dev->of_node,
++ "rockchip,php-grf");
++ if (IS_ERR(bsp_priv->php_grf)) {
++ dev_err_probe(dev, PTR_ERR(bsp_priv->php_grf),
++ "failed to lookup rockchip,php-grf\n");
++ return ERR_CAST(bsp_priv->php_grf);
++ }
++ }
+
+ if (plat->phy_node) {
+ bsp_priv->integrated_phy = of_property_read_bool(plat->phy_node,
+--
+2.39.5
+
--- /dev/null
+From 66ff3b0a7b7c1cf9093d438345d826304a6bdab3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 21 Feb 2025 05:12:23 +0000
+Subject: net-sysfs: restore behavior for not running devices
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit 75bc3dab4e49b4daccb27ad6ce8ce2fcd253fc1b ]
+
+modprobe dummy dumdummies=1
+
+Old behavior :
+
+$ cat /sys/class/net/dummy0/carrier
+cat: /sys/class/net/dummy0/carrier: Invalid argument
+
+After blamed commit, an empty string is reported.
+
+$ cat /sys/class/net/dummy0/carrier
+$
+
+In this commit, I restore the old behavior for carrier,
+speed and duplex attributes.
+
+Fixes: 79c61899b5ee ("net-sysfs: remove rtnl_trylock from device attributes")
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Reported-by: Marco Leogrande <leogrande@google.com>
+Reviewed-by: Antoine Tenart <atenart@kernel.org>
+Link: https://patch.msgid.link/20250221051223.576726-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/core/net-sysfs.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
+index 07cb99b114bdd..88e001a4e0810 100644
+--- a/net/core/net-sysfs.c
++++ b/net/core/net-sysfs.c
+@@ -232,11 +232,12 @@ static ssize_t carrier_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+ {
+ struct net_device *netdev = to_net_dev(dev);
+- int ret = -EINVAL;
++ int ret;
+
+ if (!rtnl_trylock())
+ return restart_syscall();
+
++ ret = -EINVAL;
+ if (netif_running(netdev)) {
+ /* Synchronize carrier state with link watch,
+ * see also rtnl_getlink().
+@@ -266,6 +267,7 @@ static ssize_t speed_show(struct device *dev,
+ if (!rtnl_trylock())
+ return restart_syscall();
+
++ ret = -EINVAL;
+ if (netif_running(netdev)) {
+ struct ethtool_link_ksettings cmd;
+
+@@ -292,6 +294,7 @@ static ssize_t duplex_show(struct device *dev,
+ if (!rtnl_trylock())
+ return restart_syscall();
+
++ ret = -EINVAL;
+ if (netif_running(netdev)) {
+ struct ethtool_link_ksettings cmd;
+
+--
+2.39.5
+
--- /dev/null
+From a0eac8e8be4ffe356c41818185280ba493862429 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 22 Mar 2025 11:45:58 +0100
+Subject: net: tn40xx: add pci-id of the aqr105-based Tehuti TN4010 cards
+
+From: Hans-Frieder Vogt <hfdevel@gmx.net>
+
+[ Upstream commit 53377b5c2952097527b01ce2f1d9a9332f042f70 ]
+
+Add the PCI-ID of the AQR105-based Tehuti TN4010 cards to allow loading
+of the tn40xx driver on these cards. Here, I chose the detailed definition
+with the subvendor ID similar to the QT2025 cards with the PCI-ID
+TEHUTI:0x4022, because there is a card with an AQ2104 hiding amongst the
+AQR105 cards, and they all come with the same PCI-ID (TEHUTI:0x4025). But
+the AQ2104 is currently not supported.
+
+Signed-off-by: Hans-Frieder Vogt <hfdevel@gmx.net>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Link: https://patch.msgid.link/20250322-tn9510-v3a-v7-7-672a9a3d8628@gmx.net
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/tehuti/tn40.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/net/ethernet/tehuti/tn40.c b/drivers/net/ethernet/tehuti/tn40.c
+index 259bdac24cf21..a6965258441c4 100644
+--- a/drivers/net/ethernet/tehuti/tn40.c
++++ b/drivers/net/ethernet/tehuti/tn40.c
+@@ -1832,6 +1832,10 @@ static const struct pci_device_id tn40_id_table[] = {
+ PCI_VENDOR_ID_ASUSTEK, 0x8709) },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_TEHUTI, 0x4022,
+ PCI_VENDOR_ID_EDIMAX, 0x8103) },
++ { PCI_DEVICE_SUB(PCI_VENDOR_ID_TEHUTI, PCI_DEVICE_ID_TEHUTI_TN9510,
++ PCI_VENDOR_ID_TEHUTI, 0x3015) },
++ { PCI_DEVICE_SUB(PCI_VENDOR_ID_TEHUTI, PCI_DEVICE_ID_TEHUTI_TN9510,
++ PCI_VENDOR_ID_EDIMAX, 0x8102) },
+ { }
+ };
+
+--
+2.39.5
+
--- /dev/null
+From 7e32147f0508f30b1f90514151d0136c38d39cd7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 22 Mar 2025 11:45:56 +0100
+Subject: net: tn40xx: create swnode for mdio and aqr105 phy and add to mdiobus
+
+From: Hans-Frieder Vogt <hfdevel@gmx.net>
+
+[ Upstream commit 25b6a6d29d4082f6ac231c056ac321a996eb55c9 ]
+
+In case of an AQR105-based device, create a software node for the mdio
+function, with a child node for the Aquantia AQR105 PHY, providing a
+firmware-name (and a bit more, which may be used for future checks) to
+allow the PHY to load a MAC specific firmware from the file system.
+
+The name of the PHY software node follows the naming convention suggested
+in the patch for the mdiobus_scan function (in the same patch series).
+
+Signed-off-by: Hans-Frieder Vogt <hfdevel@gmx.net>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Link: https://patch.msgid.link/20250322-tn9510-v3a-v7-5-672a9a3d8628@gmx.net
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/tehuti/tn40.c | 5 +-
+ drivers/net/ethernet/tehuti/tn40.h | 33 ++++++++++
+ drivers/net/ethernet/tehuti/tn40_mdio.c | 82 ++++++++++++++++++++++++-
+ 3 files changed, 117 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/ethernet/tehuti/tn40.c b/drivers/net/ethernet/tehuti/tn40.c
+index a6965258441c4..558b791a97edd 100644
+--- a/drivers/net/ethernet/tehuti/tn40.c
++++ b/drivers/net/ethernet/tehuti/tn40.c
+@@ -1778,7 +1778,7 @@ static int tn40_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ ret = tn40_phy_register(priv);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to set up PHY.\n");
+- goto err_free_irq;
++ goto err_cleanup_swnodes;
+ }
+
+ ret = tn40_priv_init(priv);
+@@ -1795,6 +1795,8 @@ static int tn40_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ return 0;
+ err_unregister_phydev:
+ tn40_phy_unregister(priv);
++err_cleanup_swnodes:
++ tn40_swnodes_cleanup(priv);
+ err_free_irq:
+ pci_free_irq_vectors(pdev);
+ err_unset_drvdata:
+@@ -1816,6 +1818,7 @@ static void tn40_remove(struct pci_dev *pdev)
+ unregister_netdev(ndev);
+
+ tn40_phy_unregister(priv);
++ tn40_swnodes_cleanup(priv);
+ pci_free_irq_vectors(priv->pdev);
+ pci_set_drvdata(pdev, NULL);
+ iounmap(priv->regs);
+diff --git a/drivers/net/ethernet/tehuti/tn40.h b/drivers/net/ethernet/tehuti/tn40.h
+index 490781fe51205..25da8686d4691 100644
+--- a/drivers/net/ethernet/tehuti/tn40.h
++++ b/drivers/net/ethernet/tehuti/tn40.h
+@@ -4,10 +4,13 @@
+ #ifndef _TN40_H_
+ #define _TN40_H_
+
++#include <linux/property.h>
+ #include "tn40_regs.h"
+
+ #define TN40_DRV_NAME "tn40xx"
+
++#define PCI_DEVICE_ID_TEHUTI_TN9510 0x4025
++
+ #define TN40_MDIO_SPEED_1MHZ (1)
+ #define TN40_MDIO_SPEED_6MHZ (6)
+
+@@ -102,10 +105,39 @@ struct tn40_txdb {
+ int size; /* Number of elements in the db */
+ };
+
++#define NODE_PROP(_NAME, _PROP) ( \
++ (const struct software_node) { \
++ .name = _NAME, \
++ .properties = _PROP, \
++ })
++
++#define NODE_PAR_PROP(_NAME, _PAR, _PROP) ( \
++ (const struct software_node) { \
++ .name = _NAME, \
++ .parent = _PAR, \
++ .properties = _PROP, \
++ })
++
++enum tn40_swnodes {
++ SWNODE_MDIO,
++ SWNODE_PHY,
++ SWNODE_MAX
++};
++
++struct tn40_nodes {
++ char phy_name[32];
++ char mdio_name[32];
++ struct property_entry phy_props[3];
++ struct software_node swnodes[SWNODE_MAX];
++ const struct software_node *group[SWNODE_MAX + 1];
++};
++
+ struct tn40_priv {
+ struct net_device *ndev;
+ struct pci_dev *pdev;
+
++ struct tn40_nodes nodes;
++
+ struct napi_struct napi;
+ /* RX FIFOs: 1 for data (full) descs, and 2 for free descs */
+ struct tn40_rxd_fifo rxd_fifo0;
+@@ -225,6 +257,7 @@ static inline void tn40_write_reg(struct tn40_priv *priv, u32 reg, u32 val)
+
+ int tn40_set_link_speed(struct tn40_priv *priv, u32 speed);
+
++void tn40_swnodes_cleanup(struct tn40_priv *priv);
+ int tn40_mdiobus_init(struct tn40_priv *priv);
+
+ int tn40_phy_register(struct tn40_priv *priv);
+diff --git a/drivers/net/ethernet/tehuti/tn40_mdio.c b/drivers/net/ethernet/tehuti/tn40_mdio.c
+index af18615d64a8a..5bb0cbc87d064 100644
+--- a/drivers/net/ethernet/tehuti/tn40_mdio.c
++++ b/drivers/net/ethernet/tehuti/tn40_mdio.c
+@@ -14,6 +14,8 @@
+ (FIELD_PREP(TN40_MDIO_PRTAD_MASK, (port))))
+ #define TN40_MDIO_CMD_READ BIT(15)
+
++#define AQR105_FIRMWARE "tehuti/aqr105-tn40xx.cld"
++
+ static void tn40_mdio_set_speed(struct tn40_priv *priv, u32 speed)
+ {
+ void __iomem *regs = priv->regs;
+@@ -111,6 +113,56 @@ static int tn40_mdio_write_c45(struct mii_bus *mii_bus, int addr, int devnum,
+ return tn40_mdio_write(mii_bus->priv, addr, devnum, regnum, val);
+ }
+
++/* registers an mdio node and an aqr105 PHY at address 1
++ * tn40_mdio-%id {
++ * ethernet-phy@1 {
++ * compatible = "ethernet-phy-id03a1.b4a3";
++ * reg = <1>;
++ * firmware-name = AQR105_FIRMWARE;
++ * };
++ * };
++ */
++static int tn40_swnodes_register(struct tn40_priv *priv)
++{
++ struct tn40_nodes *nodes = &priv->nodes;
++ struct pci_dev *pdev = priv->pdev;
++ struct software_node *swnodes;
++ u32 id;
++
++ id = pci_dev_id(pdev);
++
++ snprintf(nodes->phy_name, sizeof(nodes->phy_name), "ethernet-phy@1");
++ snprintf(nodes->mdio_name, sizeof(nodes->mdio_name), "tn40_mdio-%x",
++ id);
++
++ swnodes = nodes->swnodes;
++
++ swnodes[SWNODE_MDIO] = NODE_PROP(nodes->mdio_name, NULL);
++
++ nodes->phy_props[0] = PROPERTY_ENTRY_STRING("compatible",
++ "ethernet-phy-id03a1.b4a3");
++ nodes->phy_props[1] = PROPERTY_ENTRY_U32("reg", 1);
++ nodes->phy_props[2] = PROPERTY_ENTRY_STRING("firmware-name",
++ AQR105_FIRMWARE);
++ swnodes[SWNODE_PHY] = NODE_PAR_PROP(nodes->phy_name,
++ &swnodes[SWNODE_MDIO],
++ nodes->phy_props);
++
++ nodes->group[SWNODE_PHY] = &swnodes[SWNODE_PHY];
++ nodes->group[SWNODE_MDIO] = &swnodes[SWNODE_MDIO];
++ return software_node_register_node_group(nodes->group);
++}
++
++void tn40_swnodes_cleanup(struct tn40_priv *priv)
++{
++ /* cleanup of swnodes is only needed for AQR105-based cards */
++ if (priv->pdev->device == PCI_DEVICE_ID_TEHUTI_TN9510) {
++ fwnode_handle_put(dev_fwnode(&priv->mdio->dev));
++ device_remove_software_node(&priv->mdio->dev);
++ software_node_unregister_node_group(priv->nodes.group);
++ }
++}
++
+ int tn40_mdiobus_init(struct tn40_priv *priv)
+ {
+ struct pci_dev *pdev = priv->pdev;
+@@ -129,14 +181,40 @@ int tn40_mdiobus_init(struct tn40_priv *priv)
+
+ bus->read_c45 = tn40_mdio_read_c45;
+ bus->write_c45 = tn40_mdio_write_c45;
++ priv->mdio = bus;
++
++ /* provide swnodes for AQR105-based cards only */
++ if (pdev->device == PCI_DEVICE_ID_TEHUTI_TN9510) {
++ ret = tn40_swnodes_register(priv);
++ if (ret) {
++ pr_err("swnodes failed\n");
++ return ret;
++ }
++
++ ret = device_add_software_node(&bus->dev,
++ priv->nodes.group[SWNODE_MDIO]);
++ if (ret) {
++ dev_err(&pdev->dev,
++ "device_add_software_node failed: %d\n", ret);
++ goto err_swnodes_unregister;
++ }
++ }
+
+ ret = devm_mdiobus_register(&pdev->dev, bus);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register mdiobus %d %u %u\n",
+ ret, bus->state, MDIOBUS_UNREGISTERED);
+- return ret;
++ goto err_swnodes_cleanup;
+ }
+ tn40_mdio_set_speed(priv, TN40_MDIO_SPEED_6MHZ);
+- priv->mdio = bus;
+ return 0;
++
++err_swnodes_unregister:
++ software_node_unregister_node_group(priv->nodes.group);
++ return ret;
++err_swnodes_cleanup:
++ tn40_swnodes_cleanup(priv);
++ return ret;
+ }
++
++MODULE_FIRMWARE(AQR105_FIRMWARE);
+--
+2.39.5
+
--- /dev/null
+From c9c4a0380f0f18dfda0f106df68b63409d3c1fc8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 25 Feb 2025 17:33:33 +0100
+Subject: net: xgene-v2: remove incorrect ACPI_PTR annotation
+
+From: Arnd Bergmann <arnd@arndb.de>
+
+[ Upstream commit 01358e8fe922f716c05d7864ac2213b2440026e7 ]
+
+Building with W=1 shows a warning about xge_acpi_match being unused when
+CONFIG_ACPI is disabled:
+
+drivers/net/ethernet/apm/xgene-v2/main.c:723:36: error: unused variable 'xge_acpi_match' [-Werror,-Wunused-const-variable]
+
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Link: https://patch.msgid.link/20250225163341.4168238-2-arnd@kernel.org
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/apm/xgene-v2/main.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+diff --git a/drivers/net/ethernet/apm/xgene-v2/main.c b/drivers/net/ethernet/apm/xgene-v2/main.c
+index 2a91c84aebdb0..d7ca847d44c7c 100644
+--- a/drivers/net/ethernet/apm/xgene-v2/main.c
++++ b/drivers/net/ethernet/apm/xgene-v2/main.c
+@@ -9,8 +9,6 @@
+
+ #include "main.h"
+
+-static const struct acpi_device_id xge_acpi_match[];
+-
+ static int xge_get_resources(struct xge_pdata *pdata)
+ {
+ struct platform_device *pdev;
+@@ -731,7 +729,7 @@ MODULE_DEVICE_TABLE(acpi, xge_acpi_match);
+ static struct platform_driver xge_driver = {
+ .driver = {
+ .name = "xgene-enet-v2",
+- .acpi_match_table = ACPI_PTR(xge_acpi_match),
++ .acpi_match_table = xge_acpi_match,
+ },
+ .probe = xge_probe,
+ .remove = xge_remove,
+--
+2.39.5
+
--- /dev/null
+From f6fc83791c2b992379c98c7d18449ffc2361a8d9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Feb 2025 14:56:38 -0800
+Subject: netdevsim: allow normal queue reset while down
+
+From: Jakub Kicinski <kuba@kernel.org>
+
+[ Upstream commit 285b3f78eabd951e59e98f01f86abaaa6c76cd44 ]
+
+Resetting queues while the device is down should be legal.
+Allow it, test it. Ideally we'd test this with a real device
+supporting devmem but I don't have access to such devices.
+
+Reviewed-by: Mina Almasry <almasrymina@google.com>
+Link: https://patch.msgid.link/20250206225638.1387810-5-kuba@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/netdevsim/netdev.c | 10 ++++------
+ tools/testing/selftests/net/nl_netdev.py | 18 +++++++++++++++++-
+ 2 files changed, 21 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c
+index e4c0d77849b82..a41dc79e9c2e0 100644
+--- a/drivers/net/netdevsim/netdev.c
++++ b/drivers/net/netdevsim/netdev.c
+@@ -664,8 +664,11 @@ nsim_queue_mem_alloc(struct net_device *dev, void *per_queue_mem, int idx)
+ if (ns->rq_reset_mode > 3)
+ return -EINVAL;
+
+- if (ns->rq_reset_mode == 1)
++ if (ns->rq_reset_mode == 1) {
++ if (!netif_running(ns->netdev))
++ return -ENETDOWN;
+ return nsim_create_page_pool(&qmem->pp, &ns->rq[idx]->napi);
++ }
+
+ qmem->rq = nsim_queue_alloc();
+ if (!qmem->rq)
+@@ -773,11 +776,6 @@ nsim_qreset_write(struct file *file, const char __user *data,
+ return -EINVAL;
+
+ rtnl_lock();
+- if (!netif_running(ns->netdev)) {
+- ret = -ENETDOWN;
+- goto exit_unlock;
+- }
+-
+ if (queue >= ns->netdev->real_num_rx_queues) {
+ ret = -EINVAL;
+ goto exit_unlock;
+diff --git a/tools/testing/selftests/net/nl_netdev.py b/tools/testing/selftests/net/nl_netdev.py
+index 93e8cb671c3d9..beaee5e4e2aab 100755
+--- a/tools/testing/selftests/net/nl_netdev.py
++++ b/tools/testing/selftests/net/nl_netdev.py
+@@ -35,6 +35,21 @@ def napi_list_check(nf) -> None:
+ comment=f"queue count after reset queue {q} mode {i}")
+
+
++def nsim_rxq_reset_down(nf) -> None:
++ """
++ Test that the queue API supports resetting a queue
++ while the interface is down. We should convert this
++ test to testing real HW once more devices support
++ queue API.
++ """
++ with NetdevSimDev(queue_count=4) as nsimdev:
++ nsim = nsimdev.nsims[0]
++
++ ip(f"link set dev {nsim.ifname} down")
++ for i in [0, 2, 3]:
++ nsim.dfs_write("queue_reset", f"1 {i}")
++
++
+ def page_pool_check(nf) -> None:
+ with NetdevSimDev() as nsimdev:
+ nsim = nsimdev.nsims[0]
+@@ -106,7 +121,8 @@ def page_pool_check(nf) -> None:
+
+ def main() -> None:
+ nf = NetdevFamily()
+- ksft_run([empty_check, lo_check, page_pool_check, napi_list_check],
++ ksft_run([empty_check, lo_check, page_pool_check, napi_list_check,
++ nsim_rxq_reset_down],
+ args=(nf, ))
+ ksft_exit()
+
+--
+2.39.5
+
--- /dev/null
+From bc86ccb1060c6e2f099354b406e9d492b2300b21 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 19 Feb 2025 08:41:20 -0800
+Subject: netdevsim: call napi_schedule from a timer context
+
+From: Breno Leitao <leitao@debian.org>
+
+[ Upstream commit bf3624cf1c3708284c53ed99a1c43f2e104dc2dd ]
+
+The netdevsim driver was experiencing NOHZ tick-stop errors during packet
+transmission due to pending softirq work when calling napi_schedule().
+This issue was observed when running the netconsole selftest, which
+triggered the following error message:
+
+ NOHZ tick-stop error: local softirq work is pending, handler #08!!!
+
+To fix this issue, introduce a timer that schedules napi_schedule()
+from a timer context instead of calling it directly from the TX path.
+
+Create an hrtimer for each queue and kick it from the TX path,
+which then schedules napi_schedule() from the timer context.
+
+Suggested-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Breno Leitao <leitao@debian.org>
+Link: https://patch.msgid.link/20250219-netdevsim-v3-1-811e2b8abc4c@debian.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/netdevsim/netdev.c | 21 ++++++++++++++++++++-
+ drivers/net/netdevsim/netdevsim.h | 1 +
+ 2 files changed, 21 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c
+index 42f247cbdceec..e4c0d77849b82 100644
+--- a/drivers/net/netdevsim/netdev.c
++++ b/drivers/net/netdevsim/netdev.c
+@@ -87,7 +87,8 @@ static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ if (unlikely(nsim_forward_skb(peer_dev, skb, rq) == NET_RX_DROP))
+ goto out_drop_cnt;
+
+- napi_schedule(&rq->napi);
++ if (!hrtimer_active(&rq->napi_timer))
++ hrtimer_start(&rq->napi_timer, us_to_ktime(5), HRTIMER_MODE_REL);
+
+ rcu_read_unlock();
+ u64_stats_update_begin(&ns->syncp);
+@@ -426,6 +427,22 @@ static int nsim_init_napi(struct netdevsim *ns)
+ return err;
+ }
+
++static enum hrtimer_restart nsim_napi_schedule(struct hrtimer *timer)
++{
++ struct nsim_rq *rq;
++
++ rq = container_of(timer, struct nsim_rq, napi_timer);
++ napi_schedule(&rq->napi);
++
++ return HRTIMER_NORESTART;
++}
++
++static void nsim_rq_timer_init(struct nsim_rq *rq)
++{
++ hrtimer_init(&rq->napi_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
++ rq->napi_timer.function = nsim_napi_schedule;
++}
++
+ static void nsim_enable_napi(struct netdevsim *ns)
+ {
+ struct net_device *dev = ns->netdev;
+@@ -615,11 +632,13 @@ static struct nsim_rq *nsim_queue_alloc(void)
+ return NULL;
+
+ skb_queue_head_init(&rq->skb_queue);
++ nsim_rq_timer_init(rq);
+ return rq;
+ }
+
+ static void nsim_queue_free(struct nsim_rq *rq)
+ {
++ hrtimer_cancel(&rq->napi_timer);
+ skb_queue_purge_reason(&rq->skb_queue, SKB_DROP_REASON_QUEUE_PURGE);
+ kfree(rq);
+ }
+diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h
+index 96d54c08043d3..e757f85ed8617 100644
+--- a/drivers/net/netdevsim/netdevsim.h
++++ b/drivers/net/netdevsim/netdevsim.h
+@@ -97,6 +97,7 @@ struct nsim_rq {
+ struct napi_struct napi;
+ struct sk_buff_head skb_queue;
+ struct page_pool *page_pool;
++ struct hrtimer napi_timer;
+ };
+
+ struct netdevsim {
+--
+2.39.5
+
--- /dev/null
+From 2519fbb3ffa61369fa084c37c49dbe08bd7366fe Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jan 2025 18:06:30 +0100
+Subject: netfilter: conntrack: Bound nf_conntrack sysctl writes
+
+From: Nicolas Bouchinet <nicolas.bouchinet@ssi.gouv.fr>
+
+[ Upstream commit 8b6861390ffee6b8ed78b9395e3776c16fec6579 ]
+
+nf_conntrack_max and nf_conntrack_expect_max sysctls were authorized to
+be written any negative value, which would then be stored in the
+unsigned int variables nf_conntrack_max and nf_ct_expect_max variables.
+
+While the do_proc_dointvec_conv function is supposed to limit writing
+handled by proc_dointvec proc_handler to INT_MAX. Such a negative value
+being written in an unsigned int leads to a very high value, exceeding
+this limit.
+
+Moreover, the nf_conntrack_expect_max sysctl documentation specifies the
+minimum value is 1.
+
+The proc_handlers have thus been updated to proc_dointvec_minmax in
+order to specify the following write bounds :
+
+* Bound nf_conntrack_max sysctl writings between SYSCTL_ZERO
+ and SYSCTL_INT_MAX.
+
+* Bound nf_conntrack_expect_max sysctl writings between SYSCTL_ONE
+ and SYSCTL_INT_MAX as defined in the sysctl documentation.
+
+With this patch applied, sysctl writes outside the defined in the bound
+will thus lead to a write error :
+
+```
+sysctl -w net.netfilter.nf_conntrack_expect_max=-1
+sysctl: setting key "net.netfilter.nf_conntrack_expect_max": Invalid argument
+```
+
+Signed-off-by: Nicolas Bouchinet <nicolas.bouchinet@ssi.gouv.fr>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_conntrack_standalone.c | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
+index 502cf10aab41d..2f666751c7e7c 100644
+--- a/net/netfilter/nf_conntrack_standalone.c
++++ b/net/netfilter/nf_conntrack_standalone.c
+@@ -618,7 +618,9 @@ static struct ctl_table nf_ct_sysctl_table[] = {
+ .data = &nf_conntrack_max,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+- .proc_handler = proc_dointvec,
++ .proc_handler = proc_dointvec_minmax,
++ .extra1 = SYSCTL_ZERO,
++ .extra2 = SYSCTL_INT_MAX,
+ },
+ [NF_SYSCTL_CT_COUNT] = {
+ .procname = "nf_conntrack_count",
+@@ -654,7 +656,9 @@ static struct ctl_table nf_ct_sysctl_table[] = {
+ .data = &nf_ct_expect_max,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+- .proc_handler = proc_dointvec,
++ .proc_handler = proc_dointvec_minmax,
++ .extra1 = SYSCTL_ONE,
++ .extra2 = SYSCTL_INT_MAX,
+ },
+ [NF_SYSCTL_CT_ACCT] = {
+ .procname = "nf_conntrack_acct",
+@@ -947,7 +951,9 @@ static struct ctl_table nf_ct_netfilter_table[] = {
+ .data = &nf_conntrack_max,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+- .proc_handler = proc_dointvec,
++ .proc_handler = proc_dointvec_minmax,
++ .extra1 = SYSCTL_ZERO,
++ .extra2 = SYSCTL_INT_MAX,
+ },
+ };
+
+--
+2.39.5
+
--- /dev/null
+From d8b29bfdfb205853a7976e7119f35e60c5fd352a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 28 Mar 2025 13:19:18 -0400
+Subject: NFS: Don't allow waiting for exiting tasks
+
+From: Trond Myklebust <trond.myklebust@hammerspace.com>
+
+[ Upstream commit 8d3ca331026a7f9700d3747eed59a67b8f828cdc ]
+
+Once a task calls exit_signals() it can no longer be signalled. So do
+not allow it to do killable waits.
+
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/nfs/inode.c | 2 ++
+ fs/nfs/internal.h | 5 +++++
+ fs/nfs/nfs3proc.c | 2 +-
+ fs/nfs/nfs4proc.c | 9 +++++++--
+ 4 files changed, 15 insertions(+), 3 deletions(-)
+
+diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
+index 1aa67fca69b2f..119e447758b99 100644
+--- a/fs/nfs/inode.c
++++ b/fs/nfs/inode.c
+@@ -74,6 +74,8 @@ nfs_fattr_to_ino_t(struct nfs_fattr *fattr)
+
+ int nfs_wait_bit_killable(struct wait_bit_key *key, int mode)
+ {
++ if (unlikely(nfs_current_task_exiting()))
++ return -EINTR;
+ schedule();
+ if (signal_pending_state(mode, current))
+ return -ERESTARTSYS;
+diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
+index 59bb4d0338f39..3cedb7979fcd0 100644
+--- a/fs/nfs/internal.h
++++ b/fs/nfs/internal.h
+@@ -905,6 +905,11 @@ static inline u32 nfs_stateid_hash(const nfs4_stateid *stateid)
+ NFS4_STATEID_OTHER_SIZE);
+ }
+
++static inline bool nfs_current_task_exiting(void)
++{
++ return (current->flags & PF_EXITING) != 0;
++}
++
+ static inline bool nfs_error_is_fatal(int err)
+ {
+ switch (err) {
+diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
+index 0c3bc98cd999c..c1736dbb92b63 100644
+--- a/fs/nfs/nfs3proc.c
++++ b/fs/nfs/nfs3proc.c
+@@ -39,7 +39,7 @@ nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
+ __set_current_state(TASK_KILLABLE|TASK_FREEZABLE_UNSAFE);
+ schedule_timeout(NFS_JUKEBOX_RETRY_TIME);
+ res = -ERESTARTSYS;
+- } while (!fatal_signal_pending(current));
++ } while (!fatal_signal_pending(current) && !nfs_current_task_exiting());
+ return res;
+ }
+
+diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
+index 810cfd9b7e533..cfdbd521fc7b6 100644
+--- a/fs/nfs/nfs4proc.c
++++ b/fs/nfs/nfs4proc.c
+@@ -443,6 +443,8 @@ static int nfs4_delay_killable(long *timeout)
+ {
+ might_sleep();
+
++ if (unlikely(nfs_current_task_exiting()))
++ return -EINTR;
+ __set_current_state(TASK_KILLABLE|TASK_FREEZABLE_UNSAFE);
+ schedule_timeout(nfs4_update_delay(timeout));
+ if (!__fatal_signal_pending(current))
+@@ -454,6 +456,8 @@ static int nfs4_delay_interruptible(long *timeout)
+ {
+ might_sleep();
+
++ if (unlikely(nfs_current_task_exiting()))
++ return -EINTR;
+ __set_current_state(TASK_INTERRUPTIBLE|TASK_FREEZABLE_UNSAFE);
+ schedule_timeout(nfs4_update_delay(timeout));
+ if (!signal_pending(current))
+@@ -1774,7 +1778,8 @@ static void nfs_set_open_stateid_locked(struct nfs4_state *state,
+ rcu_read_unlock();
+ trace_nfs4_open_stateid_update_wait(state->inode, stateid, 0);
+
+- if (!fatal_signal_pending(current)) {
++ if (!fatal_signal_pending(current) &&
++ !nfs_current_task_exiting()) {
+ if (schedule_timeout(5*HZ) == 0)
+ status = -EAGAIN;
+ else
+@@ -3578,7 +3583,7 @@ static bool nfs4_refresh_open_old_stateid(nfs4_stateid *dst,
+ write_sequnlock(&state->seqlock);
+ trace_nfs4_close_stateid_update_wait(state->inode, dst, 0);
+
+- if (fatal_signal_pending(current))
++ if (fatal_signal_pending(current) || nfs_current_task_exiting())
+ status = -EINTR;
+ else
+ if (schedule_timeout(5*HZ) != 0)
+--
+2.39.5
+
--- /dev/null
+From fc00ea48a17838d3642bb05832f3750b65857e27 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Mar 2025 19:20:53 -0400
+Subject: NFSv4: Check for delegation validity in
+ nfs_start_delegation_return_locked()
+
+From: Trond Myklebust <trond.myklebust@hammerspace.com>
+
+[ Upstream commit 9e8f324bd44c1fe026b582b75213de4eccfa1163 ]
+
+Check that the delegation is still attached after taking the spin lock
+in nfs_start_delegation_return_locked().
+
+Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/nfs/delegation.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
+index 325ba0663a6de..8bdbc4dca89ca 100644
+--- a/fs/nfs/delegation.c
++++ b/fs/nfs/delegation.c
+@@ -307,7 +307,8 @@ nfs_start_delegation_return_locked(struct nfs_inode *nfsi)
+ if (delegation == NULL)
+ goto out;
+ spin_lock(&delegation->lock);
+- if (!test_and_set_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) {
++ if (delegation->inode &&
++ !test_and_set_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) {
+ clear_bit(NFS_DELEGATION_RETURN_DELAYED, &delegation->flags);
+ /* Refcount matched in nfs_end_delegation_return() */
+ ret = nfs_get_delegation(delegation);
+--
+2.39.5
+
--- /dev/null
+From fb8c3e11e202e7b62b58de206321f1e778857f49 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 24 Mar 2025 20:35:33 -0400
+Subject: NFSv4: Treat ENETUNREACH errors as fatal for state recovery
+
+From: Trond Myklebust <trond.myklebust@hammerspace.com>
+
+[ Upstream commit 0af5fb5ed3d2fd9e110c6112271f022b744a849a ]
+
+If a containerised process is killed and causes an ENETUNREACH or
+ENETDOWN error to be propagated to the state manager, then mark the
+nfs_client as being dead so that we don't loop in functions that are
+expecting recovery to succeed.
+
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Reviewed-by: Benjamin Coddington <bcodding@redhat.com>
+Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/nfs/nfs4state.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
+index 542cdf71229fe..04c726cc2900b 100644
+--- a/fs/nfs/nfs4state.c
++++ b/fs/nfs/nfs4state.c
+@@ -2739,7 +2739,15 @@ static void nfs4_state_manager(struct nfs_client *clp)
+ pr_warn_ratelimited("NFS: state manager%s%s failed on NFSv4 server %s"
+ " with error %d\n", section_sep, section,
+ clp->cl_hostname, -status);
+- ssleep(1);
++ switch (status) {
++ case -ENETDOWN:
++ case -ENETUNREACH:
++ nfs_mark_client_ready(clp, -EIO);
++ break;
++ default:
++ ssleep(1);
++ break;
++ }
+ out_drain:
+ memalloc_nofs_restore(memflags);
+ nfs4_end_drain_session(clp);
+--
+2.39.5
+
--- /dev/null
+From 870c1a026c6be100cb616275fac6fa23e7816eb3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Feb 2025 19:06:09 +0900
+Subject: null_blk: generate null_blk configfs features string
+
+From: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
+
+[ Upstream commit 2cadb8ef25a6157b5bd3e8fe0d3e23f32defec25 ]
+
+The null_blk configfs file 'features' provides a string that lists
+available null_blk features for userspace programs to reference.
+The string is defined as a long constant in the code, which tends to be
+forgotten for updates. It also causes checkpatch.pl to report
+"WARNING: quoted string split across lines".
+
+To avoid these drawbacks, generate the feature string on the fly. Refer
+to the ca_name field of each element in the nullb_device_attrs table and
+concatenate them in the given buffer. Also, sorted nullb_device_attrs
+table elements in alphabetical order.
+
+Of note is that the feature "index" was missing before this commit.
+This commit adds it to the generated string.
+
+Suggested-by: Bart Van Assche <bvanassche@acm.org>
+Reviewed-by: Bart Van Assche <bvanassche@acm.org>
+Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
+Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
+Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
+Signed-off-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
+Link: https://lore.kernel.org/r/20250226100613.1622564-2-shinichiro.kawasaki@wdc.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/block/null_blk/main.c | 86 ++++++++++++++++++++---------------
+ 1 file changed, 49 insertions(+), 37 deletions(-)
+
+diff --git a/drivers/block/null_blk/main.c b/drivers/block/null_blk/main.c
+index 175566a71bb3f..41c2cd5818b4a 100644
+--- a/drivers/block/null_blk/main.c
++++ b/drivers/block/null_blk/main.c
+@@ -592,41 +592,41 @@ static ssize_t nullb_device_zone_offline_store(struct config_item *item,
+ CONFIGFS_ATTR_WO(nullb_device_, zone_offline);
+
+ static struct configfs_attribute *nullb_device_attrs[] = {
+- &nullb_device_attr_size,
++ &nullb_device_attr_badblocks,
++ &nullb_device_attr_blocking,
++ &nullb_device_attr_blocksize,
++ &nullb_device_attr_cache_size,
+ &nullb_device_attr_completion_nsec,
+- &nullb_device_attr_submit_queues,
+- &nullb_device_attr_poll_queues,
++ &nullb_device_attr_discard,
++ &nullb_device_attr_fua,
+ &nullb_device_attr_home_node,
+- &nullb_device_attr_queue_mode,
+- &nullb_device_attr_blocksize,
+- &nullb_device_attr_max_sectors,
+- &nullb_device_attr_irqmode,
+ &nullb_device_attr_hw_queue_depth,
+ &nullb_device_attr_index,
+- &nullb_device_attr_blocking,
+- &nullb_device_attr_use_per_node_hctx,
+- &nullb_device_attr_power,
+- &nullb_device_attr_memory_backed,
+- &nullb_device_attr_discard,
++ &nullb_device_attr_irqmode,
++ &nullb_device_attr_max_sectors,
+ &nullb_device_attr_mbps,
+- &nullb_device_attr_cache_size,
+- &nullb_device_attr_badblocks,
+- &nullb_device_attr_zoned,
+- &nullb_device_attr_zone_size,
++ &nullb_device_attr_memory_backed,
++ &nullb_device_attr_no_sched,
++ &nullb_device_attr_poll_queues,
++ &nullb_device_attr_power,
++ &nullb_device_attr_queue_mode,
++ &nullb_device_attr_rotational,
++ &nullb_device_attr_shared_tag_bitmap,
++ &nullb_device_attr_shared_tags,
++ &nullb_device_attr_size,
++ &nullb_device_attr_submit_queues,
++ &nullb_device_attr_use_per_node_hctx,
++ &nullb_device_attr_virt_boundary,
++ &nullb_device_attr_zone_append_max_sectors,
+ &nullb_device_attr_zone_capacity,
+- &nullb_device_attr_zone_nr_conv,
+- &nullb_device_attr_zone_max_open,
++ &nullb_device_attr_zone_full,
+ &nullb_device_attr_zone_max_active,
+- &nullb_device_attr_zone_append_max_sectors,
+- &nullb_device_attr_zone_readonly,
++ &nullb_device_attr_zone_max_open,
++ &nullb_device_attr_zone_nr_conv,
+ &nullb_device_attr_zone_offline,
+- &nullb_device_attr_zone_full,
+- &nullb_device_attr_virt_boundary,
+- &nullb_device_attr_no_sched,
+- &nullb_device_attr_shared_tags,
+- &nullb_device_attr_shared_tag_bitmap,
+- &nullb_device_attr_fua,
+- &nullb_device_attr_rotational,
++ &nullb_device_attr_zone_readonly,
++ &nullb_device_attr_zone_size,
++ &nullb_device_attr_zoned,
+ NULL,
+ };
+
+@@ -704,16 +704,28 @@ nullb_group_drop_item(struct config_group *group, struct config_item *item)
+
+ static ssize_t memb_group_features_show(struct config_item *item, char *page)
+ {
+- return snprintf(page, PAGE_SIZE,
+- "badblocks,blocking,blocksize,cache_size,fua,"
+- "completion_nsec,discard,home_node,hw_queue_depth,"
+- "irqmode,max_sectors,mbps,memory_backed,no_sched,"
+- "poll_queues,power,queue_mode,shared_tag_bitmap,"
+- "shared_tags,size,submit_queues,use_per_node_hctx,"
+- "virt_boundary,zoned,zone_capacity,zone_max_active,"
+- "zone_max_open,zone_nr_conv,zone_offline,zone_readonly,"
+- "zone_size,zone_append_max_sectors,zone_full,"
+- "rotational\n");
++
++ struct configfs_attribute **entry;
++ char delimiter = ',';
++ size_t left = PAGE_SIZE;
++ size_t written = 0;
++ int ret;
++
++ for (entry = &nullb_device_attrs[0]; *entry && left > 0; entry++) {
++ if (!*(entry + 1))
++ delimiter = '\n';
++ ret = snprintf(page + written, left, "%s%c", (*entry)->ca_name,
++ delimiter);
++ if (ret >= left) {
++ WARN_ONCE(1, "Too many null_blk features to print\n");
++ memzero_explicit(page, PAGE_SIZE);
++ return -ENOBUFS;
++ }
++ left -= ret;
++ written += ret;
++ }
++
++ return written;
+ }
+
+ CONFIGFS_ATTR_RO(memb_group_, features);
+--
+2.39.5
+
--- /dev/null
+From f2bb98e26000a4275706bb5c26b02be15ae41e5f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Feb 2025 14:39:13 -0800
+Subject: nvme: map uring_cmd data even if address is 0
+
+From: Xinyu Zhang <xizhang@purestorage.com>
+
+[ Upstream commit 99fde895ff56ac2241e7b7b4566731d72f2fdaa7 ]
+
+When using kernel registered bvec fixed buffers, the "address" is
+actually the offset into the bvec rather than userspace address.
+Therefore it can be 0.
+
+We can skip checking whether the address is NULL before mapping
+uring_cmd data. Bad userspace address will be handled properly later when
+the user buffer is imported.
+
+With this patch, we will be able to use the kernel registered bvec fixed
+buffers in io_uring NVMe passthru with ublk zero-copy support.
+
+Reviewed-by: Caleb Sander Mateos <csander@purestorage.com>
+Reviewed-by: Jens Axboe <axboe@kernel.dk>
+Reviewed-by: Ming Lei <ming.lei@redhat.com>
+Signed-off-by: Xinyu Zhang <xizhang@purestorage.com>
+Signed-off-by: Keith Busch <kbusch@kernel.org>
+Link: https://lore.kernel.org/r/20250227223916.143006-4-kbusch@meta.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/nvme/host/ioctl.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/nvme/host/ioctl.c b/drivers/nvme/host/ioctl.c
+index fed6b29098ad3..11509ffd28fb5 100644
+--- a/drivers/nvme/host/ioctl.c
++++ b/drivers/nvme/host/ioctl.c
+@@ -514,7 +514,7 @@ static int nvme_uring_cmd_io(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
+ return PTR_ERR(req);
+ req->timeout = d.timeout_ms ? msecs_to_jiffies(d.timeout_ms) : 0;
+
+- if (d.addr && d.data_len) {
++ if (d.data_len) {
+ ret = nvme_map_user_request(req, d.addr,
+ d.data_len, nvme_to_user_ptr(d.metadata),
+ d.metadata_len, ioucmd, vec);
+--
+2.39.5
+
--- /dev/null
+From 7a187e62372ea77f5d983698f4a275b4d2215ded Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 22 Apr 2025 20:17:25 +0800
+Subject: nvme-pci: add quirks for device 126f:1001
+
+From: Wentao Guan <guanwentao@uniontech.com>
+
+[ Upstream commit 5b960f92ac3e5b4d7f60a506a6b6735eead1da01 ]
+
+This commit adds NVME_QUIRK_NO_DEEPEST_PS and NVME_QUIRK_BOGUS_NID for
+device [126f:1001].
+
+It is similar to commit e89086c43f05 ("drivers/nvme: Add quirks for
+device 126f:2262")
+
+Diff is according the dmesg, use NVME_QUIRK_IGNORE_DEV_SUBNQN.
+
+dmesg | grep -i nvme0:
+ nvme nvme0: pci function 0000:01:00.0
+ nvme nvme0: missing or invalid SUBNQN field.
+ nvme nvme0: 12/0/0 default/read/poll queues
+
+Link:https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=e89086c43f0500bc7c4ce225495b73b8ce234c1f
+Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
+Signed-off-by: WangYuli <wangyuli@uniontech.com>
+Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/nvme/host/pci.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
+index 00bd21b5c641e..63b03a5a5b765 100644
+--- a/drivers/nvme/host/pci.c
++++ b/drivers/nvme/host/pci.c
+@@ -3628,6 +3628,9 @@ static const struct pci_device_id nvme_id_table[] = {
+ .driver_data = NVME_QUIRK_BOGUS_NID, },
+ { PCI_DEVICE(0x1217, 0x8760), /* O2 Micro 64GB Steam Deck */
+ .driver_data = NVME_QUIRK_DMAPOOL_ALIGN_512, },
++ { PCI_DEVICE(0x126f, 0x1001), /* Silicon Motion generic */
++ .driver_data = NVME_QUIRK_NO_DEEPEST_PS |
++ NVME_QUIRK_IGNORE_DEV_SUBNQN, },
+ { PCI_DEVICE(0x126f, 0x2262), /* Silicon Motion generic */
+ .driver_data = NVME_QUIRK_NO_DEEPEST_PS |
+ NVME_QUIRK_BOGUS_NID, },
+--
+2.39.5
+
--- /dev/null
+From 7428e8064eb3d715524f37c3c3b6d701ea1805ce Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 24 Apr 2025 10:40:10 +0800
+Subject: nvme-pci: add quirks for WDC Blue SN550 15b7:5009
+
+From: Wentao Guan <guanwentao@uniontech.com>
+
+[ Upstream commit ab35ad950d439ec3409509835d229b3d93d3c7f9 ]
+
+Add two quirks for the WDC Blue SN550 (PCI ID 15b7:5009) based on user
+reports and hardware analysis:
+
+ - NVME_QUIRK_NO_DEEPEST_PS:
+ liaozw talked to me the problem and solved with
+ nvme_core.default_ps_max_latency_us=0, so add the quirk.
+ I also found some reports in the following link.
+
+ - NVME_QUIRK_BROKEN_MSI:
+ after get the lspci from Jack Rio.
+ I think that the disk also have NVME_QUIRK_BROKEN_MSI.
+ described in commit d5887dc6b6c0 ("nvme-pci: Add quirk for broken MSIs")
+ as sean said in link which match the MSI 1/32 and MSI-X 17.
+
+Log:
+lspci -nn | grep -i memory
+03:00.0 Non-Volatile memory controller [0108]: Sandisk Corp SanDisk Ultra 3D / WD PC SN530, IX SN530, Blue SN550 NVMe SSD (DRAM-less) [15b7:5009] (rev 01)
+lspci -v -d 15b7:5009
+03:00.0 Non-Volatile memory controller: Sandisk Corp SanDisk Ultra 3D / WD PC SN530, IX SN530, Blue SN550 NVMe SSD (DRAM-less) (rev 01) (prog-if 02 [NVM Express])
+ Subsystem: Sandisk Corp WD Blue SN550 NVMe SSD
+ Flags: bus master, fast devsel, latency 0, IRQ 35, IOMMU group 10
+ Memory at fe800000 (64-bit, non-prefetchable) [size=16K]
+ Memory at fe804000 (64-bit, non-prefetchable) [size=256]
+ Capabilities: [80] Power Management version 3
+ Capabilities: [90] MSI: Enable- Count=1/32 Maskable- 64bit+
+ Capabilities: [b0] MSI-X: Enable+ Count=17 Masked-
+ Capabilities: [c0] Express Endpoint, MSI 00
+ Capabilities: [100] Advanced Error Reporting
+ Capabilities: [150] Device Serial Number 00-00-00-00-00-00-00-00
+ Capabilities: [1b8] Latency Tolerance Reporting
+ Capabilities: [300] Secondary PCI Express
+ Capabilities: [900] L1 PM Substates
+ Kernel driver in use: nvme
+dmesg | grep nvme
+[ 0.000000] Command line: BOOT_IMAGE=/vmlinuz-6.12.20-amd64-desktop-rolling root=UUID= ro splash quiet nvme_core.default_ps_max_latency_us=0 DEEPIN_GFXMODE=
+[ 0.059301] Kernel command line: BOOT_IMAGE=/vmlinuz-6.12.20-amd64-desktop-rolling root=UUID= ro splash quiet nvme_core.default_ps_max_latency_us=0 DEEPIN_GFXMODE=
+[ 0.542430] nvme nvme0: pci function 0000:03:00.0
+[ 0.560426] nvme nvme0: allocated 32 MiB host memory buffer.
+[ 0.562491] nvme nvme0: 16/0/0 default/read/poll queues
+[ 0.567764] nvme0n1: p1 p2 p3 p4 p5 p6 p7 p8 p9
+[ 6.388726] EXT4-fs (nvme0n1p7): mounted filesystem ro with ordered data mode. Quota mode: none.
+[ 6.893421] EXT4-fs (nvme0n1p7): re-mounted r/w. Quota mode: none.
+[ 7.125419] Adding 16777212k swap on /dev/nvme0n1p8. Priority:-2 extents:1 across:16777212k SS
+[ 7.157588] EXT4-fs (nvme0n1p6): mounted filesystem r/w with ordered data mode. Quota mode: none.
+[ 7.165021] EXT4-fs (nvme0n1p9): mounted filesystem r/w with ordered data mode. Quota mode: none.
+[ 8.036932] nvme nvme0: using unchecked data buffer
+[ 8.096023] block nvme0n1: No UUID available providing old NGUID
+
+Link: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=d5887dc6b6c054d0da3cd053afc15b7be1f45ff6
+Link: https://lore.kernel.org/all/20240422162822.3539156-1-sean.anderson@linux.dev/
+Reported-by: liaozw <hedgehog-002@163.com>
+Closes: https://bbs.deepin.org.cn/post/286300
+Reported-by: rugk <rugk+github@posteo.de>
+Closes: https://bugzilla.kernel.org/show_bug.cgi?id=208123
+Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/nvme/host/pci.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
+index 63b03a5a5b765..abd097eba6623 100644
+--- a/drivers/nvme/host/pci.c
++++ b/drivers/nvme/host/pci.c
+@@ -3654,6 +3654,9 @@ static const struct pci_device_id nvme_id_table[] = {
+ NVME_QUIRK_IGNORE_DEV_SUBNQN, },
+ { PCI_DEVICE(0x15b7, 0x5008), /* Sandisk SN530 */
+ .driver_data = NVME_QUIRK_BROKEN_MSI },
++ { PCI_DEVICE(0x15b7, 0x5009), /* Sandisk SN550 */
++ .driver_data = NVME_QUIRK_BROKEN_MSI |
++ NVME_QUIRK_NO_DEEPEST_PS },
+ { PCI_DEVICE(0x1987, 0x5012), /* Phison E12 */
+ .driver_data = NVME_QUIRK_BOGUS_NID, },
+ { PCI_DEVICE(0x1987, 0x5016), /* Phison E16 */
+--
+2.39.5
+
--- /dev/null
+From 61587d03820e1f0da6cbaec219c75b83f1fba7bb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 11 Apr 2025 12:22:46 +0100
+Subject: nvmem: core: fix bit offsets of more than one byte
+
+From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+
+[ Upstream commit 7a06ef75107799675ea6e4d73b9df37e18e352a8 ]
+
+If the NVMEM specifies a stride to access data, reading particular cell
+might require bit offset that is bigger than one byte. Rework NVMEM core
+code to support bit offsets of more than 8 bits.
+
+Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Link: https://lore.kernel.org/r/20250411112251.68002-9-srinivas.kandagatla@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/nvmem/core.c | 24 +++++++++++++++++-------
+ 1 file changed, 17 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
+index fff85bbf0ecd0..7872903c08a11 100644
+--- a/drivers/nvmem/core.c
++++ b/drivers/nvmem/core.c
+@@ -837,7 +837,9 @@ static int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_nod
+ if (addr && len == (2 * sizeof(u32))) {
+ info.bit_offset = be32_to_cpup(addr++);
+ info.nbits = be32_to_cpup(addr);
+- if (info.bit_offset >= BITS_PER_BYTE || info.nbits < 1) {
++ if (info.bit_offset >= BITS_PER_BYTE * info.bytes ||
++ info.nbits < 1 ||
++ info.bit_offset + info.nbits > BITS_PER_BYTE * info.bytes) {
+ dev_err(dev, "nvmem: invalid bits on %pOF\n", child);
+ of_node_put(child);
+ return -EINVAL;
+@@ -1630,21 +1632,29 @@ EXPORT_SYMBOL_GPL(nvmem_cell_put);
+ static void nvmem_shift_read_buffer_in_place(struct nvmem_cell_entry *cell, void *buf)
+ {
+ u8 *p, *b;
+- int i, extra, bit_offset = cell->bit_offset;
++ int i, extra, bytes_offset;
++ int bit_offset = cell->bit_offset;
+
+ p = b = buf;
+- if (bit_offset) {
++
++ bytes_offset = bit_offset / BITS_PER_BYTE;
++ b += bytes_offset;
++ bit_offset %= BITS_PER_BYTE;
++
++ if (bit_offset % BITS_PER_BYTE) {
+ /* First shift */
+- *b++ >>= bit_offset;
++ *p = *b++ >> bit_offset;
+
+ /* setup rest of the bytes if any */
+ for (i = 1; i < cell->bytes; i++) {
+ /* Get bits from next byte and shift them towards msb */
+- *p |= *b << (BITS_PER_BYTE - bit_offset);
++ *p++ |= *b << (BITS_PER_BYTE - bit_offset);
+
+- p = b;
+- *b++ >>= bit_offset;
++ *p = *b++ >> bit_offset;
+ }
++ } else if (p != b) {
++ memmove(p, b, cell->bytes - bytes_offset);
++ p += cell->bytes - 1;
+ } else {
+ /* point to the msb */
+ p += cell->bytes - 1;
+--
+2.39.5
+
--- /dev/null
+From 02b3db4f4badafd3be309f0cbe76c77716c4e507 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 11 Apr 2025 12:22:48 +0100
+Subject: nvmem: core: update raw_len if the bit reading is required
+
+From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+
+[ Upstream commit 6786484223d5705bf7f919c1e5055d478ebeec32 ]
+
+If NVMEM cell uses bit offset or specifies bit truncation, update
+raw_len manually (following the cell->bytes update), ensuring that the
+NVMEM access is still word-aligned.
+
+Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Link: https://lore.kernel.org/r/20250411112251.68002-11-srinivas.kandagatla@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/nvmem/core.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
+index 7b8c85f9e035c..e206efc29a004 100644
+--- a/drivers/nvmem/core.c
++++ b/drivers/nvmem/core.c
+@@ -594,9 +594,11 @@ static int nvmem_cell_info_to_nvmem_cell_entry_nodup(struct nvmem_device *nvmem,
+ cell->nbits = info->nbits;
+ cell->np = info->np;
+
+- if (cell->nbits)
++ if (cell->nbits) {
+ cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset,
+ BITS_PER_BYTE);
++ cell->raw_len = ALIGN(cell->bytes, nvmem->word_size);
++ }
+
+ if (!IS_ALIGNED(cell->offset, nvmem->stride)) {
+ dev_err(&nvmem->dev,
+--
+2.39.5
+
--- /dev/null
+From c68bb59e4462412e25de5bfa7d56abf7fddc307a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 11 Apr 2025 12:22:47 +0100
+Subject: nvmem: core: verify cell's raw_len
+
+From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+
+[ Upstream commit 13bcd440f2ff38cd7e42a179c223d4b833158b33 ]
+
+Check that the NVMEM cell's raw_len is a aligned to word_size. Otherwise
+Otherwise drivers might face incomplete read while accessing the last
+part of the NVMEM cell.
+
+Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Link: https://lore.kernel.org/r/20250411112251.68002-10-srinivas.kandagatla@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/nvmem/core.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
+index 7872903c08a11..7b8c85f9e035c 100644
+--- a/drivers/nvmem/core.c
++++ b/drivers/nvmem/core.c
+@@ -605,6 +605,18 @@ static int nvmem_cell_info_to_nvmem_cell_entry_nodup(struct nvmem_device *nvmem,
+ return -EINVAL;
+ }
+
++ if (!IS_ALIGNED(cell->raw_len, nvmem->word_size)) {
++ dev_err(&nvmem->dev,
++ "cell %s raw len %zd unaligned to nvmem word size %d\n",
++ cell->name ?: "<unknown>", cell->raw_len,
++ nvmem->word_size);
++
++ if (info->raw_len)
++ return -EINVAL;
++
++ cell->raw_len = ALIGN(cell->raw_len, nvmem->word_size);
++ }
++
+ return 0;
+ }
+
+--
+2.39.5
+
--- /dev/null
+From a2c90e7c892db8e698208dd025350732b0908636 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 11 Apr 2025 12:22:49 +0100
+Subject: nvmem: qfprom: switch to 4-byte aligned reads
+
+From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+
+[ Upstream commit 3566a737db87a9bf360c2fd36433c5149f805f2e ]
+
+All platforms since Snapdragon 8 Gen1 (SM8450) require using 4-byte
+reads to access QFPROM data. While older platforms were more than happy
+with 1-byte reads, change the qfprom driver to use 4-byte reads for all
+the platforms. Specify stride and word size of 4 bytes. To retain
+compatibility with the existing DT and to simplify porting data from
+vendor kernels, use fixup_dt_cell_info in order to bump alignment
+requirements.
+
+Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Link: https://lore.kernel.org/r/20250411112251.68002-12-srinivas.kandagatla@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/nvmem/qfprom.c | 26 ++++++++++++++++++++------
+ 1 file changed, 20 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/nvmem/qfprom.c b/drivers/nvmem/qfprom.c
+index 116a39e804c70..a872c640b8c5a 100644
+--- a/drivers/nvmem/qfprom.c
++++ b/drivers/nvmem/qfprom.c
+@@ -321,19 +321,32 @@ static int qfprom_reg_read(void *context,
+ unsigned int reg, void *_val, size_t bytes)
+ {
+ struct qfprom_priv *priv = context;
+- u8 *val = _val;
+- int i = 0, words = bytes;
++ u32 *val = _val;
+ void __iomem *base = priv->qfpcorrected;
++ int words = DIV_ROUND_UP(bytes, sizeof(u32));
++ int i;
+
+ if (read_raw_data && priv->qfpraw)
+ base = priv->qfpraw;
+
+- while (words--)
+- *val++ = readb(base + reg + i++);
++ for (i = 0; i < words; i++)
++ *val++ = readl(base + reg + i * sizeof(u32));
+
+ return 0;
+ }
+
++/* Align reads to word boundary */
++static void qfprom_fixup_dt_cell_info(struct nvmem_device *nvmem,
++ struct nvmem_cell_info *cell)
++{
++ unsigned int byte_offset = cell->offset % sizeof(u32);
++
++ cell->bit_offset += byte_offset * BITS_PER_BYTE;
++ cell->offset -= byte_offset;
++ if (byte_offset && !cell->nbits)
++ cell->nbits = cell->bytes * BITS_PER_BYTE;
++}
++
+ static void qfprom_runtime_disable(void *data)
+ {
+ pm_runtime_disable(data);
+@@ -358,10 +371,11 @@ static int qfprom_probe(struct platform_device *pdev)
+ struct nvmem_config econfig = {
+ .name = "qfprom",
+ .add_legacy_fixed_of_cells = true,
+- .stride = 1,
+- .word_size = 1,
++ .stride = 4,
++ .word_size = 4,
+ .id = NVMEM_DEVID_AUTO,
+ .reg_read = qfprom_reg_read,
++ .fixup_dt_cell_info = qfprom_fixup_dt_cell_info,
+ };
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+--
+2.39.5
+
--- /dev/null
+From 9e01c16adf9181e9dbc67ce094799209d7d66b42 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 11 Apr 2025 12:22:42 +0100
+Subject: nvmem: rockchip-otp: add rk3576 variant data
+
+From: Heiko Stuebner <heiko@sntech.de>
+
+[ Upstream commit 50d75a13a9ce880a5ef07a4ccc63ba561cc2e69a ]
+
+The variant works very similar to the rk3588, just with a different
+read-offset and size.
+
+Signed-off-by: Heiko Stuebner <heiko@sntech.de>
+Tested-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Link: https://lore.kernel.org/r/20250411112251.68002-5-srinivas.kandagatla@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/nvmem/rockchip-otp.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/drivers/nvmem/rockchip-otp.c b/drivers/nvmem/rockchip-otp.c
+index 3edfbfc2d7220..d88f12c532426 100644
+--- a/drivers/nvmem/rockchip-otp.c
++++ b/drivers/nvmem/rockchip-otp.c
+@@ -274,6 +274,14 @@ static const struct rockchip_data px30_data = {
+ .reg_read = px30_otp_read,
+ };
+
++static const struct rockchip_data rk3576_data = {
++ .size = 0x100,
++ .read_offset = 0x700,
++ .clks = px30_otp_clocks,
++ .num_clks = ARRAY_SIZE(px30_otp_clocks),
++ .reg_read = rk3588_otp_read,
++};
++
+ static const char * const rk3588_otp_clocks[] = {
+ "otp", "apb_pclk", "phy", "arb",
+ };
+@@ -295,6 +303,10 @@ static const struct of_device_id rockchip_otp_match[] = {
+ .compatible = "rockchip,rk3308-otp",
+ .data = &px30_data,
+ },
++ {
++ .compatible = "rockchip,rk3576-otp",
++ .data = &rk3576_data,
++ },
+ {
+ .compatible = "rockchip,rk3588-otp",
+ .data = &rk3588_data,
+--
+2.39.5
+
--- /dev/null
+From f794bdd3978ecd50923e883f3272717b9cfac22c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 11 Apr 2025 12:22:39 +0100
+Subject: nvmem: rockchip-otp: Move read-offset into variant-data
+
+From: Heiko Stuebner <heiko@sntech.de>
+
+[ Upstream commit 6907e8093b3070d877ee607e5ceede60cfd08bde ]
+
+The RK3588 has an offset into the OTP area where the readable area begins
+and automatically adds this to the start address.
+Other variants are very much similar to rk3588, just with a different
+offset, so move that value into variant-data.
+
+To match the size in bytes, store this value also in bytes and not in
+number of blocks.
+
+Signed-off-by: Heiko Stuebner <heiko@sntech.de>
+Tested-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Link: https://lore.kernel.org/r/20250411112251.68002-2-srinivas.kandagatla@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/nvmem/rockchip-otp.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/nvmem/rockchip-otp.c b/drivers/nvmem/rockchip-otp.c
+index ebc3f0b24166b..3edfbfc2d7220 100644
+--- a/drivers/nvmem/rockchip-otp.c
++++ b/drivers/nvmem/rockchip-otp.c
+@@ -59,7 +59,6 @@
+ #define RK3588_OTPC_AUTO_EN 0x08
+ #define RK3588_OTPC_INT_ST 0x84
+ #define RK3588_OTPC_DOUT0 0x20
+-#define RK3588_NO_SECURE_OFFSET 0x300
+ #define RK3588_NBYTES 4
+ #define RK3588_BURST_NUM 1
+ #define RK3588_BURST_SHIFT 8
+@@ -69,6 +68,7 @@
+
+ struct rockchip_data {
+ int size;
++ int read_offset;
+ const char * const *clks;
+ int num_clks;
+ nvmem_reg_read_t reg_read;
+@@ -196,7 +196,7 @@ static int rk3588_otp_read(void *context, unsigned int offset,
+ addr_start = round_down(offset, RK3588_NBYTES) / RK3588_NBYTES;
+ addr_end = round_up(offset + bytes, RK3588_NBYTES) / RK3588_NBYTES;
+ addr_len = addr_end - addr_start;
+- addr_start += RK3588_NO_SECURE_OFFSET;
++ addr_start += otp->data->read_offset / RK3588_NBYTES;
+
+ buf = kzalloc(array_size(addr_len, RK3588_NBYTES), GFP_KERNEL);
+ if (!buf)
+@@ -280,6 +280,7 @@ static const char * const rk3588_otp_clocks[] = {
+
+ static const struct rockchip_data rk3588_data = {
+ .size = 0x400,
++ .read_offset = 0xc00,
+ .clks = rk3588_otp_clocks,
+ .num_clks = ARRAY_SIZE(rk3588_otp_clocks),
+ .reg_read = rk3588_otp_read,
+--
+2.39.5
+
--- /dev/null
+From 79fc0c44b1c4dc306e2f89d909c56b626af2e132 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 9 May 2025 08:25:00 +0900
+Subject: nvmet: pci-epf: clear completion queue IRQ flag on delete
+
+From: Damien Le Moal <dlemoal@kernel.org>
+
+[ Upstream commit 85adf2094abb9084770dc4ab302aaa9c5d26dd2d ]
+
+The function nvmet_pci_epf_delete_cq() unconditionally calls
+nvmet_pci_epf_remove_irq_vector() even for completion queues that do not
+have interrupts enabled. Furthermore, for completion queues that do
+have IRQ enabled, deleting and re-creating the completion queue leaves
+the flag NVMET_PCI_EPF_Q_IRQ_ENABLED set, even if the completion queue
+is being re-created with IRQ disabled.
+
+Fix these issues by calling nvmet_pci_epf_remove_irq_vector() only if
+NVMET_PCI_EPF_Q_IRQ_ENABLED is set and make sure to always clear that
+flag.
+
+Fixes: 0faa0fe6f90e ("nvmet: New NVMe PCI endpoint function target driver")
+Cc: stable@vger.kernel.org
+Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/nvme/target/pci-epf.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/nvme/target/pci-epf.c b/drivers/nvme/target/pci-epf.c
+index 81957b6e84986..fbc167f47d8a6 100644
+--- a/drivers/nvme/target/pci-epf.c
++++ b/drivers/nvme/target/pci-epf.c
+@@ -1344,7 +1344,8 @@ static u16 nvmet_pci_epf_delete_cq(struct nvmet_ctrl *tctrl, u16 cqid)
+
+ cancel_delayed_work_sync(&cq->work);
+ nvmet_pci_epf_drain_queue(cq);
+- nvmet_pci_epf_remove_irq_vector(ctrl, cq->vector);
++ if (test_and_clear_bit(NVMET_PCI_EPF_Q_IRQ_ENABLED, &cq->flags))
++ nvmet_pci_epf_remove_irq_vector(ctrl, cq->vector);
+ nvmet_pci_epf_mem_unmap(ctrl->nvme_epf, &cq->pci_map);
+
+ return NVME_SC_SUCCESS;
+--
+2.39.5
+
--- /dev/null
+From 80f6ffb45100c939a8cbfaffde56ec0400becf52 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 13 Mar 2025 17:22:18 +0900
+Subject: nvmet: pci-epf: Keep completion queues mapped
+
+From: Damien Le Moal <dlemoal@kernel.org>
+
+[ Upstream commit ea7789c1541084a3dae65ffd36778348dd98f61b ]
+
+Instead of mapping and unmapping the completion queues memory to the
+host PCI address space whenever nvmet_pci_epf_cq_work() is called, map
+a completion queue to the host PCI address space when the completion
+queue is created with nvmet_pci_epf_create_cq() and unmap it when the
+completion queue is deleted with nvmet_pci_epf_delete_cq().
+
+This removes the completion queue mapping/unmapping from
+nvmet_pci_epf_cq_work() and significantly increases performance. For
+a single job 4K random read QD=1 workload, the IOPS is increased from
+23 KIOPS to 25 KIOPS. Some significant throughput increasde for high
+queue depth and large IOs workloads can also be seen.
+
+Since the functions nvmet_pci_epf_map_queue() and
+nvmet_pci_epf_unmap_queue() are called respectively only from
+nvmet_pci_epf_create_cq() and nvmet_pci_epf_delete_cq(), these functions
+are removed and open-coded in their respective call sites.
+
+Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Keith Busch <kbusch@kernel.org>
+Stable-dep-of: 85adf2094abb ("nvmet: pci-epf: clear completion queue IRQ flag on delete")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/nvme/target/pci-epf.c | 63 ++++++++++++++---------------------
+ 1 file changed, 25 insertions(+), 38 deletions(-)
+
+diff --git a/drivers/nvme/target/pci-epf.c b/drivers/nvme/target/pci-epf.c
+index bc1daa9aede9d..81957b6e84986 100644
+--- a/drivers/nvme/target/pci-epf.c
++++ b/drivers/nvme/target/pci-epf.c
+@@ -1264,6 +1264,7 @@ static u16 nvmet_pci_epf_create_cq(struct nvmet_ctrl *tctrl,
+ struct nvmet_pci_epf_ctrl *ctrl = tctrl->drvdata;
+ struct nvmet_pci_epf_queue *cq = &ctrl->cq[cqid];
+ u16 status;
++ int ret;
+
+ if (test_bit(NVMET_PCI_EPF_Q_LIVE, &cq->flags))
+ return NVME_SC_QID_INVALID | NVME_STATUS_DNR;
+@@ -1298,6 +1299,24 @@ static u16 nvmet_pci_epf_create_cq(struct nvmet_ctrl *tctrl,
+ if (status != NVME_SC_SUCCESS)
+ goto err;
+
++ /*
++ * Map the CQ PCI address space and since PCI endpoint controllers may
++ * return a partial mapping, check that the mapping is large enough.
++ */
++ ret = nvmet_pci_epf_mem_map(ctrl->nvme_epf, cq->pci_addr, cq->pci_size,
++ &cq->pci_map);
++ if (ret) {
++ dev_err(ctrl->dev, "Failed to map CQ %u (err=%d)\n",
++ cq->qid, ret);
++ goto err_internal;
++ }
++
++ if (cq->pci_map.pci_size < cq->pci_size) {
++ dev_err(ctrl->dev, "Invalid partial mapping of queue %u\n",
++ cq->qid);
++ goto err_unmap_queue;
++ }
++
+ set_bit(NVMET_PCI_EPF_Q_LIVE, &cq->flags);
+
+ dev_dbg(ctrl->dev, "CQ[%u]: %u entries of %zu B, IRQ vector %u\n",
+@@ -1305,6 +1324,10 @@ static u16 nvmet_pci_epf_create_cq(struct nvmet_ctrl *tctrl,
+
+ return NVME_SC_SUCCESS;
+
++err_unmap_queue:
++ nvmet_pci_epf_mem_unmap(ctrl->nvme_epf, &cq->pci_map);
++err_internal:
++ status = NVME_SC_INTERNAL | NVME_STATUS_DNR;
+ err:
+ if (test_and_clear_bit(NVMET_PCI_EPF_Q_IRQ_ENABLED, &cq->flags))
+ nvmet_pci_epf_remove_irq_vector(ctrl, cq->vector);
+@@ -1322,6 +1345,7 @@ static u16 nvmet_pci_epf_delete_cq(struct nvmet_ctrl *tctrl, u16 cqid)
+ cancel_delayed_work_sync(&cq->work);
+ nvmet_pci_epf_drain_queue(cq);
+ nvmet_pci_epf_remove_irq_vector(ctrl, cq->vector);
++ nvmet_pci_epf_mem_unmap(ctrl->nvme_epf, &cq->pci_map);
+
+ return NVME_SC_SUCCESS;
+ }
+@@ -1554,36 +1578,6 @@ static void nvmet_pci_epf_free_queues(struct nvmet_pci_epf_ctrl *ctrl)
+ ctrl->cq = NULL;
+ }
+
+-static int nvmet_pci_epf_map_queue(struct nvmet_pci_epf_ctrl *ctrl,
+- struct nvmet_pci_epf_queue *queue)
+-{
+- struct nvmet_pci_epf *nvme_epf = ctrl->nvme_epf;
+- int ret;
+-
+- ret = nvmet_pci_epf_mem_map(nvme_epf, queue->pci_addr,
+- queue->pci_size, &queue->pci_map);
+- if (ret) {
+- dev_err(ctrl->dev, "Failed to map queue %u (err=%d)\n",
+- queue->qid, ret);
+- return ret;
+- }
+-
+- if (queue->pci_map.pci_size < queue->pci_size) {
+- dev_err(ctrl->dev, "Invalid partial mapping of queue %u\n",
+- queue->qid);
+- nvmet_pci_epf_mem_unmap(nvme_epf, &queue->pci_map);
+- return -ENOMEM;
+- }
+-
+- return 0;
+-}
+-
+-static inline void nvmet_pci_epf_unmap_queue(struct nvmet_pci_epf_ctrl *ctrl,
+- struct nvmet_pci_epf_queue *queue)
+-{
+- nvmet_pci_epf_mem_unmap(ctrl->nvme_epf, &queue->pci_map);
+-}
+-
+ static void nvmet_pci_epf_exec_iod_work(struct work_struct *work)
+ {
+ struct nvmet_pci_epf_iod *iod =
+@@ -1749,11 +1743,7 @@ static void nvmet_pci_epf_cq_work(struct work_struct *work)
+ struct nvme_completion *cqe;
+ struct nvmet_pci_epf_iod *iod;
+ unsigned long flags;
+- int ret, n = 0;
+-
+- ret = nvmet_pci_epf_map_queue(ctrl, cq);
+- if (ret)
+- goto again;
++ int ret = 0, n = 0;
+
+ while (test_bit(NVMET_PCI_EPF_Q_LIVE, &cq->flags) && ctrl->link_up) {
+
+@@ -1809,8 +1799,6 @@ static void nvmet_pci_epf_cq_work(struct work_struct *work)
+ n++;
+ }
+
+- nvmet_pci_epf_unmap_queue(ctrl, cq);
+-
+ /*
+ * We do not support precise IRQ coalescing time (100ns units as per
+ * NVMe specifications). So if we have posted completion entries without
+@@ -1819,7 +1807,6 @@ static void nvmet_pci_epf_cq_work(struct work_struct *work)
+ if (n)
+ nvmet_pci_epf_raise_irq(ctrl, cq, true);
+
+-again:
+ if (ret < 0)
+ queue_delayed_work(system_highpri_wq, &cq->work,
+ NVMET_PCI_EPF_CQ_RETRY_INTERVAL);
+--
+2.39.5
+
--- /dev/null
+From 031ea99745f8866c58cea9cb93e2a7d53bccf37a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 23 Apr 2025 16:06:21 +1000
+Subject: nvmet-tcp: don't restore null sk_state_change
+
+From: Alistair Francis <alistair.francis@wdc.com>
+
+[ Upstream commit 46d22b47df2741996af277a2838b95f130436c13 ]
+
+queue->state_change is set as part of nvmet_tcp_set_queue_sock(), but if
+the TCP connection isn't established when nvmet_tcp_set_queue_sock() is
+called then queue->state_change isn't set and sock->sk->sk_state_change
+isn't replaced.
+
+As such we don't need to restore sock->sk->sk_state_change if
+queue->state_change is NULL.
+
+This avoids NULL pointer dereferences such as this:
+
+[ 286.462026][ C0] BUG: kernel NULL pointer dereference, address: 0000000000000000
+[ 286.462814][ C0] #PF: supervisor instruction fetch in kernel mode
+[ 286.463796][ C0] #PF: error_code(0x0010) - not-present page
+[ 286.464392][ C0] PGD 8000000140620067 P4D 8000000140620067 PUD 114201067 PMD 0
+[ 286.465086][ C0] Oops: Oops: 0010 [#1] SMP KASAN PTI
+[ 286.465559][ C0] CPU: 0 UID: 0 PID: 1628 Comm: nvme Not tainted 6.15.0-rc2+ #11 PREEMPT(voluntary)
+[ 286.466393][ C0] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.3-3.fc41 04/01/2014
+[ 286.467147][ C0] RIP: 0010:0x0
+[ 286.467420][ C0] Code: Unable to access opcode bytes at 0xffffffffffffffd6.
+[ 286.467977][ C0] RSP: 0018:ffff8883ae008580 EFLAGS: 00010246
+[ 286.468425][ C0] RAX: 0000000000000000 RBX: ffff88813fd34100 RCX: ffffffffa386cc43
+[ 286.469019][ C0] RDX: 1ffff11027fa68b6 RSI: 0000000000000008 RDI: ffff88813fd34100
+[ 286.469545][ C0] RBP: ffff88813fd34160 R08: 0000000000000000 R09: ffffed1027fa682c
+[ 286.470072][ C0] R10: ffff88813fd34167 R11: 0000000000000000 R12: ffff88813fd344c3
+[ 286.470585][ C0] R13: ffff88813fd34112 R14: ffff88813fd34aec R15: ffff888132cdd268
+[ 286.471070][ C0] FS: 00007fe3c04c7d80(0000) GS:ffff88840743f000(0000) knlGS:0000000000000000
+[ 286.471644][ C0] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[ 286.472543][ C0] CR2: ffffffffffffffd6 CR3: 000000012daca000 CR4: 00000000000006f0
+[ 286.473500][ C0] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
+[ 286.474467][ C0] DR3: 0000000000000000 DR6: 00000000ffff07f0 DR7: 0000000000000400
+[ 286.475453][ C0] Call Trace:
+[ 286.476102][ C0] <IRQ>
+[ 286.476719][ C0] tcp_fin+0x2bb/0x440
+[ 286.477429][ C0] tcp_data_queue+0x190f/0x4e60
+[ 286.478174][ C0] ? __build_skb_around+0x234/0x330
+[ 286.478940][ C0] ? rcu_is_watching+0x11/0xb0
+[ 286.479659][ C0] ? __pfx_tcp_data_queue+0x10/0x10
+[ 286.480431][ C0] ? tcp_try_undo_loss+0x640/0x6c0
+[ 286.481196][ C0] ? seqcount_lockdep_reader_access.constprop.0+0x82/0x90
+[ 286.482046][ C0] ? kvm_clock_get_cycles+0x14/0x30
+[ 286.482769][ C0] ? ktime_get+0x66/0x150
+[ 286.483433][ C0] ? rcu_is_watching+0x11/0xb0
+[ 286.484146][ C0] tcp_rcv_established+0x6e4/0x2050
+[ 286.484857][ C0] ? rcu_is_watching+0x11/0xb0
+[ 286.485523][ C0] ? ipv4_dst_check+0x160/0x2b0
+[ 286.486203][ C0] ? __pfx_tcp_rcv_established+0x10/0x10
+[ 286.486917][ C0] ? lock_release+0x217/0x2c0
+[ 286.487595][ C0] tcp_v4_do_rcv+0x4d6/0x9b0
+[ 286.488279][ C0] tcp_v4_rcv+0x2af8/0x3e30
+[ 286.488904][ C0] ? raw_local_deliver+0x51b/0xad0
+[ 286.489551][ C0] ? rcu_is_watching+0x11/0xb0
+[ 286.490198][ C0] ? __pfx_tcp_v4_rcv+0x10/0x10
+[ 286.490813][ C0] ? __pfx_raw_local_deliver+0x10/0x10
+[ 286.491487][ C0] ? __pfx_nf_confirm+0x10/0x10 [nf_conntrack]
+[ 286.492275][ C0] ? rcu_is_watching+0x11/0xb0
+[ 286.492900][ C0] ip_protocol_deliver_rcu+0x8f/0x370
+[ 286.493579][ C0] ip_local_deliver_finish+0x297/0x420
+[ 286.494268][ C0] ip_local_deliver+0x168/0x430
+[ 286.494867][ C0] ? __pfx_ip_local_deliver+0x10/0x10
+[ 286.495498][ C0] ? __pfx_ip_local_deliver_finish+0x10/0x10
+[ 286.496204][ C0] ? ip_rcv_finish_core+0x19a/0x1f20
+[ 286.496806][ C0] ? lock_release+0x217/0x2c0
+[ 286.497414][ C0] ip_rcv+0x455/0x6e0
+[ 286.497945][ C0] ? __pfx_ip_rcv+0x10/0x10
+[ 286.498550][ C0] ? rcu_is_watching+0x11/0xb0
+[ 286.499137][ C0] ? __pfx_ip_rcv_finish+0x10/0x10
+[ 286.499763][ C0] ? lock_release+0x217/0x2c0
+[ 286.500327][ C0] ? dl_scaled_delta_exec+0xd1/0x2c0
+[ 286.500922][ C0] ? __pfx_ip_rcv+0x10/0x10
+[ 286.501480][ C0] __netif_receive_skb_one_core+0x166/0x1b0
+[ 286.502173][ C0] ? __pfx___netif_receive_skb_one_core+0x10/0x10
+[ 286.502903][ C0] ? lock_acquire+0x2b2/0x310
+[ 286.503487][ C0] ? process_backlog+0x372/0x1350
+[ 286.504087][ C0] ? lock_release+0x217/0x2c0
+[ 286.504642][ C0] process_backlog+0x3b9/0x1350
+[ 286.505214][ C0] ? process_backlog+0x372/0x1350
+[ 286.505779][ C0] __napi_poll.constprop.0+0xa6/0x490
+[ 286.506363][ C0] net_rx_action+0x92e/0xe10
+[ 286.506889][ C0] ? __pfx_net_rx_action+0x10/0x10
+[ 286.507437][ C0] ? timerqueue_add+0x1f0/0x320
+[ 286.507977][ C0] ? sched_clock_cpu+0x68/0x540
+[ 286.508492][ C0] ? lock_acquire+0x2b2/0x310
+[ 286.509043][ C0] ? kvm_sched_clock_read+0xd/0x20
+[ 286.509607][ C0] ? handle_softirqs+0x1aa/0x7d0
+[ 286.510187][ C0] handle_softirqs+0x1f2/0x7d0
+[ 286.510754][ C0] ? __pfx_handle_softirqs+0x10/0x10
+[ 286.511348][ C0] ? irqtime_account_irq+0x181/0x290
+[ 286.511937][ C0] ? __dev_queue_xmit+0x85d/0x3450
+[ 286.512510][ C0] do_softirq.part.0+0x89/0xc0
+[ 286.513100][ C0] </IRQ>
+[ 286.513548][ C0] <TASK>
+[ 286.513953][ C0] __local_bh_enable_ip+0x112/0x140
+[ 286.514522][ C0] ? __dev_queue_xmit+0x85d/0x3450
+[ 286.515072][ C0] __dev_queue_xmit+0x872/0x3450
+[ 286.515619][ C0] ? nft_do_chain+0xe16/0x15b0 [nf_tables]
+[ 286.516252][ C0] ? __pfx___dev_queue_xmit+0x10/0x10
+[ 286.516817][ C0] ? selinux_ip_postroute+0x43c/0xc50
+[ 286.517433][ C0] ? __pfx_selinux_ip_postroute+0x10/0x10
+[ 286.518061][ C0] ? rcu_is_watching+0x11/0xb0
+[ 286.518606][ C0] ? ip_output+0x164/0x4a0
+[ 286.519149][ C0] ? rcu_is_watching+0x11/0xb0
+[ 286.519671][ C0] ? ip_finish_output2+0x17d5/0x1fb0
+[ 286.520258][ C0] ip_finish_output2+0xb4b/0x1fb0
+[ 286.520787][ C0] ? __pfx_ip_finish_output2+0x10/0x10
+[ 286.521355][ C0] ? __ip_finish_output+0x15d/0x750
+[ 286.521890][ C0] ip_output+0x164/0x4a0
+[ 286.522372][ C0] ? __pfx_ip_output+0x10/0x10
+[ 286.522872][ C0] ? rcu_is_watching+0x11/0xb0
+[ 286.523402][ C0] ? _raw_spin_unlock_irqrestore+0x4c/0x60
+[ 286.524031][ C0] ? __pfx_ip_finish_output+0x10/0x10
+[ 286.524605][ C0] ? __ip_queue_xmit+0x999/0x2260
+[ 286.525200][ C0] ? rcu_is_watching+0x11/0xb0
+[ 286.525744][ C0] ? ipv4_dst_check+0x16a/0x2b0
+[ 286.526279][ C0] ? lock_release+0x217/0x2c0
+[ 286.526793][ C0] __ip_queue_xmit+0x1883/0x2260
+[ 286.527324][ C0] ? __skb_clone+0x54c/0x730
+[ 286.527827][ C0] __tcp_transmit_skb+0x209b/0x37a0
+[ 286.528374][ C0] ? __pfx___tcp_transmit_skb+0x10/0x10
+[ 286.528952][ C0] ? rcu_is_watching+0x11/0xb0
+[ 286.529472][ C0] ? seqcount_lockdep_reader_access.constprop.0+0x82/0x90
+[ 286.530152][ C0] ? trace_hardirqs_on+0x12/0x120
+[ 286.530691][ C0] tcp_write_xmit+0xb81/0x88b0
+[ 286.531224][ C0] ? mod_memcg_state+0x4d/0x60
+[ 286.531736][ C0] ? rcu_is_watching+0x11/0xb0
+[ 286.532253][ C0] __tcp_push_pending_frames+0x90/0x320
+[ 286.532826][ C0] tcp_send_fin+0x141/0xb50
+[ 286.533352][ C0] ? __pfx_tcp_send_fin+0x10/0x10
+[ 286.533908][ C0] ? __local_bh_enable_ip+0xab/0x140
+[ 286.534495][ C0] inet_shutdown+0x243/0x320
+[ 286.535077][ C0] nvme_tcp_alloc_queue+0xb3b/0x2590 [nvme_tcp]
+[ 286.535709][ C0] ? do_raw_spin_lock+0x129/0x260
+[ 286.536314][ C0] ? __pfx_nvme_tcp_alloc_queue+0x10/0x10 [nvme_tcp]
+[ 286.536996][ C0] ? do_raw_spin_unlock+0x54/0x1e0
+[ 286.537550][ C0] ? _raw_spin_unlock+0x29/0x50
+[ 286.538127][ C0] ? do_raw_spin_lock+0x129/0x260
+[ 286.538664][ C0] ? __pfx_do_raw_spin_lock+0x10/0x10
+[ 286.539249][ C0] ? nvme_tcp_alloc_admin_queue+0xd5/0x340 [nvme_tcp]
+[ 286.539892][ C0] ? __wake_up+0x40/0x60
+[ 286.540392][ C0] nvme_tcp_alloc_admin_queue+0xd5/0x340 [nvme_tcp]
+[ 286.541047][ C0] ? rcu_is_watching+0x11/0xb0
+[ 286.541589][ C0] nvme_tcp_setup_ctrl+0x8b/0x7a0 [nvme_tcp]
+[ 286.542254][ C0] ? _raw_spin_unlock_irqrestore+0x4c/0x60
+[ 286.542887][ C0] ? __pfx_nvme_tcp_setup_ctrl+0x10/0x10 [nvme_tcp]
+[ 286.543568][ C0] ? trace_hardirqs_on+0x12/0x120
+[ 286.544166][ C0] ? _raw_spin_unlock_irqrestore+0x35/0x60
+[ 286.544792][ C0] ? nvme_change_ctrl_state+0x196/0x2e0 [nvme_core]
+[ 286.545477][ C0] nvme_tcp_create_ctrl+0x839/0xb90 [nvme_tcp]
+[ 286.546126][ C0] nvmf_dev_write+0x3db/0x7e0 [nvme_fabrics]
+[ 286.546775][ C0] ? rw_verify_area+0x69/0x520
+[ 286.547334][ C0] vfs_write+0x218/0xe90
+[ 286.547854][ C0] ? do_syscall_64+0x9f/0x190
+[ 286.548408][ C0] ? trace_hardirqs_on_prepare+0xdb/0x120
+[ 286.549037][ C0] ? syscall_exit_to_user_mode+0x93/0x280
+[ 286.549659][ C0] ? __pfx_vfs_write+0x10/0x10
+[ 286.550259][ C0] ? do_syscall_64+0x9f/0x190
+[ 286.550840][ C0] ? syscall_exit_to_user_mode+0x8e/0x280
+[ 286.551516][ C0] ? trace_hardirqs_on_prepare+0xdb/0x120
+[ 286.552180][ C0] ? syscall_exit_to_user_mode+0x93/0x280
+[ 286.552834][ C0] ? ksys_read+0xf5/0x1c0
+[ 286.553386][ C0] ? __pfx_ksys_read+0x10/0x10
+[ 286.553964][ C0] ksys_write+0xf5/0x1c0
+[ 286.554499][ C0] ? __pfx_ksys_write+0x10/0x10
+[ 286.555072][ C0] ? trace_hardirqs_on_prepare+0xdb/0x120
+[ 286.555698][ C0] ? syscall_exit_to_user_mode+0x93/0x280
+[ 286.556319][ C0] ? do_syscall_64+0x54/0x190
+[ 286.556866][ C0] do_syscall_64+0x93/0x190
+[ 286.557420][ C0] ? rcu_read_unlock+0x17/0x60
+[ 286.557986][ C0] ? rcu_is_watching+0x11/0xb0
+[ 286.558526][ C0] ? lock_release+0x217/0x2c0
+[ 286.559087][ C0] ? rcu_is_watching+0x11/0xb0
+[ 286.559659][ C0] ? count_memcg_events.constprop.0+0x4a/0x60
+[ 286.560476][ C0] ? exc_page_fault+0x7a/0x110
+[ 286.561064][ C0] ? rcu_is_watching+0x11/0xb0
+[ 286.561647][ C0] ? lock_release+0x217/0x2c0
+[ 286.562257][ C0] ? do_user_addr_fault+0x171/0xa00
+[ 286.562839][ C0] ? do_user_addr_fault+0x4a2/0xa00
+[ 286.563453][ C0] ? irqentry_exit_to_user_mode+0x84/0x270
+[ 286.564112][ C0] ? rcu_is_watching+0x11/0xb0
+[ 286.564677][ C0] ? irqentry_exit_to_user_mode+0x84/0x270
+[ 286.565317][ C0] ? trace_hardirqs_on_prepare+0xdb/0x120
+[ 286.565922][ C0] entry_SYSCALL_64_after_hwframe+0x76/0x7e
+[ 286.566542][ C0] RIP: 0033:0x7fe3c05e6504
+[ 286.567102][ C0] Code: c7 00 16 00 00 00 b8 ff ff ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 f3 0f 1e fa 80 3d c5 8b 10 00 00 74 13 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 54 c3 0f 1f 00 55 48 89 e5 48 83 ec 20 48 89
+[ 286.568931][ C0] RSP: 002b:00007fff76444f58 EFLAGS: 00000202 ORIG_RAX: 0000000000000001
+[ 286.569807][ C0] RAX: ffffffffffffffda RBX: 000000003b40d930 RCX: 00007fe3c05e6504
+[ 286.570621][ C0] RDX: 00000000000000cf RSI: 000000003b40d930 RDI: 0000000000000003
+[ 286.571443][ C0] RBP: 0000000000000003 R08: 00000000000000cf R09: 000000003b40d930
+[ 286.572246][ C0] R10: 0000000000000000 R11: 0000000000000202 R12: 000000003b40cd60
+[ 286.573069][ C0] R13: 00000000000000cf R14: 00007fe3c07417f8 R15: 00007fe3c073502e
+[ 286.573886][ C0] </TASK>
+
+Closes: https://lore.kernel.org/linux-nvme/5hdonndzoqa265oq3bj6iarwtfk5dewxxjtbjvn5uqnwclpwt6@a2n6w3taxxex/
+Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
+Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
+Tested-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/nvme/target/tcp.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
+index 4f9cac8a5abe0..259ad77c03c50 100644
+--- a/drivers/nvme/target/tcp.c
++++ b/drivers/nvme/target/tcp.c
+@@ -1560,6 +1560,9 @@ static void nvmet_tcp_restore_socket_callbacks(struct nvmet_tcp_queue *queue)
+ {
+ struct socket *sock = queue->sock;
+
++ if (!queue->state_change)
++ return;
++
+ write_lock_bh(&sock->sk->sk_callback_lock);
+ sock->sk->sk_data_ready = queue->data_ready;
+ sock->sk->sk_state_change = queue->state_change;
+--
+2.39.5
+
--- /dev/null
+From 8c5fc31078ea90f0d8b57af1b352fd5119c4fd1d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 14 Mar 2025 12:29:00 -0700
+Subject: objtool: Fix error handling inconsistencies in check()
+
+From: Josh Poimboeuf <jpoimboe@kernel.org>
+
+[ Upstream commit b745962cb97569aad026806bb0740663cf813147 ]
+
+Make sure all fatal errors are funneled through the 'out' label with a
+negative ret.
+
+Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Reviewed-by: Brendan Jackman <jackmanb@google.com>
+Link: https://lore.kernel.org/r/0f49d6a27a080b4012e84e6df1e23097f44cc082.1741975349.git.jpoimboe@kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/objtool/check.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/tools/objtool/check.c b/tools/objtool/check.c
+index 522ae26f581be..70f5b3fa587c5 100644
+--- a/tools/objtool/check.c
++++ b/tools/objtool/check.c
+@@ -4633,8 +4633,10 @@ int check(struct objtool_file *file)
+ init_cfi_state(&force_undefined_cfi);
+ force_undefined_cfi.force_undefined = true;
+
+- if (!cfi_hash_alloc(1UL << (file->elf->symbol_bits - 3)))
++ if (!cfi_hash_alloc(1UL << (file->elf->symbol_bits - 3))) {
++ ret = -1;
+ goto out;
++ }
+
+ cfi_hash_add(&init_cfi);
+ cfi_hash_add(&func_cfi);
+@@ -4651,7 +4653,7 @@ int check(struct objtool_file *file)
+ if (opts.retpoline) {
+ ret = validate_retpoline(file);
+ if (ret < 0)
+- return ret;
++ goto out;
+ warnings += ret;
+ }
+
+@@ -4687,7 +4689,7 @@ int check(struct objtool_file *file)
+ */
+ ret = validate_unrets(file);
+ if (ret < 0)
+- return ret;
++ goto out;
+ warnings += ret;
+ }
+
+@@ -4750,7 +4752,7 @@ int check(struct objtool_file *file)
+ if (opts.prefix) {
+ ret = add_prefix_symbols(file);
+ if (ret < 0)
+- return ret;
++ goto out;
+ warnings += ret;
+ }
+
+--
+2.39.5
+
--- /dev/null
+From 110b1fc10c00543d827ba11ed739f1b44c72d50b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 24 Mar 2025 14:55:58 -0700
+Subject: objtool: Properly disable uaccess validation
+
+From: Josh Poimboeuf <jpoimboe@kernel.org>
+
+[ Upstream commit e1a9dda74dbffbc3fa2069ff418a1876dc99fb14 ]
+
+If opts.uaccess isn't set, the uaccess validation is disabled, but only
+partially: it doesn't read the uaccess_safe_builtin list but still tries
+to do the validation. Disable it completely to prevent false warnings.
+
+Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Link: https://lore.kernel.org/r/0e95581c1d2107fb5f59418edf2b26bba38b0cbb.1742852846.git.jpoimboe@kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/objtool/check.c | 11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+diff --git a/tools/objtool/check.c b/tools/objtool/check.c
+index a7dcf2d00ab65..522ae26f581be 100644
+--- a/tools/objtool/check.c
++++ b/tools/objtool/check.c
+@@ -3209,7 +3209,7 @@ static int handle_insn_ops(struct instruction *insn,
+ if (update_cfi_state(insn, next_insn, &state->cfi, op))
+ return 1;
+
+- if (!insn->alt_group)
++ if (!opts.uaccess || !insn->alt_group)
+ continue;
+
+ if (op->dest.type == OP_DEST_PUSHF) {
+@@ -3676,6 +3676,9 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
+ return 0;
+
+ case INSN_STAC:
++ if (!opts.uaccess)
++ break;
++
+ if (state.uaccess) {
+ WARN_INSN(insn, "recursive UACCESS enable");
+ return 1;
+@@ -3685,6 +3688,9 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
+ break;
+
+ case INSN_CLAC:
++ if (!opts.uaccess)
++ break;
++
+ if (!state.uaccess && func) {
+ WARN_INSN(insn, "redundant UACCESS disable");
+ return 1;
+@@ -4160,7 +4166,8 @@ static int validate_symbol(struct objtool_file *file, struct section *sec,
+ if (!insn || insn->ignore || insn->visited)
+ return 0;
+
+- state->uaccess = sym->uaccess_safe;
++ if (opts.uaccess)
++ state->uaccess = sym->uaccess_safe;
+
+ ret = validate_branch(file, insn_func(insn), insn, *state);
+ if (ret)
+--
+2.39.5
+
--- /dev/null
+From 7c7472a0e17f7f613f9ee3a5260a0be5ac74722d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 24 Feb 2025 09:26:03 +0530
+Subject: Octeontx2-af: RPM: Register driver with PCI subsys IDs
+
+From: Hariprasad Kelam <hkelam@marvell.com>
+
+[ Upstream commit fc9167192f29485be5621e2e9c8208b717b65753 ]
+
+Although the PCI device ID and Vendor ID for the RPM (MAC) block
+have remained the same across Octeon CN10K and the next-generation
+CN20K silicon, Hardware architecture has changed (NIX mapped RPMs
+and RFOE Mapped RPMs).
+
+Add PCI Subsystem IDs to the device table to ensure that this driver
+can be probed from NIX mapped RPM devices only.
+
+Signed-off-by: Hariprasad Kelam <hkelam@marvell.com>
+Link: https://patch.msgid.link/20250224035603.1220913-1-hkelam@marvell.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/marvell/octeontx2/af/cgx.c | 14 ++++++++++++--
+ drivers/net/ethernet/marvell/octeontx2/af/rvu.h | 2 ++
+ 2 files changed, 14 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
+index e43c4608d3ba3..971993586fb49 100644
+--- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
++++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
+@@ -66,8 +66,18 @@ static int cgx_fwi_link_change(struct cgx *cgx, int lmac_id, bool en);
+ /* Supported devices */
+ static const struct pci_device_id cgx_id_table[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_OCTEONTX2_CGX) },
+- { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CN10K_RPM) },
+- { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CN10KB_RPM) },
++ { PCI_DEVICE_SUB(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CN10K_RPM,
++ PCI_ANY_ID, PCI_SUBSYS_DEVID_CN10K_A) },
++ { PCI_DEVICE_SUB(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CN10K_RPM,
++ PCI_ANY_ID, PCI_SUBSYS_DEVID_CNF10K_A) },
++ { PCI_DEVICE_SUB(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CN10K_RPM,
++ PCI_ANY_ID, PCI_SUBSYS_DEVID_CNF10K_B) },
++ { PCI_DEVICE_SUB(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CN10KB_RPM,
++ PCI_ANY_ID, PCI_SUBSYS_DEVID_CN10K_B) },
++ { PCI_DEVICE_SUB(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CN10KB_RPM,
++ PCI_ANY_ID, PCI_SUBSYS_DEVID_CN20KA) },
++ { PCI_DEVICE_SUB(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CN10KB_RPM,
++ PCI_ANY_ID, PCI_SUBSYS_DEVID_CNF20KA) },
+ { 0, } /* end of table */
+ };
+
+diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
+index a383b5ef5b2d8..60f085b00a8cc 100644
+--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
+@@ -30,6 +30,8 @@
+ #define PCI_SUBSYS_DEVID_CNF10K_A 0xBA00
+ #define PCI_SUBSYS_DEVID_CNF10K_B 0xBC00
+ #define PCI_SUBSYS_DEVID_CN10K_B 0xBD00
++#define PCI_SUBSYS_DEVID_CN20KA 0xC220
++#define PCI_SUBSYS_DEVID_CNF20KA 0xC320
+
+ /* PCI BAR nos */
+ #define PCI_AF_REG_BAR_NUM 0
+--
+2.39.5
+
--- /dev/null
+From bd50263d29bd1d2cc7804570957f59ac87a60aab Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Mar 2025 20:47:25 +0000
+Subject: orangefs: Do not truncate file size
+
+From: Matthew Wilcox (Oracle) <willy@infradead.org>
+
+[ Upstream commit 062e8093592fb866b8e016641a8b27feb6ac509d ]
+
+'len' is used to store the result of i_size_read(), so making 'len'
+a size_t results in truncation to 4GiB on 32-bit systems.
+
+Signed-off-by: "Matthew Wilcox (Oracle)" <willy@infradead.org>
+Link: https://lore.kernel.org/r/20250305204734.1475264-2-willy@infradead.org
+Tested-by: Mike Marshall <hubcap@omnibond.com>
+Signed-off-by: Christian Brauner <brauner@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/orangefs/inode.c | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c
+index aae6d2b8767df..63d7c1ca0dfd3 100644
+--- a/fs/orangefs/inode.c
++++ b/fs/orangefs/inode.c
+@@ -23,9 +23,9 @@ static int orangefs_writepage_locked(struct page *page,
+ struct orangefs_write_range *wr = NULL;
+ struct iov_iter iter;
+ struct bio_vec bv;
+- size_t len, wlen;
++ size_t wlen;
+ ssize_t ret;
+- loff_t off;
++ loff_t len, off;
+
+ set_page_writeback(page);
+
+@@ -91,8 +91,7 @@ static int orangefs_writepages_work(struct orangefs_writepages *ow,
+ struct orangefs_write_range *wrp, wr;
+ struct iov_iter iter;
+ ssize_t ret;
+- size_t len;
+- loff_t off;
++ loff_t len, off;
+ int i;
+
+ len = i_size_read(inode);
+--
+2.39.5
+
--- /dev/null
+From e4243d31cf3079f0b67dcdd4e50c2b586e50fb28 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 24 Feb 2025 10:35:56 +0200
+Subject: PCI: brcmstb: Add a softdep to MIP MSI-X driver
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Stanimir Varbanov <svarbanov@suse.de>
+
+[ Upstream commit 2294059118c550464dd8906286324d90c33b152b ]
+
+Then the brcmstb PCIe driver and MIP MSI-X interrupt controller
+drivers are built as modules there could be a race in probing.
+
+To avoid this, add a softdep to MIP driver to guarantee that
+MIP driver will be load first.
+
+Signed-off-by: Stanimir Varbanov <svarbanov@suse.de>
+Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
+Tested-by: Ivan T. Ivanov <iivanov@suse.de>
+Link: https://lore.kernel.org/r/20250224083559.47645-5-svarbanov@suse.de
+[kwilczynski: commit log]
+Signed-off-by: Krzysztof Wilczyński <kwilczynski@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/controller/pcie-brcmstb.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c
+index ff217a0b80ad3..bae226c779a50 100644
+--- a/drivers/pci/controller/pcie-brcmstb.c
++++ b/drivers/pci/controller/pcie-brcmstb.c
+@@ -1947,3 +1947,4 @@ module_platform_driver(brcm_pcie_driver);
+ MODULE_LICENSE("GPL");
+ MODULE_DESCRIPTION("Broadcom STB PCIe RC driver");
+ MODULE_AUTHOR("Broadcom");
++MODULE_SOFTDEP("pre: irq_bcm2712_mip");
+--
+2.39.5
+
--- /dev/null
+From 844b5ac3b277a8104143d152ad3fcbd0e055ec1e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 24 Feb 2025 10:35:58 +0200
+Subject: PCI: brcmstb: Expand inbound window size up to 64GB
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Stanimir Varbanov <svarbanov@suse.de>
+
+[ Upstream commit 25a98c727015638baffcfa236e3f37b70cedcf87 ]
+
+The BCM2712 memory map can support up to 64GB of system memory, thus
+expand the inbound window size in calculation helper function.
+
+The change is safe for the currently supported SoCs that have smaller
+inbound window sizes.
+
+Signed-off-by: Stanimir Varbanov <svarbanov@suse.de>
+Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
+Reviewed-by: Jim Quinlan <james.quinlan@broadcom.com>
+Tested-by: Ivan T. Ivanov <iivanov@suse.de>
+Link: https://lore.kernel.org/r/20250224083559.47645-7-svarbanov@suse.de
+[kwilczynski: commit log]
+Signed-off-by: Krzysztof Wilczyński <kwilczynski@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/controller/pcie-brcmstb.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c
+index 1a3bdc01b0747..ff217a0b80ad3 100644
+--- a/drivers/pci/controller/pcie-brcmstb.c
++++ b/drivers/pci/controller/pcie-brcmstb.c
+@@ -309,8 +309,8 @@ static int brcm_pcie_encode_ibar_size(u64 size)
+ if (log2_in >= 12 && log2_in <= 15)
+ /* Covers 4KB to 32KB (inclusive) */
+ return (log2_in - 12) + 0x1c;
+- else if (log2_in >= 16 && log2_in <= 35)
+- /* Covers 64KB to 32GB, (inclusive) */
++ else if (log2_in >= 16 && log2_in <= 36)
++ /* Covers 64KB to 64GB, (inclusive) */
+ return log2_in - 15;
+ /* Something is awry so disable */
+ return 0;
+--
+2.39.5
+
--- /dev/null
+From ac6857755f3ae8e38c6ec0f31e055602598afea0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 15 Mar 2025 15:15:46 -0500
+Subject: PCI: dwc: ep: Ensure proper iteration over outbound map windows
+
+From: Frank Li <Frank.Li@nxp.com>
+
+[ Upstream commit f3e1dccba0a0833fc9a05fb838ebeb6ea4ca0e1a ]
+
+Most systems' PCIe outbound map windows have non-zero physical addresses,
+but the possibility of encountering zero increased after following commit
+("PCI: dwc: Use parent_bus_offset").
+
+'ep->outbound_addr[n]', representing 'parent_bus_address', might be 0 on
+some hardware, which trims high address bits through bus fabric before
+sending to the PCIe controller.
+
+Replace the iteration logic with 'for_each_set_bit()' to ensure only
+allocated map windows are iterated when determining the ATU index from a
+given address.
+
+Link: https://lore.kernel.org/r/20250315201548.858189-12-helgaas@kernel.org
+Signed-off-by: Frank Li <Frank.Li@nxp.com>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/controller/dwc/pcie-designware-ep.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
+index e41479a9ca027..c91d095024689 100644
+--- a/drivers/pci/controller/dwc/pcie-designware-ep.c
++++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
+@@ -282,7 +282,7 @@ static int dw_pcie_find_index(struct dw_pcie_ep *ep, phys_addr_t addr,
+ u32 index;
+ struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+
+- for (index = 0; index < pci->num_ob_windows; index++) {
++ for_each_set_bit(index, ep->ob_window_map, pci->num_ob_windows) {
+ if (ep->outbound_addr[index] != addr)
+ continue;
+ *atu_index = index;
+--
+2.39.5
+
--- /dev/null
+From 8108cc60f1fa7f21eab45ac23f33a8f9898e5714 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 15 Mar 2025 15:15:36 -0500
+Subject: PCI: dwc: Use resource start as ioremap() input in
+ dw_pcie_pme_turn_off()
+
+From: Frank Li <Frank.Li@nxp.com>
+
+[ Upstream commit 8f4a489b370e6612700aa16b9e4373b2d85d7503 ]
+
+The msg_res region translates writes into PCIe Message TLPs. Previously we
+mapped this region using atu.cpu_addr, the input address programmed into
+the ATU.
+
+"cpu_addr" is a misnomer because when a bus fabric translates addresses
+between the CPU and the ATU, the ATU input address is different from the
+CPU address. A future patch will rename "cpu_addr" and correct the value
+to be the ATU input address instead of the CPU physical address.
+
+Map the msg_res region before writing to it using the msg_res resource
+start, a CPU physical address.
+
+Link: https://lore.kernel.org/r/20250315201548.858189-2-helgaas@kernel.org
+Signed-off-by: Frank Li <Frank.Li@nxp.com>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/controller/dwc/pcie-designware-host.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
+index ffaded8f2df7b..ae3fd2a5dbf85 100644
+--- a/drivers/pci/controller/dwc/pcie-designware-host.c
++++ b/drivers/pci/controller/dwc/pcie-designware-host.c
+@@ -908,7 +908,7 @@ static int dw_pcie_pme_turn_off(struct dw_pcie *pci)
+ if (ret)
+ return ret;
+
+- mem = ioremap(atu.cpu_addr, pci->region_align);
++ mem = ioremap(pci->pp.msg_res->start, pci->region_align);
+ if (!mem)
+ return -ENOMEM;
+
+--
+2.39.5
+
--- /dev/null
+From d7478a4d98e5ee10d49b16779d3c100ec09bbc90 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 24 Jan 2025 13:30:43 +0100
+Subject: PCI: endpoint: pci-epf-test: Fix double free that causes kernel to
+ oops
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Christian Bruel <christian.bruel@foss.st.com>
+
+[ Upstream commit 934e9d137d937706004c325fa1474f9e3f1ba10a ]
+
+Fix a kernel oops found while testing the stm32_pcie Endpoint driver
+with handling of PERST# deassertion:
+
+During EP initialization, pci_epf_test_alloc_space() allocates all BARs,
+which are further freed if epc_set_bar() fails (for instance, due to no
+free inbound window).
+
+However, when pci_epc_set_bar() fails, the error path:
+
+ pci_epc_set_bar() ->
+ pci_epf_free_space()
+
+does not clear the previous assignment to epf_test->reg[bar].
+
+Then, if the host reboots, the PERST# deassertion restarts the BAR
+allocation sequence with the same allocation failure (no free inbound
+window), creating a double free situation since epf_test->reg[bar] was
+deallocated and is still non-NULL.
+
+Thus, make sure that pci_epf_alloc_space() and pci_epf_free_space()
+invocations are symmetric, and as such, set epf_test->reg[bar] to NULL
+when memory is freed.
+
+Reviewed-by: Niklas Cassel <cassel@kernel.org>
+Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+Signed-off-by: Christian Bruel <christian.bruel@foss.st.com>
+Link: https://lore.kernel.org/r/20250124123043.96112-1-christian.bruel@foss.st.com
+[kwilczynski: commit log]
+Signed-off-by: Krzysztof Wilczyński <kwilczynski@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/endpoint/functions/pci-epf-test.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
+index 2409787cf56d9..bce3ae2c0f652 100644
+--- a/drivers/pci/endpoint/functions/pci-epf-test.c
++++ b/drivers/pci/endpoint/functions/pci-epf-test.c
+@@ -738,6 +738,7 @@ static int pci_epf_test_set_bar(struct pci_epf *epf)
+ if (ret) {
+ pci_epf_free_space(epf, epf_test->reg[bar], bar,
+ PRIMARY_INTERFACE);
++ epf_test->reg[bar] = NULL;
+ dev_err(dev, "Failed to set BAR%d\n", bar);
+ if (bar == test_reg_bar)
+ return ret;
+@@ -929,6 +930,7 @@ static void pci_epf_test_free_space(struct pci_epf *epf)
+
+ pci_epf_free_space(epf, epf_test->reg[bar], bar,
+ PRIMARY_INTERFACE);
++ epf_test->reg[bar] = NULL;
+ }
+ }
+
+--
+2.39.5
+
--- /dev/null
+From e07b054b70c6932ae139698a8660be2f44c8e78a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 5 Dec 2024 12:24:20 +0530
+Subject: PCI: epf-mhi: Update device ID for SA8775P
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Mrinmay Sarkar <quic_msarkar@quicinc.com>
+
+[ Upstream commit 4f13dd9e2b1d2b317bb36704f8a7bd1d3017f7a2 ]
+
+Update device ID for the Qcom SA8775P SoC.
+
+Signed-off-by: Mrinmay Sarkar <quic_msarkar@quicinc.com>
+Link: https://lore.kernel.org/r/20241205065422.2515086-3-quic_msarkar@quicinc.com
+[kwilczynski: commit log]
+Signed-off-by: Krzysztof Wilczyński <kwilczynski@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/endpoint/functions/pci-epf-mhi.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/pci/endpoint/functions/pci-epf-mhi.c b/drivers/pci/endpoint/functions/pci-epf-mhi.c
+index 54286a40bdfbf..6643a88c7a0ce 100644
+--- a/drivers/pci/endpoint/functions/pci-epf-mhi.c
++++ b/drivers/pci/endpoint/functions/pci-epf-mhi.c
+@@ -125,7 +125,7 @@ static const struct pci_epf_mhi_ep_info sm8450_info = {
+
+ static struct pci_epf_header sa8775p_header = {
+ .vendorid = PCI_VENDOR_ID_QCOM,
+- .deviceid = 0x0306, /* FIXME: Update deviceid for sa8775p EP */
++ .deviceid = 0x0116,
+ .baseclass_code = PCI_CLASS_OTHERS,
+ .interrupt_pin = PCI_INTERRUPT_INTA,
+ };
+--
+2.39.5
+
--- /dev/null
+From 5c3bb987449ca5bf7a7a674cbe0482d699692ed7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 16 Dec 2024 19:56:12 +0200
+Subject: PCI: Fix old_size lower bound in calculate_iosize() too
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+
+[ Upstream commit ff61f380de5652e723168341480cc7adf1dd6213 ]
+
+Commit 903534fa7d30 ("PCI: Fix resource double counting on remove &
+rescan") fixed double counting of mem resources because of old_size being
+applied too early.
+
+Fix a similar counting bug on the io resource side.
+
+Link: https://lore.kernel.org/r/20241216175632.4175-6-ilpo.jarvinen@linux.intel.com
+Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Tested-by: Xiaochun Lee <lixc17@lenovo.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/setup-bus.c | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
+index 8707c5b08cf34..477eb07bfbca9 100644
+--- a/drivers/pci/setup-bus.c
++++ b/drivers/pci/setup-bus.c
+@@ -814,11 +814,9 @@ static resource_size_t calculate_iosize(resource_size_t size,
+ size = (size & 0xff) + ((size & ~0xffUL) << 2);
+ #endif
+ size = size + size1;
+- if (size < old_size)
+- size = old_size;
+
+- size = ALIGN(max(size, add_size) + children_add_size, align);
+- return size;
++ size = max(size, add_size) + children_add_size;
++ return ALIGN(max(size, old_size), align);
+ }
+
+ static resource_size_t calculate_memsize(resource_size_t size,
+--
+2.39.5
+
--- /dev/null
+From 8dbfe01e42616bb68faef98252c74b2ad2f200f5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Jan 2025 19:39:12 +0530
+Subject: PCI/pwrctrl: Move pci_pwrctrl_unregister() to pci_destroy_dev()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+
+[ Upstream commit 2d923930f2e3fe1ecf060169f57980da819a191f ]
+
+The PCI core will try to access the devices even after pci_stop_dev()
+for things like Data Object Exchange (DOE), ASPM, etc.
+
+So, move pci_pwrctrl_unregister() to the near end of pci_destroy_dev()
+to make sure that the devices are powered down only after the PCI core
+is done with them.
+
+Suggested-by: Lukas Wunner <lukas@wunner.de>
+Reviewed-by: Lukas Wunner <lukas@wunner.de>
+Tested-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+Link: https://lore.kernel.org/r/20250116-pci-pwrctrl-slot-v3-2-827473c8fbf4@linaro.org
+[kwilczynski: commit log]
+Signed-off-by: Krzysztof Wilczyński <kwilczynski@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/remove.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
+index efc37fcb73e24..58859f9d92f73 100644
+--- a/drivers/pci/remove.c
++++ b/drivers/pci/remove.c
+@@ -41,7 +41,6 @@ static void pci_stop_dev(struct pci_dev *dev)
+ if (!pci_dev_test_and_clear_added(dev))
+ return;
+
+- pci_pwrctrl_unregister(&dev->dev);
+ device_release_driver(&dev->dev);
+ pci_proc_detach_device(dev);
+ pci_remove_sysfs_dev_files(dev);
+@@ -64,6 +63,7 @@ static void pci_destroy_dev(struct pci_dev *dev)
+ pci_doe_destroy(dev);
+ pcie_aspm_exit_link_state(dev);
+ pci_bridge_d3_update(dev);
++ pci_pwrctrl_unregister(&dev->dev);
+ pci_free_resources(dev);
+ put_device(&dev->dev);
+ }
+--
+2.39.5
+
--- /dev/null
+From a2f79b01e008c0f475e968cf506c35348383b328 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 19 Feb 2025 10:20:56 +0100
+Subject: PCI: vmd: Disable MSI remapping bypass under Xen
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Roger Pau Monne <roger.pau@citrix.com>
+
+[ Upstream commit 6c4d5aadf5df31ea0ac025980670eee9beaf466b ]
+
+MSI remapping bypass (directly configuring MSI entries for devices on the
+VMD bus) won't work under Xen, as Xen is not aware of devices in such bus,
+and hence cannot configure the entries using the pIRQ interface in the PV
+case, and in the PVH case traps won't be setup for MSI entries for such
+devices.
+
+Until Xen is aware of devices in the VMD bus prevent the
+VMD_FEAT_CAN_BYPASS_MSI_REMAP capability from being used when running as
+any kind of Xen guest.
+
+The MSI remapping bypass is an optional feature of VMD bridges, and hence
+when running under Xen it will be masked and devices will be forced to
+redirect its interrupts from the VMD bridge. That mode of operation must
+always be supported by VMD bridges and works when Xen is not aware of
+devices behind the VMD bridge.
+
+Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
+Acked-by: Bjorn Helgaas <bhelgaas@google.com>
+Message-ID: <20250219092059.90850-3-roger.pau@citrix.com>
+Signed-off-by: Juergen Gross <jgross@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/controller/vmd.c | 20 ++++++++++++++++++++
+ 1 file changed, 20 insertions(+)
+
+diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c
+index 94ceec50a2b94..8df064b62a2ff 100644
+--- a/drivers/pci/controller/vmd.c
++++ b/drivers/pci/controller/vmd.c
+@@ -17,6 +17,8 @@
+ #include <linux/rculist.h>
+ #include <linux/rcupdate.h>
+
++#include <xen/xen.h>
++
+ #include <asm/irqdomain.h>
+
+ #define VMD_CFGBAR 0
+@@ -970,6 +972,24 @@ static int vmd_probe(struct pci_dev *dev, const struct pci_device_id *id)
+ struct vmd_dev *vmd;
+ int err;
+
++ if (xen_domain()) {
++ /*
++ * Xen doesn't have knowledge about devices in the VMD bus
++ * because the config space of devices behind the VMD bridge is
++ * not known to Xen, and hence Xen cannot discover or configure
++ * them in any way.
++ *
++ * Bypass of MSI remapping won't work in that case as direct
++ * write by Linux to the MSI entries won't result in functional
++ * interrupts, as Xen is the entity that manages the host
++ * interrupt controller and must configure interrupts. However
++ * multiplexing of interrupts by the VMD bridge will work under
++ * Xen, so force the usage of that mode which must always be
++ * supported by VMD bridges.
++ */
++ features &= ~VMD_FEAT_CAN_BYPASS_MSI_REMAP;
++ }
++
+ if (resource_size(&dev->resource[VMD_CFGBAR]) < (1 << 20))
+ return -ENOMEM;
+
+--
+2.39.5
+
--- /dev/null
+From 00e35dd69cd5a9e740726e89b57cebae94d365e2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 17 Mar 2025 18:11:36 +0530
+Subject: PCI: xilinx-cpm: Add cpm_csr register mapping for CPM5_HOST1 variant
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Thippeswamy Havalige <thippeswamy.havalige@amd.com>
+
+[ Upstream commit 9e141923cf86b2e1c83d21b87fb4de3d14a20c99 ]
+
+Update the CPM5 check to include CPM5_HOST1 variant. Previously, only
+CPM5 was considered when mapping the "cpm_csr" register.
+
+With this change, CPM5_HOST1 is also supported, ensuring proper
+resource mapping for this variant.
+
+Signed-off-by: Thippeswamy Havalige <thippeswamy.havalige@amd.com>
+[kwilczynski: commit log]
+Signed-off-by: Krzysztof Wilczyński <kwilczynski@kernel.org>
+Link: https://lore.kernel.org/r/20250317124136.1317723-1-thippeswamy.havalige@amd.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/controller/pcie-xilinx-cpm.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/pci/controller/pcie-xilinx-cpm.c b/drivers/pci/controller/pcie-xilinx-cpm.c
+index dc8ecdbee56c8..163d805673d6d 100644
+--- a/drivers/pci/controller/pcie-xilinx-cpm.c
++++ b/drivers/pci/controller/pcie-xilinx-cpm.c
+@@ -538,7 +538,8 @@ static int xilinx_cpm_pcie_parse_dt(struct xilinx_cpm_pcie *port,
+ if (IS_ERR(port->cfg))
+ return PTR_ERR(port->cfg);
+
+- if (port->variant->version == CPM5) {
++ if (port->variant->version == CPM5 ||
++ port->variant->version == CPM5_HOST1) {
+ port->reg_base = devm_platform_ioremap_resource_byname(pdev,
+ "cpm_csr");
+ if (IS_ERR(port->reg_base))
+--
+2.39.5
+
--- /dev/null
+From 6101a045693ad3129315a076bfd4721c75e0c533 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 15 Jan 2025 05:44:32 +0000
+Subject: perf/amd/ibs: Fix ->config to sample period calculation for OP PMU
+
+From: Ravi Bangoria <ravi.bangoria@amd.com>
+
+[ Upstream commit 598bdf4fefff5af4ce6d26d16f7b2a20808fc4cb ]
+
+Instead of using standard perf_event_attr->freq=0 and ->sample_period
+fields, IBS event in 'sample period mode' can also be opened by setting
+period value directly in perf_event_attr->config in a MaxCnt bit-field
+format.
+
+IBS OP MaxCnt bits are defined as:
+
+ (high bits) IbsOpCtl[26:20] = IbsOpMaxCnt[26:20]
+ (low bits) IbsOpCtl[15:0] = IbsOpMaxCnt[19:4]
+
+Perf event sample period can be derived from MaxCnt bits as:
+
+ sample_period = (high bits) | ((low_bits) << 4);
+
+However, current code just masks MaxCnt bits and shifts all of them,
+including high bits, which is incorrect. Fix it.
+
+Signed-off-by: Ravi Bangoria <ravi.bangoria@amd.com>
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Acked-by: Namhyung Kim <namhyung@kernel.org>
+Link: https://lkml.kernel.org/r/20250115054438.1021-4-ravi.bangoria@amd.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/events/amd/ibs.c | 17 +++++++++++++----
+ 1 file changed, 13 insertions(+), 4 deletions(-)
+
+diff --git a/arch/x86/events/amd/ibs.c b/arch/x86/events/amd/ibs.c
+index 5d975c39701cb..58ad23205d59d 100644
+--- a/arch/x86/events/amd/ibs.c
++++ b/arch/x86/events/amd/ibs.c
+@@ -274,7 +274,7 @@ static int perf_ibs_init(struct perf_event *event)
+ {
+ struct hw_perf_event *hwc = &event->hw;
+ struct perf_ibs *perf_ibs;
+- u64 max_cnt, config;
++ u64 config;
+ int ret;
+
+ perf_ibs = get_ibs_pmu(event->attr.type);
+@@ -321,10 +321,19 @@ static int perf_ibs_init(struct perf_event *event)
+ if (!hwc->sample_period)
+ hwc->sample_period = 0x10;
+ } else {
+- max_cnt = config & perf_ibs->cnt_mask;
++ u64 period = 0;
++
++ if (perf_ibs == &perf_ibs_op) {
++ period = (config & IBS_OP_MAX_CNT) << 4;
++ if (ibs_caps & IBS_CAPS_OPCNTEXT)
++ period |= config & IBS_OP_MAX_CNT_EXT_MASK;
++ } else {
++ period = (config & IBS_FETCH_MAX_CNT) << 4;
++ }
++
+ config &= ~perf_ibs->cnt_mask;
+- event->attr.sample_period = max_cnt << 4;
+- hwc->sample_period = event->attr.sample_period;
++ event->attr.sample_period = period;
++ hwc->sample_period = period;
+ }
+
+ if (!hwc->sample_period)
+--
+2.39.5
+
--- /dev/null
+From e59057b3746acb661c56170c279b17fef1995e5c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 15 Jan 2025 05:44:33 +0000
+Subject: perf/amd/ibs: Fix perf_ibs_op.cnt_mask for CurCnt
+
+From: Ravi Bangoria <ravi.bangoria@amd.com>
+
+[ Upstream commit 46dcf85566170d4528b842bf83ffc350d71771fa ]
+
+IBS Op uses two counters: MaxCnt and CurCnt. MaxCnt is programmed with
+the desired sample period. IBS hw generates sample when CurCnt reaches
+to MaxCnt. The size of these counter used to be 20 bits but later they
+were extended to 27 bits. The 7 bit extension is indicated by CPUID
+Fn8000_001B_EAX[6 / OpCntExt].
+
+perf_ibs->cnt_mask variable contains bit masks for MaxCnt and CurCnt.
+But IBS driver does not set upper 7 bits of CurCnt in cnt_mask even
+when OpCntExt CPUID bit is set. Fix this.
+
+IBS driver uses cnt_mask[CurCnt] bits only while disabling an event.
+Fortunately, CurCnt bits are not read from MSR while re-enabling the
+event, instead MaxCnt is programmed with desired period and CurCnt is
+set to 0. Hence, we did not see any issues so far.
+
+Signed-off-by: Ravi Bangoria <ravi.bangoria@amd.com>
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Acked-by: Namhyung Kim <namhyung@kernel.org>
+Link: https://lkml.kernel.org/r/20250115054438.1021-5-ravi.bangoria@amd.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/events/amd/ibs.c | 3 ++-
+ arch/x86/include/asm/perf_event.h | 1 +
+ 2 files changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/arch/x86/events/amd/ibs.c b/arch/x86/events/amd/ibs.c
+index e36c9c63c97cc..5d975c39701cb 100644
+--- a/arch/x86/events/amd/ibs.c
++++ b/arch/x86/events/amd/ibs.c
+@@ -1318,7 +1318,8 @@ static __init int perf_ibs_op_init(void)
+ if (ibs_caps & IBS_CAPS_OPCNTEXT) {
+ perf_ibs_op.max_period |= IBS_OP_MAX_CNT_EXT_MASK;
+ perf_ibs_op.config_mask |= IBS_OP_MAX_CNT_EXT_MASK;
+- perf_ibs_op.cnt_mask |= IBS_OP_MAX_CNT_EXT_MASK;
++ perf_ibs_op.cnt_mask |= (IBS_OP_MAX_CNT_EXT_MASK |
++ IBS_OP_CUR_CNT_EXT_MASK);
+ }
+
+ if (ibs_caps & IBS_CAPS_ZEN4)
+diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h
+index 0ba8d20f2d1d5..d37c1c32e74b9 100644
+--- a/arch/x86/include/asm/perf_event.h
++++ b/arch/x86/include/asm/perf_event.h
+@@ -536,6 +536,7 @@ struct pebs_xmm {
+ */
+ #define IBS_OP_CUR_CNT (0xFFF80ULL<<32)
+ #define IBS_OP_CUR_CNT_RAND (0x0007FULL<<32)
++#define IBS_OP_CUR_CNT_EXT_MASK (0x7FULL<<52)
+ #define IBS_OP_CNT_CTL (1ULL<<19)
+ #define IBS_OP_VAL (1ULL<<18)
+ #define IBS_OP_ENABLE (1ULL<<17)
+--
+2.39.5
+
--- /dev/null
+From e3a54607f67db017fbe0214101536a05a825aee5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Feb 2025 14:39:56 -0600
+Subject: perf: arm_pmuv3: Call kvm_vcpu_pmu_resync_el0() before enabling
+ counters
+
+From: Rob Herring (Arm) <robh@kernel.org>
+
+[ Upstream commit 04bd15c4cbc3f7bd2399d1baab958c5e738dbfc9 ]
+
+Counting events related to setup of the PMU is not desired, but
+kvm_vcpu_pmu_resync_el0() is called just after the PMU counters have
+been enabled. Move the call to before enabling the counters.
+
+Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
+Reviewed-by: Anshuman Khandual <anshuman.khandual@arm.com>
+Tested-by: James Clark <james.clark@linaro.org>
+Link: https://lore.kernel.org/r/20250218-arm-brbe-v19-v20-1-4e9922fc2e8e@kernel.org
+Signed-off-by: Will Deacon <will@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/perf/arm_pmuv3.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/perf/arm_pmuv3.c b/drivers/perf/arm_pmuv3.c
+index 0e360feb3432e..9ebc950559c0a 100644
+--- a/drivers/perf/arm_pmuv3.c
++++ b/drivers/perf/arm_pmuv3.c
+@@ -825,10 +825,10 @@ static void armv8pmu_start(struct arm_pmu *cpu_pmu)
+ else
+ armv8pmu_disable_user_access();
+
++ kvm_vcpu_pmu_resync_el0();
++
+ /* Enable all counters */
+ armv8pmu_pmcr_write(armv8pmu_pmcr_read() | ARMV8_PMU_PMCR_E);
+-
+- kvm_vcpu_pmu_resync_el0();
+ }
+
+ static void armv8pmu_stop(struct arm_pmu *cpu_pmu)
+--
+2.39.5
+
--- /dev/null
+From f5ec1867499335eeced21c8868f31f27ae804cfb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 21 Jan 2025 07:23:02 -0800
+Subject: perf: Avoid the read if the count is already updated
+
+From: Peter Zijlstra (Intel) <peterz@infradead.org>
+
+[ Upstream commit 8ce939a0fa194939cc1f92dbd8bc1a7806e7d40a ]
+
+The event may have been updated in the PMU-specific implementation,
+e.g., Intel PEBS counters snapshotting. The common code should not
+read and overwrite the value.
+
+The PERF_SAMPLE_READ in the data->sample_type can be used to detect
+whether the PMU-specific value is available. If yes, avoid the
+pmu->read() in the common code. Add a new flag, skip_read, to track the
+case.
+
+Factor out a perf_pmu_read() to clean up the code.
+
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Signed-off-by: Kan Liang <kan.liang@linux.intel.com>
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Link: https://lkml.kernel.org/r/20250121152303.3128733-3-kan.liang@linux.intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/perf_event.h | 8 +++++++-
+ kernel/events/core.c | 33 ++++++++++++++++-----------------
+ kernel/events/ring_buffer.c | 1 +
+ 3 files changed, 24 insertions(+), 18 deletions(-)
+
+diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
+index 93ea9c6672f0e..3d5814c6d251c 100644
+--- a/include/linux/perf_event.h
++++ b/include/linux/perf_event.h
+@@ -1098,7 +1098,13 @@ struct perf_output_handle {
+ struct perf_buffer *rb;
+ unsigned long wakeup;
+ unsigned long size;
+- u64 aux_flags;
++ union {
++ u64 flags; /* perf_output*() */
++ u64 aux_flags; /* perf_aux_output*() */
++ struct {
++ u64 skip_read : 1;
++ };
++ };
+ union {
+ void *addr;
+ unsigned long head;
+diff --git a/kernel/events/core.c b/kernel/events/core.c
+index dda1670b3539a..6fa70b3826d0e 100644
+--- a/kernel/events/core.c
++++ b/kernel/events/core.c
+@@ -1191,6 +1191,12 @@ static void perf_assert_pmu_disabled(struct pmu *pmu)
+ WARN_ON_ONCE(*this_cpu_ptr(pmu->pmu_disable_count) == 0);
+ }
+
++static inline void perf_pmu_read(struct perf_event *event)
++{
++ if (event->state == PERF_EVENT_STATE_ACTIVE)
++ event->pmu->read(event);
++}
++
+ static void get_ctx(struct perf_event_context *ctx)
+ {
+ refcount_inc(&ctx->refcount);
+@@ -3478,8 +3484,7 @@ static void __perf_event_sync_stat(struct perf_event *event,
+ * we know the event must be on the current CPU, therefore we
+ * don't need to use it.
+ */
+- if (event->state == PERF_EVENT_STATE_ACTIVE)
+- event->pmu->read(event);
++ perf_pmu_read(event);
+
+ perf_event_update_time(event);
+
+@@ -4625,15 +4630,8 @@ static void __perf_event_read(void *info)
+
+ pmu->read(event);
+
+- for_each_sibling_event(sub, event) {
+- if (sub->state == PERF_EVENT_STATE_ACTIVE) {
+- /*
+- * Use sibling's PMU rather than @event's since
+- * sibling could be on different (eg: software) PMU.
+- */
+- sub->pmu->read(sub);
+- }
+- }
++ for_each_sibling_event(sub, event)
++ perf_pmu_read(sub);
+
+ data->ret = pmu->commit_txn(pmu);
+
+@@ -7451,9 +7449,8 @@ static void perf_output_read_group(struct perf_output_handle *handle,
+ if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
+ values[n++] = running;
+
+- if ((leader != event) &&
+- (leader->state == PERF_EVENT_STATE_ACTIVE))
+- leader->pmu->read(leader);
++ if ((leader != event) && !handle->skip_read)
++ perf_pmu_read(leader);
+
+ values[n++] = perf_event_count(leader, self);
+ if (read_format & PERF_FORMAT_ID)
+@@ -7466,9 +7463,8 @@ static void perf_output_read_group(struct perf_output_handle *handle,
+ for_each_sibling_event(sub, leader) {
+ n = 0;
+
+- if ((sub != event) &&
+- (sub->state == PERF_EVENT_STATE_ACTIVE))
+- sub->pmu->read(sub);
++ if ((sub != event) && !handle->skip_read)
++ perf_pmu_read(sub);
+
+ values[n++] = perf_event_count(sub, self);
+ if (read_format & PERF_FORMAT_ID)
+@@ -7527,6 +7523,9 @@ void perf_output_sample(struct perf_output_handle *handle,
+ {
+ u64 sample_type = data->type;
+
++ if (data->sample_flags & PERF_SAMPLE_READ)
++ handle->skip_read = 1;
++
+ perf_output_put(handle, *header);
+
+ if (sample_type & PERF_SAMPLE_IDENTIFIER)
+diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c
+index 09459647cb822..5130b119d0ae0 100644
+--- a/kernel/events/ring_buffer.c
++++ b/kernel/events/ring_buffer.c
+@@ -185,6 +185,7 @@ __perf_output_begin(struct perf_output_handle *handle,
+
+ handle->rb = rb;
+ handle->event = event;
++ handle->flags = 0;
+
+ have_lost = local_read(&rb->lost);
+ if (unlikely(have_lost)) {
+--
+2.39.5
+
--- /dev/null
+From 8f118752248d31e353d89737e9e059b0987f2d80 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Feb 2025 11:21:28 +0100
+Subject: perf/core: Clean up perf_try_init_event()
+
+From: Peter Zijlstra <peterz@infradead.org>
+
+[ Upstream commit da02f54e81db2f7bf6af9d1d0cfc5b41ec6d0dcb ]
+
+Make sure that perf_try_init_event() doesn't leave event->pmu nor
+event->destroy set on failure.
+
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Acked-by: Ravi Bangoria <ravi.bangoria@amd.com>
+Link: https://lore.kernel.org/r/20250205102449.110145835@infradead.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/events/core.c | 65 ++++++++++++++++++++++++++------------------
+ 1 file changed, 38 insertions(+), 27 deletions(-)
+
+diff --git a/kernel/events/core.c b/kernel/events/core.c
+index 93ce810384c92..de838d3819ca7 100644
+--- a/kernel/events/core.c
++++ b/kernel/events/core.c
+@@ -12020,40 +12020,51 @@ static int perf_try_init_event(struct pmu *pmu, struct perf_event *event)
+ if (ctx)
+ perf_event_ctx_unlock(event->group_leader, ctx);
+
+- if (!ret) {
+- if (!(pmu->capabilities & PERF_PMU_CAP_EXTENDED_REGS) &&
+- has_extended_regs(event))
+- ret = -EOPNOTSUPP;
++ if (ret)
++ goto err_pmu;
+
+- if (pmu->capabilities & PERF_PMU_CAP_NO_EXCLUDE &&
+- event_has_any_exclude_flag(event))
+- ret = -EINVAL;
++ if (!(pmu->capabilities & PERF_PMU_CAP_EXTENDED_REGS) &&
++ has_extended_regs(event)) {
++ ret = -EOPNOTSUPP;
++ goto err_destroy;
++ }
+
+- if (pmu->scope != PERF_PMU_SCOPE_NONE && event->cpu >= 0) {
+- const struct cpumask *cpumask = perf_scope_cpu_topology_cpumask(pmu->scope, event->cpu);
+- struct cpumask *pmu_cpumask = perf_scope_cpumask(pmu->scope);
+- int cpu;
+-
+- if (pmu_cpumask && cpumask) {
+- cpu = cpumask_any_and(pmu_cpumask, cpumask);
+- if (cpu >= nr_cpu_ids)
+- ret = -ENODEV;
+- else
+- event->event_caps |= PERF_EV_CAP_READ_SCOPE;
+- } else {
+- ret = -ENODEV;
+- }
+- }
++ if (pmu->capabilities & PERF_PMU_CAP_NO_EXCLUDE &&
++ event_has_any_exclude_flag(event)) {
++ ret = -EINVAL;
++ goto err_destroy;
++ }
+
+- if (ret && event->destroy)
+- event->destroy(event);
++ if (pmu->scope != PERF_PMU_SCOPE_NONE && event->cpu >= 0) {
++ const struct cpumask *cpumask;
++ struct cpumask *pmu_cpumask;
++ int cpu;
++
++ cpumask = perf_scope_cpu_topology_cpumask(pmu->scope, event->cpu);
++ pmu_cpumask = perf_scope_cpumask(pmu->scope);
++
++ ret = -ENODEV;
++ if (!pmu_cpumask || !cpumask)
++ goto err_destroy;
++
++ cpu = cpumask_any_and(pmu_cpumask, cpumask);
++ if (cpu >= nr_cpu_ids)
++ goto err_destroy;
++
++ event->event_caps |= PERF_EV_CAP_READ_SCOPE;
+ }
+
+- if (ret) {
+- event->pmu = NULL;
+- module_put(pmu->module);
++ return 0;
++
++err_destroy:
++ if (event->destroy) {
++ event->destroy(event);
++ event->destroy = NULL;
+ }
+
++err_pmu:
++ event->pmu = NULL;
++ module_put(pmu->module);
+ return ret;
+ }
+
+--
+2.39.5
+
--- /dev/null
+From b123b565967bb53f1fc3f958942e885579db6071 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 4 Nov 2024 14:39:24 +0100
+Subject: perf/core: Fix perf_mmap() failure path
+
+From: Peter Zijlstra <peterz@infradead.org>
+
+[ Upstream commit 66477c7230eb1f9b90deb8c0f4da2bac2053c329 ]
+
+When f_ops->mmap() returns failure, m_ops->close() is *not* called.
+
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Acked-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
+Reviewed-by: Ravi Bangoria <ravi.bangoria@amd.com>
+Link: https://lore.kernel.org/r/20241104135519.248358497@infradead.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/events/core.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/kernel/events/core.c b/kernel/events/core.c
+index de838d3819ca7..dda1670b3539a 100644
+--- a/kernel/events/core.c
++++ b/kernel/events/core.c
+@@ -6834,7 +6834,7 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma)
+ if (!ret)
+ ret = map_range(rb, vma);
+
+- if (event->pmu->event_mapped)
++ if (!ret && event->pmu->event_mapped)
+ event->pmu->event_mapped(event, vma->vm_mm);
+
+ return ret;
+--
+2.39.5
+
--- /dev/null
+From 29b49b94a1cadf233fdb8cb3de089eb1bea0de10 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Mar 2025 14:54:51 +0530
+Subject: perf/hw_breakpoint: Return EOPNOTSUPP for unsupported breakpoint type
+
+From: Saket Kumar Bhaskar <skb99@linux.ibm.com>
+
+[ Upstream commit 061c991697062f3bf87b72ed553d1d33a0e370dd ]
+
+Currently, __reserve_bp_slot() returns -ENOSPC for unsupported
+breakpoint types on the architecture. For example, powerpc
+does not support hardware instruction breakpoints. This causes
+the perf_skip BPF selftest to fail, as neither ENOENT nor
+EOPNOTSUPP is returned by perf_event_open for unsupported
+breakpoint types. As a result, the test that should be skipped
+for this arch is not correctly identified.
+
+To resolve this, hw_breakpoint_event_init() should exit early by
+checking for unsupported breakpoint types using
+hw_breakpoint_slots_cached() and return the appropriate error
+(-EOPNOTSUPP).
+
+Signed-off-by: Saket Kumar Bhaskar <skb99@linux.ibm.com>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Cc: Marco Elver <elver@google.com>
+Cc: Dmitry Vyukov <dvyukov@google.com>
+Cc: Ian Rogers <irogers@google.com>
+Cc: Frederic Weisbecker <fweisbec@gmail.com>
+Link: https://lore.kernel.org/r/20250303092451.1862862-1-skb99@linux.ibm.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/events/hw_breakpoint.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/kernel/events/hw_breakpoint.c b/kernel/events/hw_breakpoint.c
+index bc4a61029b6dc..8ec2cb6889038 100644
+--- a/kernel/events/hw_breakpoint.c
++++ b/kernel/events/hw_breakpoint.c
+@@ -950,9 +950,10 @@ static int hw_breakpoint_event_init(struct perf_event *bp)
+ return -ENOENT;
+
+ /*
+- * no branch sampling for breakpoint events
++ * Check if breakpoint type is supported before proceeding.
++ * Also, no branch sampling for breakpoint events.
+ */
+- if (has_branch_stack(bp))
++ if (!hw_breakpoint_slots_cached(find_slot_idx(bp->attr.bp_type)) || has_branch_stack(bp))
+ return -EOPNOTSUPP;
+
+ err = register_perf_hw_breakpoint(bp);
+--
+2.39.5
+
--- /dev/null
+From 0e2169f9297489799153f868825e90256a9da6a1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 9 Feb 2025 14:31:45 +0200
+Subject: phy: core: don't require set_mode() callback for phy_get_mode() to
+ work
+
+From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+
+[ Upstream commit d58c04e305afbaa9dda7969151f06c4efe2c98b0 ]
+
+As reported by Damon Ding, the phy_get_mode() call doesn't work as
+expected unless the PHY driver has a .set_mode() call. This prompts PHY
+drivers to have empty stubs for .set_mode() for the sake of being able
+to get the mode.
+
+Make .set_mode() callback truly optional and update PHY's mode even if
+it there is none.
+
+Cc: Damon Ding <damon.ding@rock-chips.com>
+Link: https://lore.kernel.org/r/96f8310f-93f1-4bcb-8637-137e1159ff83@rock-chips.com
+Tested-by: Damon Ding <damon.ding@rock-chips.com>
+Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Link: https://lore.kernel.org/r/20250209-phy-fix-set-moe-v2-1-76e248503856@linaro.org
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/phy/phy-core.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
+index 8dfdce605a905..067316dfcd83a 100644
+--- a/drivers/phy/phy-core.c
++++ b/drivers/phy/phy-core.c
+@@ -405,13 +405,14 @@ EXPORT_SYMBOL_GPL(phy_power_off);
+
+ int phy_set_mode_ext(struct phy *phy, enum phy_mode mode, int submode)
+ {
+- int ret;
++ int ret = 0;
+
+- if (!phy || !phy->ops->set_mode)
++ if (!phy)
+ return 0;
+
+ mutex_lock(&phy->mutex);
+- ret = phy->ops->set_mode(phy, mode, submode);
++ if (phy->ops->set_mode)
++ ret = phy->ops->set_mode(phy, mode, submode);
+ if (!ret)
+ phy->attrs.mode = mode;
+ mutex_unlock(&phy->mutex);
+--
+2.39.5
+
--- /dev/null
+From efa954707ae2c66c1a49d6b9f0ca558aa22d5512 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 6 Dec 2024 16:31:04 +0000
+Subject: phy: exynos5-usbdrd: fix EDS distribution tuning (gs101)
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: André Draszik <andre.draszik@linaro.org>
+
+[ Upstream commit 21860f340ba76ee042e5431ff92537f89bc11476 ]
+
+This code's intention is to configure lane0 and lane2 tunings, but for
+lane2 there is a typo and it ends up tuning something else.
+
+Fix the typo, as it doesn't appear to make sense to apply different
+tunings for lane0 vs lane2.
+
+The same typo appears to exist in the bootloader, hence we restore the
+original value in the typo'd registers as well. This can be removed
+once / if the bootloader is updated.
+
+Note that this is incorrect in the downstream driver as well - the
+values had been copied from there.
+
+Reviewed-by: Peter Griffin <peter.griffin@linaro.org>
+Tested-by: Peter Griffin <peter.griffin@linaro.org>
+Signed-off-by: André Draszik <andre.draszik@linaro.org>
+Tested-by: Will McVicker <willmcvicker@google.com>
+Link: https://lore.kernel.org/r/20241206-gs101-phy-lanes-orientation-phy-v4-4-f5961268b149@linaro.org
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/phy/samsung/phy-exynos5-usbdrd.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/phy/samsung/phy-exynos5-usbdrd.c b/drivers/phy/samsung/phy-exynos5-usbdrd.c
+index 46b8f6987c62c..28d02ae60cc14 100644
+--- a/drivers/phy/samsung/phy-exynos5-usbdrd.c
++++ b/drivers/phy/samsung/phy-exynos5-usbdrd.c
+@@ -1513,8 +1513,11 @@ static const struct exynos5_usbdrd_phy_tuning gs101_tunes_pipe3_preinit[] = {
+ PHY_TUNING_ENTRY_PMA(0x09e0, -1, 0x00),
+ PHY_TUNING_ENTRY_PMA(0x09e4, -1, 0x36),
+ PHY_TUNING_ENTRY_PMA(0x1e7c, -1, 0x06),
+- PHY_TUNING_ENTRY_PMA(0x1e90, -1, 0x00),
+- PHY_TUNING_ENTRY_PMA(0x1e94, -1, 0x36),
++ PHY_TUNING_ENTRY_PMA(0x19e0, -1, 0x00),
++ PHY_TUNING_ENTRY_PMA(0x19e4, -1, 0x36),
++ /* fix bootloader bug */
++ PHY_TUNING_ENTRY_PMA(0x1e90, -1, 0x02),
++ PHY_TUNING_ENTRY_PMA(0x1e94, -1, 0x0b),
+ /* improve LVCC */
+ PHY_TUNING_ENTRY_PMA(0x08f0, -1, 0x30),
+ PHY_TUNING_ENTRY_PMA(0x18f0, -1, 0x30),
+--
+2.39.5
+
--- /dev/null
+From 04209f58dd11c447f57240c7baf24b758d61999b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Feb 2025 18:51:54 +0800
+Subject: phy: phy-rockchip-samsung-hdptx: Swap the definitions of LCPLL_REF
+ and ROPLL_REF
+
+From: Damon Ding <damon.ding@rock-chips.com>
+
+[ Upstream commit 2947c8065e9efdd3b6434d2817dc8896234a3fc0 ]
+
+According to the datasheet, setting the dig_clk_sel bit of CMN_REG(0097)
+to 1'b1 selects LCPLL as the reference clock, while setting it to 1'b0
+selects the ROPLL.
+
+Signed-off-by: Damon Ding <damon.ding@rock-chips.com>
+Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Link: https://lore.kernel.org/r/20250205105157.580060-2-damon.ding@rock-chips.com
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
+index 2fb4f297fda3d..920abf6fa9bdd 100644
+--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
++++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
+@@ -94,8 +94,8 @@
+ #define LCPLL_ALONE_MODE BIT(1)
+ /* CMN_REG(0097) */
+ #define DIG_CLK_SEL BIT(1)
+-#define ROPLL_REF BIT(1)
+-#define LCPLL_REF 0
++#define LCPLL_REF BIT(1)
++#define ROPLL_REF 0
+ /* CMN_REG(0099) */
+ #define CMN_ROPLL_ALONE_MODE BIT(2)
+ #define ROPLL_ALONE_MODE BIT(2)
+--
+2.39.5
+
--- /dev/null
+From 107eca439e430631bbbee9c62088a710a974d056 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 7 May 2025 15:50:31 +0300
+Subject: phy: renesas: rcar-gen3-usb2: Assert PLL reset on PHY power off
+
+From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
+
+[ Upstream commit 9ce71e85b29eb63e48e294479742e670513f03a0 ]
+
+Assert PLL reset on PHY power off. This saves power.
+
+Fixes: f3b5a8d9b50d ("phy: rcar-gen3-usb2: Add R-Car Gen3 USB2 PHY driver")
+Cc: stable@vger.kernel.org
+Reviewed-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
+Tested-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
+Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
+Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
+Link: https://lore.kernel.org/r/20250507125032.565017-5-claudiu.beznea.uj@bp.renesas.com
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/phy/renesas/phy-rcar-gen3-usb2.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
+index 7d18bc549f17e..9fdf17e0848a2 100644
+--- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c
++++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
+@@ -540,9 +540,17 @@ static int rcar_gen3_phy_usb2_power_off(struct phy *p)
+ struct rcar_gen3_chan *channel = rphy->ch;
+ int ret = 0;
+
+- scoped_guard(spinlock_irqsave, &channel->lock)
++ scoped_guard(spinlock_irqsave, &channel->lock) {
+ rphy->powered = false;
+
++ if (rcar_gen3_are_all_rphys_power_off(channel)) {
++ u32 val = readl(channel->base + USB2_USBCTR);
++
++ val |= USB2_USBCTR_PLL_RST;
++ writel(val, channel->base + USB2_USBCTR);
++ }
++ }
++
+ if (channel->vbus)
+ ret = regulator_disable(channel->vbus);
+
+--
+2.39.5
+
--- /dev/null
+From dde57b862c75b85e963db85035d0310bcaf6e28b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 7 May 2025 15:50:30 +0300
+Subject: phy: renesas: rcar-gen3-usb2: Lock around hardware registers and
+ driver data
+
+From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
+
+[ Upstream commit 55a387ebb9219cbe4edfa8ba9996ccb0e7ad4932 ]
+
+The phy-rcar-gen3-usb2 driver exposes four individual PHYs that are
+requested and configured by PHY users. The struct phy_ops APIs access the
+same set of registers to configure all PHYs. Additionally, PHY settings can
+be modified through sysfs or an IRQ handler. While some struct phy_ops APIs
+are protected by a driver-wide mutex, others rely on individual
+PHY-specific mutexes.
+
+This approach can lead to various issues, including:
+1/ the IRQ handler may interrupt PHY settings in progress, racing with
+ hardware configuration protected by a mutex lock
+2/ due to msleep(20) in rcar_gen3_init_otg(), while a configuration thread
+ suspends to wait for the delay, another thread may try to configure
+ another PHY (with phy_init() + phy_power_on()); re-running the
+ phy_init() goes to the exact same configuration code, re-running the
+ same hardware configuration on the same set of registers (and bits)
+ which might impact the result of the msleep for the 1st configuring
+ thread
+3/ sysfs can configure the hardware (though role_store()) and it can
+ still race with the phy_init()/phy_power_on() APIs calling into the
+ drivers struct phy_ops
+
+To address these issues, add a spinlock to protect hardware register access
+and driver private data structures (e.g., calls to
+rcar_gen3_is_any_rphy_initialized()). Checking driver-specific data remains
+necessary as all PHY instances share common settings. With this change,
+the existing mutex protection is removed and the cleanup.h helpers are
+used.
+
+While at it, to keep the code simpler, do not skip
+regulator_enable()/regulator_disable() APIs in
+rcar_gen3_phy_usb2_power_on()/rcar_gen3_phy_usb2_power_off() as the
+regulators enable/disable operations are reference counted anyway.
+
+Fixes: f3b5a8d9b50d ("phy: rcar-gen3-usb2: Add R-Car Gen3 USB2 PHY driver")
+Cc: stable@vger.kernel.org
+Reviewed-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
+Tested-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
+Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
+Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
+Link: https://lore.kernel.org/r/20250507125032.565017-4-claudiu.beznea.uj@bp.renesas.com
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+Stable-dep-of: 9ce71e85b29e ("phy: renesas: rcar-gen3-usb2: Assert PLL reset on PHY power off")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/phy/renesas/phy-rcar-gen3-usb2.c | 49 +++++++++++++-----------
+ 1 file changed, 26 insertions(+), 23 deletions(-)
+
+diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
+index aee33916b9073..7d18bc549f17e 100644
+--- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c
++++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
+@@ -9,6 +9,7 @@
+ * Copyright (C) 2014 Cogent Embedded, Inc.
+ */
+
++#include <linux/cleanup.h>
+ #include <linux/extcon-provider.h>
+ #include <linux/interrupt.h>
+ #include <linux/io.h>
+@@ -118,7 +119,7 @@ struct rcar_gen3_chan {
+ struct regulator *vbus;
+ struct reset_control *rstc;
+ struct work_struct work;
+- struct mutex lock; /* protects rphys[...].powered */
++ spinlock_t lock; /* protects access to hardware and driver data structure. */
+ enum usb_dr_mode dr_mode;
+ u32 obint_enable_bits;
+ bool extcon_host;
+@@ -348,6 +349,8 @@ static ssize_t role_store(struct device *dev, struct device_attribute *attr,
+ bool is_b_device;
+ enum phy_mode cur_mode, new_mode;
+
++ guard(spinlock_irqsave)(&ch->lock);
++
+ if (!ch->is_otg_channel || !rcar_gen3_is_any_otg_rphy_initialized(ch))
+ return -EIO;
+
+@@ -415,7 +418,7 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch)
+ val = readl(usb2_base + USB2_ADPCTRL);
+ writel(val | USB2_ADPCTRL_IDPULLUP, usb2_base + USB2_ADPCTRL);
+ }
+- msleep(20);
++ mdelay(20);
+
+ writel(0xffffffff, usb2_base + USB2_OBINTSTA);
+ writel(ch->obint_enable_bits, usb2_base + USB2_OBINTEN);
+@@ -436,12 +439,14 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch)
+ if (pm_runtime_suspended(dev))
+ goto rpm_put;
+
+- status = readl(usb2_base + USB2_OBINTSTA);
+- if (status & ch->obint_enable_bits) {
+- dev_vdbg(dev, "%s: %08x\n", __func__, status);
+- writel(ch->obint_enable_bits, usb2_base + USB2_OBINTSTA);
+- rcar_gen3_device_recognition(ch);
+- ret = IRQ_HANDLED;
++ scoped_guard(spinlock, &ch->lock) {
++ status = readl(usb2_base + USB2_OBINTSTA);
++ if (status & ch->obint_enable_bits) {
++ dev_vdbg(dev, "%s: %08x\n", __func__, status);
++ writel(ch->obint_enable_bits, usb2_base + USB2_OBINTSTA);
++ rcar_gen3_device_recognition(ch);
++ ret = IRQ_HANDLED;
++ }
+ }
+
+ rpm_put:
+@@ -456,6 +461,8 @@ static int rcar_gen3_phy_usb2_init(struct phy *p)
+ void __iomem *usb2_base = channel->base;
+ u32 val;
+
++ guard(spinlock_irqsave)(&channel->lock);
++
+ /* Initialize USB2 part */
+ val = readl(usb2_base + USB2_INT_ENABLE);
+ val |= USB2_INT_ENABLE_UCOM_INTEN | rphy->int_enable_bits;
+@@ -482,6 +489,8 @@ static int rcar_gen3_phy_usb2_exit(struct phy *p)
+ void __iomem *usb2_base = channel->base;
+ u32 val;
+
++ guard(spinlock_irqsave)(&channel->lock);
++
+ rphy->initialized = false;
+
+ val = readl(usb2_base + USB2_INT_ENABLE);
+@@ -501,16 +510,17 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p)
+ u32 val;
+ int ret = 0;
+
+- mutex_lock(&channel->lock);
+- if (!rcar_gen3_are_all_rphys_power_off(channel))
+- goto out;
+-
+ if (channel->vbus) {
+ ret = regulator_enable(channel->vbus);
+ if (ret)
+- goto out;
++ return ret;
+ }
+
++ guard(spinlock_irqsave)(&channel->lock);
++
++ if (!rcar_gen3_are_all_rphys_power_off(channel))
++ goto out;
++
+ val = readl(usb2_base + USB2_USBCTR);
+ val |= USB2_USBCTR_PLL_RST;
+ writel(val, usb2_base + USB2_USBCTR);
+@@ -520,7 +530,6 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p)
+ out:
+ /* The powered flag should be set for any other phys anyway */
+ rphy->powered = true;
+- mutex_unlock(&channel->lock);
+
+ return 0;
+ }
+@@ -531,18 +540,12 @@ static int rcar_gen3_phy_usb2_power_off(struct phy *p)
+ struct rcar_gen3_chan *channel = rphy->ch;
+ int ret = 0;
+
+- mutex_lock(&channel->lock);
+- rphy->powered = false;
+-
+- if (!rcar_gen3_are_all_rphys_power_off(channel))
+- goto out;
++ scoped_guard(spinlock_irqsave, &channel->lock)
++ rphy->powered = false;
+
+ if (channel->vbus)
+ ret = regulator_disable(channel->vbus);
+
+-out:
+- mutex_unlock(&channel->lock);
+-
+ return ret;
+ }
+
+@@ -753,7 +756,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
+ if (phy_data->no_adp_ctrl)
+ channel->obint_enable_bits = USB2_OBINT_IDCHG_EN;
+
+- mutex_init(&channel->lock);
++ spin_lock_init(&channel->lock);
+ for (i = 0; i < NUM_OF_PHYS; i++) {
+ channel->rphys[i].phy = devm_phy_create(dev, NULL,
+ phy_data->phy_usb2_ops);
+--
+2.39.5
+
--- /dev/null
+From d70563066ea87c8810d764ab03997616ec9e822d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 7 May 2025 15:50:29 +0300
+Subject: phy: renesas: rcar-gen3-usb2: Move IRQ request in probe
+
+From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
+
+[ Upstream commit de76809f60cc938d3580bbbd5b04b7d12af6ce3a ]
+
+Commit 08b0ad375ca6 ("phy: renesas: rcar-gen3-usb2: move IRQ registration
+to init") moved the IRQ request operation from probe to
+struct phy_ops::phy_init API to avoid triggering interrupts (which lead to
+register accesses) while the PHY clocks (enabled through runtime PM APIs)
+are not active. If this happens, it results in a synchronous abort.
+
+One way to reproduce this issue is by enabling CONFIG_DEBUG_SHIRQ, which
+calls free_irq() on driver removal.
+
+Move the IRQ request and free operations back to probe, and take the
+runtime PM state into account in IRQ handler. This commit is preparatory
+for the subsequent fixes in this series.
+
+Reviewed-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
+Tested-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
+Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
+Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
+Link: https://lore.kernel.org/r/20250507125032.565017-3-claudiu.beznea.uj@bp.renesas.com
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+Stable-dep-of: 9ce71e85b29e ("phy: renesas: rcar-gen3-usb2: Assert PLL reset on PHY power off")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/phy/renesas/phy-rcar-gen3-usb2.c | 46 +++++++++++++-----------
+ 1 file changed, 26 insertions(+), 20 deletions(-)
+
+diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
+index 946dc2f184e87..aee33916b9073 100644
+--- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c
++++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
+@@ -120,7 +120,6 @@ struct rcar_gen3_chan {
+ struct work_struct work;
+ struct mutex lock; /* protects rphys[...].powered */
+ enum usb_dr_mode dr_mode;
+- int irq;
+ u32 obint_enable_bits;
+ bool extcon_host;
+ bool is_otg_channel;
+@@ -428,16 +427,25 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch)
+ {
+ struct rcar_gen3_chan *ch = _ch;
+ void __iomem *usb2_base = ch->base;
+- u32 status = readl(usb2_base + USB2_OBINTSTA);
++ struct device *dev = ch->dev;
+ irqreturn_t ret = IRQ_NONE;
++ u32 status;
+
++ pm_runtime_get_noresume(dev);
++
++ if (pm_runtime_suspended(dev))
++ goto rpm_put;
++
++ status = readl(usb2_base + USB2_OBINTSTA);
+ if (status & ch->obint_enable_bits) {
+- dev_vdbg(ch->dev, "%s: %08x\n", __func__, status);
++ dev_vdbg(dev, "%s: %08x\n", __func__, status);
+ writel(ch->obint_enable_bits, usb2_base + USB2_OBINTSTA);
+ rcar_gen3_device_recognition(ch);
+ ret = IRQ_HANDLED;
+ }
+
++rpm_put:
++ pm_runtime_put_noidle(dev);
+ return ret;
+ }
+
+@@ -447,17 +455,6 @@ static int rcar_gen3_phy_usb2_init(struct phy *p)
+ struct rcar_gen3_chan *channel = rphy->ch;
+ void __iomem *usb2_base = channel->base;
+ u32 val;
+- int ret;
+-
+- if (!rcar_gen3_is_any_rphy_initialized(channel) && channel->irq >= 0) {
+- INIT_WORK(&channel->work, rcar_gen3_phy_usb2_work);
+- ret = request_irq(channel->irq, rcar_gen3_phy_usb2_irq,
+- IRQF_SHARED, dev_name(channel->dev), channel);
+- if (ret < 0) {
+- dev_err(channel->dev, "No irq handler (%d)\n", channel->irq);
+- return ret;
+- }
+- }
+
+ /* Initialize USB2 part */
+ val = readl(usb2_base + USB2_INT_ENABLE);
+@@ -493,9 +490,6 @@ static int rcar_gen3_phy_usb2_exit(struct phy *p)
+ val &= ~USB2_INT_ENABLE_UCOM_INTEN;
+ writel(val, usb2_base + USB2_INT_ENABLE);
+
+- if (channel->irq >= 0 && !rcar_gen3_is_any_rphy_initialized(channel))
+- free_irq(channel->irq, channel);
+-
+ return 0;
+ }
+
+@@ -701,7 +695,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
+ struct device *dev = &pdev->dev;
+ struct rcar_gen3_chan *channel;
+ struct phy_provider *provider;
+- int ret = 0, i;
++ int ret = 0, i, irq;
+
+ if (!dev->of_node) {
+ dev_err(dev, "This driver needs device tree\n");
+@@ -717,8 +711,6 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
+ return PTR_ERR(channel->base);
+
+ channel->obint_enable_bits = USB2_OBINT_BITS;
+- /* get irq number here and request_irq for OTG in phy_init */
+- channel->irq = platform_get_irq_optional(pdev, 0);
+ channel->dr_mode = rcar_gen3_get_dr_mode(dev->of_node);
+ if (channel->dr_mode != USB_DR_MODE_UNKNOWN) {
+ channel->is_otg_channel = true;
+@@ -787,6 +779,20 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
+ channel->vbus = NULL;
+ }
+
++ irq = platform_get_irq_optional(pdev, 0);
++ if (irq < 0 && irq != -ENXIO) {
++ ret = irq;
++ goto error;
++ } else if (irq > 0) {
++ INIT_WORK(&channel->work, rcar_gen3_phy_usb2_work);
++ ret = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq,
++ IRQF_SHARED, dev_name(dev), channel);
++ if (ret < 0) {
++ dev_err(dev, "Failed to request irq (%d)\n", irq);
++ goto error;
++ }
++ }
++
+ provider = devm_of_phy_provider_register(dev, rcar_gen3_phy_usb2_xlate);
+ if (IS_ERR(provider)) {
+ dev_err(dev, "Failed to register PHY provider\n");
+--
+2.39.5
+
--- /dev/null
+From 308a9875a7045a13b16ca3d5c410e11db1b273cf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 12 Mar 2025 16:00:07 +0800
+Subject: phy: rockchip: usbdp: Only verify link rates/lanes/voltage when the
+ corresponding set flags are set
+
+From: Andy Yan <andy.yan@rock-chips.com>
+
+[ Upstream commit 969a38be437b68dc9e12e3c3f08911c9f9c8be73 ]
+
+According documentation of phy_configure_opts_dp, at the configure
+stage, link rates should only be verify/configure when set_rate
+flag is set, the same applies to lanes and voltage.
+
+So do it as the documentation says.
+Because voltage setting depends on the lanes, link rates set
+previously, so record the link rates and lanes at it's verify stage.
+
+Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
+Link: https://lore.kernel.org/r/20250312080041.524546-1-andyshrk@163.com
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/phy/rockchip/phy-rockchip-usbdp.c | 87 ++++++++++++++---------
+ 1 file changed, 53 insertions(+), 34 deletions(-)
+
+diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
+index c04cf64f8a35d..fff04e0fbd800 100644
+--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
++++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
+@@ -187,6 +187,8 @@ struct rk_udphy {
+ u32 dp_aux_din_sel;
+ bool dp_sink_hpd_sel;
+ bool dp_sink_hpd_cfg;
++ unsigned int link_rate;
++ unsigned int lanes;
+ u8 bw;
+ int id;
+
+@@ -1102,15 +1104,19 @@ static int rk_udphy_dp_phy_power_off(struct phy *phy)
+ return 0;
+ }
+
+-static int rk_udphy_dp_phy_verify_link_rate(unsigned int link_rate)
++/*
++ * Verify link rate
++ */
++static int rk_udphy_dp_phy_verify_link_rate(struct rk_udphy *udphy,
++ struct phy_configure_opts_dp *dp)
+ {
+- switch (link_rate) {
++ switch (dp->link_rate) {
+ case 1620:
+ case 2700:
+ case 5400:
+ case 8100:
++ udphy->link_rate = dp->link_rate;
+ break;
+-
+ default:
+ return -EINVAL;
+ }
+@@ -1118,45 +1124,44 @@ static int rk_udphy_dp_phy_verify_link_rate(unsigned int link_rate)
+ return 0;
+ }
+
+-static int rk_udphy_dp_phy_verify_config(struct rk_udphy *udphy,
+- struct phy_configure_opts_dp *dp)
++static int rk_udphy_dp_phy_verify_lanes(struct rk_udphy *udphy,
++ struct phy_configure_opts_dp *dp)
+ {
+- int i, ret;
+-
+- /* If changing link rate was required, verify it's supported. */
+- ret = rk_udphy_dp_phy_verify_link_rate(dp->link_rate);
+- if (ret)
+- return ret;
+-
+- /* Verify lane count. */
+ switch (dp->lanes) {
+ case 1:
+ case 2:
+ case 4:
+ /* valid lane count. */
++ udphy->lanes = dp->lanes;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+- /*
+- * If changing voltages is required, check swing and pre-emphasis
+- * levels, per-lane.
+- */
+- if (dp->set_voltages) {
+- /* Lane count verified previously. */
+- for (i = 0; i < dp->lanes; i++) {
+- if (dp->voltage[i] > 3 || dp->pre[i] > 3)
+- return -EINVAL;
++ return 0;
++}
+
+- /*
+- * Sum of voltage swing and pre-emphasis levels cannot
+- * exceed 3.
+- */
+- if (dp->voltage[i] + dp->pre[i] > 3)
+- return -EINVAL;
+- }
++/*
++ * If changing voltages is required, check swing and pre-emphasis
++ * levels, per-lane.
++ */
++static int rk_udphy_dp_phy_verify_voltages(struct rk_udphy *udphy,
++ struct phy_configure_opts_dp *dp)
++{
++ int i;
++
++ /* Lane count verified previously. */
++ for (i = 0; i < udphy->lanes; i++) {
++ if (dp->voltage[i] > 3 || dp->pre[i] > 3)
++ return -EINVAL;
++
++ /*
++ * Sum of voltage swing and pre-emphasis levels cannot
++ * exceed 3.
++ */
++ if (dp->voltage[i] + dp->pre[i] > 3)
++ return -EINVAL;
+ }
+
+ return 0;
+@@ -1196,9 +1201,23 @@ static int rk_udphy_dp_phy_configure(struct phy *phy,
+ u32 i, val, lane;
+ int ret;
+
+- ret = rk_udphy_dp_phy_verify_config(udphy, dp);
+- if (ret)
+- return ret;
++ if (dp->set_rate) {
++ ret = rk_udphy_dp_phy_verify_link_rate(udphy, dp);
++ if (ret)
++ return ret;
++ }
++
++ if (dp->set_lanes) {
++ ret = rk_udphy_dp_phy_verify_lanes(udphy, dp);
++ if (ret)
++ return ret;
++ }
++
++ if (dp->set_voltages) {
++ ret = rk_udphy_dp_phy_verify_voltages(udphy, dp);
++ if (ret)
++ return ret;
++ }
+
+ if (dp->set_rate) {
+ regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET,
+@@ -1243,9 +1262,9 @@ static int rk_udphy_dp_phy_configure(struct phy *phy,
+ }
+
+ if (dp->set_voltages) {
+- for (i = 0; i < dp->lanes; i++) {
++ for (i = 0; i < udphy->lanes; i++) {
+ lane = udphy->dp_lane_sel[i];
+- switch (dp->link_rate) {
++ switch (udphy->link_rate) {
+ case 1620:
+ case 2700:
+ regmap_update_bits(udphy->pma_regmap,
+--
+2.39.5
+
--- /dev/null
+From 7bfc577726ebf2db0287215d52947c9b09cd8efb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 20 Mar 2025 14:24:08 +0100
+Subject: pidfs: improve multi-threaded exec and premature thread-group leader
+ exit polling
+
+From: Christian Brauner <brauner@kernel.org>
+
+[ Upstream commit 0fb482728ba1ee2130eaa461bf551f014447997c ]
+
+This is another attempt trying to make pidfd polling for multi-threaded
+exec and premature thread-group leader exit consistent.
+
+A quick recap of these two cases:
+
+(1) During a multi-threaded exec by a subthread, i.e., non-thread-group
+ leader thread, all other threads in the thread-group including the
+ thread-group leader are killed and the struct pid of the
+ thread-group leader will be taken over by the subthread that called
+ exec. IOW, two tasks change their TIDs.
+
+(2) A premature thread-group leader exit means that the thread-group
+ leader exited before all of the other subthreads in the thread-group
+ have exited.
+
+Both cases lead to inconsistencies for pidfd polling with PIDFD_THREAD.
+Any caller that holds a PIDFD_THREAD pidfd to the current thread-group
+leader may or may not see an exit notification on the file descriptor
+depending on when poll is performed. If the poll is performed before the
+exec of the subthread has concluded an exit notification is generated
+for the old thread-group leader. If the poll is performed after the exec
+of the subthread has concluded no exit notification is generated for the
+old thread-group leader.
+
+The correct behavior would be to simply not generate an exit
+notification on the struct pid of a subhthread exec because the struct
+pid is taken over by the subthread and thus remains alive.
+
+But this is difficult to handle because a thread-group may exit
+prematurely as mentioned in (2). In that case an exit notification is
+reliably generated but the subthreads may continue to run for an
+indeterminate amount of time and thus also may exec at some point.
+
+So far there was no way to distinguish between (1) and (2) internally.
+This tiny series tries to address this problem by discarding
+PIDFD_THREAD notification on premature thread-group leader exit.
+
+If that works correctly then no exit notifications are generated for a
+PIDFD_THREAD pidfd for a thread-group leader until all subthreads have
+been reaped. If a subthread should exec aftewards no exit notification
+will be generated until that task exits or it creates subthreads and
+repeates the cycle.
+
+Co-Developed-by: Oleg Nesterov <oleg@redhat.com>
+Signed-off-by: Oleg Nesterov <oleg@redhat.com>
+Link: https://lore.kernel.org/r/20250320-work-pidfs-thread_group-v4-1-da678ce805bf@kernel.org
+Signed-off-by: Christian Brauner <brauner@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/pidfs.c | 9 +++++----
+ kernel/exit.c | 6 +++---
+ kernel/signal.c | 3 +--
+ 3 files changed, 9 insertions(+), 9 deletions(-)
+
+diff --git a/fs/pidfs.c b/fs/pidfs.c
+index c0478b3c55d9f..9aa4c705776dd 100644
+--- a/fs/pidfs.c
++++ b/fs/pidfs.c
+@@ -188,20 +188,21 @@ static void pidfd_show_fdinfo(struct seq_file *m, struct file *f)
+ static __poll_t pidfd_poll(struct file *file, struct poll_table_struct *pts)
+ {
+ struct pid *pid = pidfd_pid(file);
+- bool thread = file->f_flags & PIDFD_THREAD;
+ struct task_struct *task;
+ __poll_t poll_flags = 0;
+
+ poll_wait(file, &pid->wait_pidfd, pts);
+ /*
+- * Depending on PIDFD_THREAD, inform pollers when the thread
+- * or the whole thread-group exits.
++ * Don't wake waiters if the thread-group leader exited
++ * prematurely. They either get notified when the last subthread
++ * exits or not at all if one of the remaining subthreads execs
++ * and assumes the struct pid of the old thread-group leader.
+ */
+ guard(rcu)();
+ task = pid_task(pid, PIDTYPE_PID);
+ if (!task)
+ poll_flags = EPOLLIN | EPOLLRDNORM | EPOLLHUP;
+- else if (task->exit_state && (thread || thread_group_empty(task)))
++ else if (task->exit_state && !delay_group_leader(task))
+ poll_flags = EPOLLIN | EPOLLRDNORM;
+
+ return poll_flags;
+diff --git a/kernel/exit.c b/kernel/exit.c
+index 6bb59b16e33e1..a9960dd6d0aa0 100644
+--- a/kernel/exit.c
++++ b/kernel/exit.c
+@@ -744,10 +744,10 @@ static void exit_notify(struct task_struct *tsk, int group_dead)
+
+ tsk->exit_state = EXIT_ZOMBIE;
+ /*
+- * sub-thread or delay_group_leader(), wake up the
+- * PIDFD_THREAD waiters.
++ * Ignore thread-group leaders that exited before all
++ * subthreads did.
+ */
+- if (!thread_group_empty(tsk))
++ if (!delay_group_leader(tsk))
+ do_notify_pidfd(tsk);
+
+ if (unlikely(tsk->ptrace)) {
+diff --git a/kernel/signal.c b/kernel/signal.c
+index 875e97f6205a2..b2e5c90f29602 100644
+--- a/kernel/signal.c
++++ b/kernel/signal.c
+@@ -2180,8 +2180,7 @@ bool do_notify_parent(struct task_struct *tsk, int sig)
+ WARN_ON_ONCE(!tsk->ptrace &&
+ (tsk->group_leader != tsk || !thread_group_empty(tsk)));
+ /*
+- * tsk is a group leader and has no threads, wake up the
+- * non-PIDFD_THREAD waiters.
++ * Notify for thread-group leaders without subthreads.
+ */
+ if (thread_group_empty(tsk))
+ do_notify_pidfd(tsk);
+--
+2.39.5
+
--- /dev/null
+From 49cd97dbe35dc8c73f074741787252d928bd8962 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Mar 2025 21:54:47 +0100
+Subject: pinctrl: bcm281xx: Use "unsigned int" instead of bare "unsigned"
+
+From: Artur Weber <aweber.kernel@gmail.com>
+
+[ Upstream commit 07b5a2a13f4704c5eae3be7277ec54ffdba45f72 ]
+
+Replace uses of bare "unsigned" with "unsigned int" to fix checkpatch
+warnings. No functional change.
+
+Signed-off-by: Artur Weber <aweber.kernel@gmail.com>
+Link: https://lore.kernel.org/20250303-bcm21664-pinctrl-v3-2-5f8b80e4ab51@gmail.com
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pinctrl/bcm/pinctrl-bcm281xx.c | 44 +++++++++++++-------------
+ 1 file changed, 22 insertions(+), 22 deletions(-)
+
+diff --git a/drivers/pinctrl/bcm/pinctrl-bcm281xx.c b/drivers/pinctrl/bcm/pinctrl-bcm281xx.c
+index cf6efa9c0364a..a039b490cdb8e 100644
+--- a/drivers/pinctrl/bcm/pinctrl-bcm281xx.c
++++ b/drivers/pinctrl/bcm/pinctrl-bcm281xx.c
+@@ -72,7 +72,7 @@ static enum bcm281xx_pin_type hdmi_pin = BCM281XX_PIN_TYPE_HDMI;
+ struct bcm281xx_pin_function {
+ const char *name;
+ const char * const *groups;
+- const unsigned ngroups;
++ const unsigned int ngroups;
+ };
+
+ /*
+@@ -84,10 +84,10 @@ struct bcm281xx_pinctrl_data {
+
+ /* List of all pins */
+ const struct pinctrl_pin_desc *pins;
+- const unsigned npins;
++ const unsigned int npins;
+
+ const struct bcm281xx_pin_function *functions;
+- const unsigned nfunctions;
++ const unsigned int nfunctions;
+
+ struct regmap *regmap;
+ };
+@@ -941,7 +941,7 @@ static struct bcm281xx_pinctrl_data bcm281xx_pinctrl = {
+ };
+
+ static inline enum bcm281xx_pin_type pin_type_get(struct pinctrl_dev *pctldev,
+- unsigned pin)
++ unsigned int pin)
+ {
+ struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
+
+@@ -985,7 +985,7 @@ static int bcm281xx_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
+ }
+
+ static const char *bcm281xx_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
+- unsigned group)
++ unsigned int group)
+ {
+ struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
+
+@@ -993,9 +993,9 @@ static const char *bcm281xx_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
+ }
+
+ static int bcm281xx_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
+- unsigned group,
++ unsigned int group,
+ const unsigned **pins,
+- unsigned *num_pins)
++ unsigned int *num_pins)
+ {
+ struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
+
+@@ -1007,7 +1007,7 @@ static int bcm281xx_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
+
+ static void bcm281xx_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev,
+ struct seq_file *s,
+- unsigned offset)
++ unsigned int offset)
+ {
+ seq_printf(s, " %s", dev_name(pctldev->dev));
+ }
+@@ -1029,7 +1029,7 @@ static int bcm281xx_pinctrl_get_fcns_count(struct pinctrl_dev *pctldev)
+ }
+
+ static const char *bcm281xx_pinctrl_get_fcn_name(struct pinctrl_dev *pctldev,
+- unsigned function)
++ unsigned int function)
+ {
+ struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
+
+@@ -1037,9 +1037,9 @@ static const char *bcm281xx_pinctrl_get_fcn_name(struct pinctrl_dev *pctldev,
+ }
+
+ static int bcm281xx_pinctrl_get_fcn_groups(struct pinctrl_dev *pctldev,
+- unsigned function,
++ unsigned int function,
+ const char * const **groups,
+- unsigned * const num_groups)
++ unsigned int * const num_groups)
+ {
+ struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
+
+@@ -1050,8 +1050,8 @@ static int bcm281xx_pinctrl_get_fcn_groups(struct pinctrl_dev *pctldev,
+ }
+
+ static int bcm281xx_pinmux_set(struct pinctrl_dev *pctldev,
+- unsigned function,
+- unsigned group)
++ unsigned int function,
++ unsigned int group)
+ {
+ struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
+ const struct bcm281xx_pin_function *f = &pdata->functions[function];
+@@ -1082,7 +1082,7 @@ static const struct pinmux_ops bcm281xx_pinctrl_pinmux_ops = {
+ };
+
+ static int bcm281xx_pinctrl_pin_config_get(struct pinctrl_dev *pctldev,
+- unsigned pin,
++ unsigned int pin,
+ unsigned long *config)
+ {
+ return -ENOTSUPP;
+@@ -1091,9 +1091,9 @@ static int bcm281xx_pinctrl_pin_config_get(struct pinctrl_dev *pctldev,
+
+ /* Goes through the configs and update register val/mask */
+ static int bcm281xx_std_pin_update(struct pinctrl_dev *pctldev,
+- unsigned pin,
++ unsigned int pin,
+ unsigned long *configs,
+- unsigned num_configs,
++ unsigned int num_configs,
+ u32 *val,
+ u32 *mask)
+ {
+@@ -1207,9 +1207,9 @@ static const u16 bcm281xx_pullup_map[] = {
+
+ /* Goes through the configs and update register val/mask */
+ static int bcm281xx_i2c_pin_update(struct pinctrl_dev *pctldev,
+- unsigned pin,
++ unsigned int pin,
+ unsigned long *configs,
+- unsigned num_configs,
++ unsigned int num_configs,
+ u32 *val,
+ u32 *mask)
+ {
+@@ -1277,9 +1277,9 @@ static int bcm281xx_i2c_pin_update(struct pinctrl_dev *pctldev,
+
+ /* Goes through the configs and update register val/mask */
+ static int bcm281xx_hdmi_pin_update(struct pinctrl_dev *pctldev,
+- unsigned pin,
++ unsigned int pin,
+ unsigned long *configs,
+- unsigned num_configs,
++ unsigned int num_configs,
+ u32 *val,
+ u32 *mask)
+ {
+@@ -1321,9 +1321,9 @@ static int bcm281xx_hdmi_pin_update(struct pinctrl_dev *pctldev,
+ }
+
+ static int bcm281xx_pinctrl_pin_config_set(struct pinctrl_dev *pctldev,
+- unsigned pin,
++ unsigned int pin,
+ unsigned long *configs,
+- unsigned num_configs)
++ unsigned int num_configs)
+ {
+ struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
+ enum bcm281xx_pin_type pin_type;
+--
+2.39.5
+
--- /dev/null
+From f64965768b29605f42028d0a655d263225bf8049 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Jan 2025 18:00:09 +0100
+Subject: pinctrl: devicetree: do not goto err when probing hogs in
+ pinctrl_dt_to_map
+
+From: Valentin Caron <valentin.caron@foss.st.com>
+
+[ Upstream commit c98868e816209e568c9d72023ba0bc1e4d96e611 ]
+
+Cross case in pinctrl framework make impossible to an hogged pin and
+another, not hogged, used within the same device-tree node. For example
+with this simplified device-tree :
+
+ &pinctrl {
+ pinctrl_pin_1: pinctrl-pin-1 {
+ pins = "dummy-pinctrl-pin";
+ };
+ };
+
+ &rtc {
+ pinctrl-names = "default"
+ pinctrl-0 = <&pinctrl_pin_1 &rtc_pin_1>
+
+ rtc_pin_1: rtc-pin-1 {
+ pins = "dummy-rtc-pin";
+ };
+ };
+
+"pinctrl_pin_1" configuration is never set. This produces this path in
+the code:
+
+ really_probe()
+ pinctrl_bind_pins()
+ | devm_pinctrl_get()
+ | pinctrl_get()
+ | create_pinctrl()
+ | pinctrl_dt_to_map()
+ | // Hog pin create an abort for all pins of the node
+ | ret = dt_to_map_one_config()
+ | | /* Do not defer probing of hogs (circular loop) */
+ | | if (np_pctldev == p->dev->of_node)
+ | | return -ENODEV;
+ | if (ret)
+ | goto err
+ |
+ call_driver_probe()
+ stm32_rtc_probe()
+ pinctrl_enable()
+ pinctrl_claim_hogs()
+ create_pinctrl()
+ for_each_maps(maps_node, i, map)
+ // Not hog pin is skipped
+ if (pctldev && strcmp(dev_name(pctldev->dev),
+ map->ctrl_dev_name))
+ continue;
+
+At the first call of create_pinctrl() the hogged pin produces an abort to
+avoid a defer of hogged pins. All other pin configurations are trashed.
+
+At the second call, create_pinctrl is now called with pctldev parameter to
+get hogs, but in this context only hogs are set. And other pins are
+skipped.
+
+To handle this, do not produce an abort in the first call of
+create_pinctrl(). Classic pin configuration will be set in
+pinctrl_bind_pins() context. And the hogged pin configuration will be set
+in pinctrl_claim_hogs() context.
+
+Signed-off-by: Valentin Caron <valentin.caron@foss.st.com>
+Link: https://lore.kernel.org/20250116170009.2075544-1-valentin.caron@foss.st.com
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pinctrl/devicetree.c | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c
+index 6a94ecd6a8dea..0b7f74beb6a6a 100644
+--- a/drivers/pinctrl/devicetree.c
++++ b/drivers/pinctrl/devicetree.c
+@@ -143,10 +143,14 @@ static int dt_to_map_one_config(struct pinctrl *p,
+ pctldev = get_pinctrl_dev_from_of_node(np_pctldev);
+ if (pctldev)
+ break;
+- /* Do not defer probing of hogs (circular loop) */
++ /*
++ * Do not defer probing of hogs (circular loop)
++ *
++ * Return 1 to let the caller catch the case.
++ */
+ if (np_pctldev == p->dev->of_node) {
+ of_node_put(np_pctldev);
+- return -ENODEV;
++ return 1;
+ }
+ }
+ of_node_put(np_pctldev);
+@@ -265,6 +269,8 @@ int pinctrl_dt_to_map(struct pinctrl *p, struct pinctrl_dev *pctldev)
+ ret = dt_to_map_one_config(p, pctldev, statename,
+ np_config);
+ of_node_put(np_config);
++ if (ret == 1)
++ continue;
+ if (ret < 0)
+ goto err;
+ }
+--
+2.39.5
+
--- /dev/null
+From c0b2ee0a75fba3f97c5caeb9f7a314d827311072 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 29 Mar 2025 20:01:32 +0100
+Subject: pinctrl: meson: define the pull up/down resistor value as 60 kOhm
+
+From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+
+[ Upstream commit e56088a13708757da68ad035269d69b93ac8c389 ]
+
+The public datasheets of the following Amlogic SoCs describe a typical
+resistor value for the built-in pull up/down resistor:
+- Meson8/8b/8m2: not documented
+- GXBB (S905): 60 kOhm
+- GXL (S905X): 60 kOhm
+- GXM (S912): 60 kOhm
+- G12B (S922X): 60 kOhm
+- SM1 (S905D3): 60 kOhm
+
+The public G12B and SM1 datasheets additionally state min and max
+values:
+- min value: 50 kOhm for both, pull-up and pull-down
+- max value for the pull-up: 70 kOhm
+- max value for the pull-down: 130 kOhm
+
+Use 60 kOhm in the pinctrl-meson driver as well so it's shown in the
+debugfs output. It may not be accurate for Meson8/8b/8m2 but in reality
+60 kOhm is closer to the actual value than 1 Ohm.
+
+Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
+Link: https://lore.kernel.org/20250329190132.855196-1-martin.blumenstingl@googlemail.com
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pinctrl/meson/pinctrl-meson.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c
+index 253a0cc57e396..e5a32a0532eee 100644
+--- a/drivers/pinctrl/meson/pinctrl-meson.c
++++ b/drivers/pinctrl/meson/pinctrl-meson.c
+@@ -487,7 +487,7 @@ static int meson_pinconf_get(struct pinctrl_dev *pcdev, unsigned int pin,
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ case PIN_CONFIG_BIAS_PULL_UP:
+ if (meson_pinconf_get_pull(pc, pin) == param)
+- arg = 1;
++ arg = 60000;
+ else
+ return -EINVAL;
+ break;
+--
+2.39.5
+
--- /dev/null
+From d9a88d89d2c5bac1c3f4ab003c1b5e793e088b32 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Feb 2025 23:37:48 +0100
+Subject: pinctrl: qcom: msm8917: Add MSM8937 wsa_reset pin
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Dang Huynh <danct12@riseup.net>
+
+[ Upstream commit 3dd3ab690172b11758e17775cfbf98986ec0cb71 ]
+
+It looks like both 8917 and 8937 are the same except for one pin
+"wsa_reset".
+
+Signed-off-by: Dang Huynh <danct12@riseup.net>
+Signed-off-by: Barnabás Czémán <barnabas.czeman@mainlining.org>
+Link: https://lore.kernel.org/20250211-msm8937-v1-4-7d27ed67f708@mainlining.org
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pinctrl/qcom/Kconfig.msm | 4 ++--
+ drivers/pinctrl/qcom/pinctrl-msm8917.c | 8 +++++++-
+ 2 files changed, 9 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/pinctrl/qcom/Kconfig.msm b/drivers/pinctrl/qcom/Kconfig.msm
+index 35f47660a56b1..a0d63a6725393 100644
+--- a/drivers/pinctrl/qcom/Kconfig.msm
++++ b/drivers/pinctrl/qcom/Kconfig.msm
+@@ -138,10 +138,10 @@ config PINCTRL_MSM8916
+ Qualcomm TLMM block found on the Qualcomm 8916 platform.
+
+ config PINCTRL_MSM8917
+- tristate "Qualcomm 8917 pin controller driver"
++ tristate "Qualcomm 8917/8937 pin controller driver"
+ help
+ This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+- Qualcomm TLMM block found on the Qualcomm MSM8917 platform.
++ Qualcomm TLMM block found on the Qualcomm MSM8917, MSM8937 platform.
+
+ config PINCTRL_MSM8953
+ tristate "Qualcomm 8953 pin controller driver"
+diff --git a/drivers/pinctrl/qcom/pinctrl-msm8917.c b/drivers/pinctrl/qcom/pinctrl-msm8917.c
+index cff137bb3b23f..350636807b07d 100644
+--- a/drivers/pinctrl/qcom/pinctrl-msm8917.c
++++ b/drivers/pinctrl/qcom/pinctrl-msm8917.c
+@@ -539,6 +539,7 @@ enum msm8917_functions {
+ msm_mux_webcam_standby,
+ msm_mux_wsa_io,
+ msm_mux_wsa_irq,
++ msm_mux_wsa_reset,
+ msm_mux__,
+ };
+
+@@ -1123,6 +1124,10 @@ static const char * const wsa_io_groups[] = {
+ "gpio94", "gpio95",
+ };
+
++static const char * const wsa_reset_groups[] = {
++ "gpio96",
++};
++
+ static const char * const blsp_spi8_groups[] = {
+ "gpio96", "gpio97", "gpio98", "gpio99",
+ };
+@@ -1378,6 +1383,7 @@ static const struct pinfunction msm8917_functions[] = {
+ MSM_PIN_FUNCTION(webcam_standby),
+ MSM_PIN_FUNCTION(wsa_io),
+ MSM_PIN_FUNCTION(wsa_irq),
++ MSM_PIN_FUNCTION(wsa_reset),
+ };
+
+ static const struct msm_pingroup msm8917_groups[] = {
+@@ -1616,5 +1622,5 @@ static void __exit msm8917_pinctrl_exit(void)
+ }
+ module_exit(msm8917_pinctrl_exit);
+
+-MODULE_DESCRIPTION("Qualcomm msm8917 pinctrl driver");
++MODULE_DESCRIPTION("Qualcomm msm8917/msm8937 pinctrl driver");
+ MODULE_LICENSE("GPL");
+--
+2.39.5
+
--- /dev/null
+From 324b9d04f699965e3669710b0fa0263fa0ae9fba Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Feb 2025 12:01:16 +0200
+Subject: pinctrl: renesas: rzg2l: Add suspend/resume support for pull up/down
+
+From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
+
+[ Upstream commit b2bd65fbb617353e3c46ba5206b3b030fa0f260c ]
+
+The Renesas RZ/G3S supports a power-saving mode where power to most of
+the SoC components is lost, including the PIN controller. Save and
+restore the pull-up/pull-down register contents to ensure the
+functionality is preserved after a suspend/resume cycle.
+
+Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
+Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
+Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
+Link: https://lore.kernel.org/20250205100116.2032765-1-claudiu.beznea.uj@bp.renesas.com
+Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pinctrl/renesas/pinctrl-rzg2l.c | 19 ++++++++++++++++++-
+ 1 file changed, 18 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c
+index d1da7f53fc600..c72e250f4a154 100644
+--- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c
++++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c
+@@ -318,6 +318,7 @@ struct rzg2l_pinctrl_pin_settings {
+ * @pmc: PMC registers cache
+ * @pfc: PFC registers cache
+ * @iolh: IOLH registers cache
++ * @pupd: PUPD registers cache
+ * @ien: IEN registers cache
+ * @sd_ch: SD_CH registers cache
+ * @eth_poc: ET_POC registers cache
+@@ -331,6 +332,7 @@ struct rzg2l_pinctrl_reg_cache {
+ u32 *pfc;
+ u32 *iolh[2];
+ u32 *ien[2];
++ u32 *pupd[2];
+ u8 sd_ch[2];
+ u8 eth_poc[2];
+ u8 eth_mode;
+@@ -2712,6 +2714,11 @@ static int rzg2l_pinctrl_reg_cache_alloc(struct rzg2l_pinctrl *pctrl)
+ if (!cache->ien[i])
+ return -ENOMEM;
+
++ cache->pupd[i] = devm_kcalloc(pctrl->dev, nports, sizeof(*cache->pupd[i]),
++ GFP_KERNEL);
++ if (!cache->pupd[i])
++ return -ENOMEM;
++
+ /* Allocate dedicated cache. */
+ dedicated_cache->iolh[i] = devm_kcalloc(pctrl->dev, n_dedicated_pins,
+ sizeof(*dedicated_cache->iolh[i]),
+@@ -2955,7 +2962,7 @@ static void rzg2l_pinctrl_pm_setup_regs(struct rzg2l_pinctrl *pctrl, bool suspen
+ struct rzg2l_pinctrl_reg_cache *cache = pctrl->cache;
+
+ for (u32 port = 0; port < nports; port++) {
+- bool has_iolh, has_ien;
++ bool has_iolh, has_ien, has_pupd;
+ u32 off, caps;
+ u8 pincnt;
+ u64 cfg;
+@@ -2967,6 +2974,7 @@ static void rzg2l_pinctrl_pm_setup_regs(struct rzg2l_pinctrl *pctrl, bool suspen
+ caps = FIELD_GET(PIN_CFG_MASK, cfg);
+ has_iolh = !!(caps & (PIN_CFG_IOLH_A | PIN_CFG_IOLH_B | PIN_CFG_IOLH_C));
+ has_ien = !!(caps & PIN_CFG_IEN);
++ has_pupd = !!(caps & PIN_CFG_PUPD);
+
+ if (suspend)
+ RZG2L_PCTRL_REG_ACCESS32(suspend, pctrl->base + PFC(off), cache->pfc[port]);
+@@ -2985,6 +2993,15 @@ static void rzg2l_pinctrl_pm_setup_regs(struct rzg2l_pinctrl *pctrl, bool suspen
+ }
+ }
+
++ if (has_pupd) {
++ RZG2L_PCTRL_REG_ACCESS32(suspend, pctrl->base + PUPD(off),
++ cache->pupd[0][port]);
++ if (pincnt >= 4) {
++ RZG2L_PCTRL_REG_ACCESS32(suspend, pctrl->base + PUPD(off),
++ cache->pupd[1][port]);
++ }
++ }
++
+ RZG2L_PCTRL_REG_ACCESS16(suspend, pctrl->base + PM(off), cache->pm[port]);
+ RZG2L_PCTRL_REG_ACCESS8(suspend, pctrl->base + P(off), cache->p[port]);
+
+--
+2.39.5
+
--- /dev/null
+From db7f0025301d0a8eb36b9879e10fbee41a6565ee Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Feb 2025 13:17:49 +0800
+Subject: pinctrl: sophgo: avoid to modify untouched bit when setting cv1800
+ pinconf
+
+From: Inochi Amaoto <inochiama@gmail.com>
+
+[ Upstream commit ef1a5121ae3da02372fcb66d9632ed3d47ad5637 ]
+
+When setting pinconf configuration for cv1800 SoC, the driver just writes
+the value. It may zero some bits of the pinconf register and cause some
+unexpected error. Add a mask to avoid this.
+
+Signed-off-by: Inochi Amaoto <inochiama@gmail.com>
+Link: https://lore.kernel.org/20250211051801.470800-2-inochiama@gmail.com
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pinctrl/sophgo/pinctrl-cv18xx.c | 33 +++++++++++++++++--------
+ 1 file changed, 23 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/pinctrl/sophgo/pinctrl-cv18xx.c b/drivers/pinctrl/sophgo/pinctrl-cv18xx.c
+index 57f2674e75d68..84b4850771ce2 100644
+--- a/drivers/pinctrl/sophgo/pinctrl-cv18xx.c
++++ b/drivers/pinctrl/sophgo/pinctrl-cv18xx.c
+@@ -574,10 +574,10 @@ static int cv1800_pinconf_compute_config(struct cv1800_pinctrl *pctrl,
+ struct cv1800_pin *pin,
+ unsigned long *configs,
+ unsigned int num_configs,
+- u32 *value)
++ u32 *value, u32 *mask)
+ {
+ int i;
+- u32 v = 0;
++ u32 v = 0, m = 0;
+ enum cv1800_pin_io_type type;
+ int ret;
+
+@@ -596,10 +596,12 @@ static int cv1800_pinconf_compute_config(struct cv1800_pinctrl *pctrl,
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ v &= ~PIN_IO_PULLDOWN;
+ v |= FIELD_PREP(PIN_IO_PULLDOWN, arg);
++ m |= PIN_IO_PULLDOWN;
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ v &= ~PIN_IO_PULLUP;
+ v |= FIELD_PREP(PIN_IO_PULLUP, arg);
++ m |= PIN_IO_PULLUP;
+ break;
+ case PIN_CONFIG_DRIVE_STRENGTH_UA:
+ ret = cv1800_pinctrl_oc2reg(pctrl, pin, arg);
+@@ -607,6 +609,7 @@ static int cv1800_pinconf_compute_config(struct cv1800_pinctrl *pctrl,
+ return ret;
+ v &= ~PIN_IO_DRIVE;
+ v |= FIELD_PREP(PIN_IO_DRIVE, ret);
++ m |= PIN_IO_DRIVE;
+ break;
+ case PIN_CONFIG_INPUT_SCHMITT_UV:
+ ret = cv1800_pinctrl_schmitt2reg(pctrl, pin, arg);
+@@ -614,6 +617,7 @@ static int cv1800_pinconf_compute_config(struct cv1800_pinctrl *pctrl,
+ return ret;
+ v &= ~PIN_IO_SCHMITT;
+ v |= FIELD_PREP(PIN_IO_SCHMITT, ret);
++ m |= PIN_IO_SCHMITT;
+ break;
+ case PIN_CONFIG_POWER_SOURCE:
+ /* Ignore power source as it is always fixed */
+@@ -621,10 +625,12 @@ static int cv1800_pinconf_compute_config(struct cv1800_pinctrl *pctrl,
+ case PIN_CONFIG_SLEW_RATE:
+ v &= ~PIN_IO_OUT_FAST_SLEW;
+ v |= FIELD_PREP(PIN_IO_OUT_FAST_SLEW, arg);
++ m |= PIN_IO_OUT_FAST_SLEW;
+ break;
+ case PIN_CONFIG_BIAS_BUS_HOLD:
+ v &= ~PIN_IO_BUS_HOLD;
+ v |= FIELD_PREP(PIN_IO_BUS_HOLD, arg);
++ m |= PIN_IO_BUS_HOLD;
+ break;
+ default:
+ return -ENOTSUPP;
+@@ -632,17 +638,19 @@ static int cv1800_pinconf_compute_config(struct cv1800_pinctrl *pctrl,
+ }
+
+ *value = v;
++ *mask = m;
+
+ return 0;
+ }
+
+ static int cv1800_pin_set_config(struct cv1800_pinctrl *pctrl,
+ unsigned int pin_id,
+- u32 value)
++ u32 value, u32 mask)
+ {
+ struct cv1800_pin *pin = cv1800_get_pin(pctrl, pin_id);
+ unsigned long flags;
+ void __iomem *addr;
++ u32 reg;
+
+ if (!pin)
+ return -EINVAL;
+@@ -650,7 +658,10 @@ static int cv1800_pin_set_config(struct cv1800_pinctrl *pctrl,
+ addr = cv1800_pinctrl_get_component_addr(pctrl, &pin->conf);
+
+ raw_spin_lock_irqsave(&pctrl->lock, flags);
+- writel(value, addr);
++ reg = readl(addr);
++ reg &= ~mask;
++ reg |= value;
++ writel(reg, addr);
+ raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+
+ return 0;
+@@ -662,16 +673,17 @@ static int cv1800_pconf_set(struct pinctrl_dev *pctldev,
+ {
+ struct cv1800_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ struct cv1800_pin *pin = cv1800_get_pin(pctrl, pin_id);
+- u32 value;
++ u32 value, mask;
+
+ if (!pin)
+ return -ENODEV;
+
+ if (cv1800_pinconf_compute_config(pctrl, pin,
+- configs, num_configs, &value))
++ configs, num_configs,
++ &value, &mask))
+ return -ENOTSUPP;
+
+- return cv1800_pin_set_config(pctrl, pin_id, value);
++ return cv1800_pin_set_config(pctrl, pin_id, value, mask);
+ }
+
+ static int cv1800_pconf_group_set(struct pinctrl_dev *pctldev,
+@@ -682,7 +694,7 @@ static int cv1800_pconf_group_set(struct pinctrl_dev *pctldev,
+ struct cv1800_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ const struct group_desc *group;
+ const struct cv1800_pin_mux_config *pinmuxs;
+- u32 value;
++ u32 value, mask;
+ int i;
+
+ group = pinctrl_generic_get_group(pctldev, gsel);
+@@ -692,11 +704,12 @@ static int cv1800_pconf_group_set(struct pinctrl_dev *pctldev,
+ pinmuxs = group->data;
+
+ if (cv1800_pinconf_compute_config(pctrl, pinmuxs[0].pin,
+- configs, num_configs, &value))
++ configs, num_configs,
++ &value, &mask))
+ return -ENOTSUPP;
+
+ for (i = 0; i < group->grp.npins; i++)
+- cv1800_pin_set_config(pctrl, group->grp.pins[i], value);
++ cv1800_pin_set_config(pctrl, group->grp.pins[i], value, mask);
+
+ return 0;
+ }
+--
+2.39.5
+
--- /dev/null
+From e9857d4ebbe88d4499a75b5d2f1ae2a57e279650 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 19 Mar 2025 10:05:47 +0300
+Subject: pinctrl: tegra: Fix off by one in tegra_pinctrl_get_group()
+
+From: Dan Carpenter <dan.carpenter@linaro.org>
+
+[ Upstream commit 5a062c3c3b82004766bc3ece82b594d337076152 ]
+
+This should be >= pmx->soc->ngroups instead of > to avoid an out of
+bounds access. The pmx->soc->groups[] array is allocated in
+tegra_pinctrl_probe().
+
+Fixes: c12bfa0fee65 ("pinctrl-tegra: Restore SFSEL bit when freeing pins")
+Signed-off-by: Dan Carpenter <dan.carpenter@linaro.org>
+Reviewed-by: Kunwu Chan <kunwu.chan@linux.dev>
+Link: https://lore.kernel.org/82b40d9d-b437-42a9-9eb3-2328aa6877ac@stanley.mountain
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pinctrl/tegra/pinctrl-tegra.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c
+index 27823e4207347..edcc78ebce456 100644
+--- a/drivers/pinctrl/tegra/pinctrl-tegra.c
++++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
+@@ -305,7 +305,7 @@ static const struct tegra_pingroup *tegra_pinctrl_get_group(struct pinctrl_dev *
+ {
+ struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+- if (group_index < 0 || group_index > pmx->soc->ngroups)
++ if (group_index < 0 || group_index >= pmx->soc->ngroups)
+ return NULL;
+
+ return &pmx->soc->groups[group_index];
+--
+2.39.5
+
--- /dev/null
+From 2394c65349756f79eba1aeb1cc111785ea01d10b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Mar 2025 16:19:39 +0530
+Subject: pinctrl-tegra: Restore SFSEL bit when freeing pins
+
+From: Prathamesh Shete <pshete@nvidia.com>
+
+[ Upstream commit c12bfa0fee65940b10ff5187349f76c6f6b1df9c ]
+
+Each pin can be configured as a Special Function IO (SFIO) or GPIO,
+where the SFIO enables the pin to operate in alternative modes such as
+I2C, SPI, etc.
+
+The current implementation sets all the pins back to SFIO mode
+even if they were initially in GPIO mode. This can cause glitches
+on the pins when pinctrl_gpio_free() is called.
+
+Avoid these undesired glitches by storing the pin's SFIO/GPIO
+state on GPIO request and restoring it on GPIO free.
+
+Signed-off-by: Prathamesh Shete <pshete@nvidia.com>
+Link: https://lore.kernel.org/20250305104939.15168-2-pshete@nvidia.com
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pinctrl/tegra/pinctrl-tegra.c | 59 +++++++++++++++++++++++----
+ drivers/pinctrl/tegra/pinctrl-tegra.h | 6 +++
+ 2 files changed, 57 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c
+index 3b046450bd3ff..27823e4207347 100644
+--- a/drivers/pinctrl/tegra/pinctrl-tegra.c
++++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
+@@ -278,8 +278,8 @@ static int tegra_pinctrl_set_mux(struct pinctrl_dev *pctldev,
+ return 0;
+ }
+
+-static const struct tegra_pingroup *tegra_pinctrl_get_group(struct pinctrl_dev *pctldev,
+- unsigned int offset)
++static int tegra_pinctrl_get_group_index(struct pinctrl_dev *pctldev,
++ unsigned int offset)
+ {
+ struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+ unsigned int group, num_pins, j;
+@@ -292,12 +292,35 @@ static const struct tegra_pingroup *tegra_pinctrl_get_group(struct pinctrl_dev *
+ continue;
+ for (j = 0; j < num_pins; j++) {
+ if (offset == pins[j])
+- return &pmx->soc->groups[group];
++ return group;
+ }
+ }
+
+- dev_err(pctldev->dev, "Pingroup not found for pin %u\n", offset);
+- return NULL;
++ return -EINVAL;
++}
++
++static const struct tegra_pingroup *tegra_pinctrl_get_group(struct pinctrl_dev *pctldev,
++ unsigned int offset,
++ int group_index)
++{
++ struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
++
++ if (group_index < 0 || group_index > pmx->soc->ngroups)
++ return NULL;
++
++ return &pmx->soc->groups[group_index];
++}
++
++static struct tegra_pingroup_config *tegra_pinctrl_get_group_config(struct pinctrl_dev *pctldev,
++ unsigned int offset,
++ int group_index)
++{
++ struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
++
++ if (group_index < 0)
++ return NULL;
++
++ return &pmx->pingroup_configs[group_index];
+ }
+
+ static int tegra_pinctrl_gpio_request_enable(struct pinctrl_dev *pctldev,
+@@ -306,12 +329,15 @@ static int tegra_pinctrl_gpio_request_enable(struct pinctrl_dev *pctldev,
+ {
+ struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+ const struct tegra_pingroup *group;
++ struct tegra_pingroup_config *config;
++ int group_index;
+ u32 value;
+
+ if (!pmx->soc->sfsel_in_mux)
+ return 0;
+
+- group = tegra_pinctrl_get_group(pctldev, offset);
++ group_index = tegra_pinctrl_get_group_index(pctldev, offset);
++ group = tegra_pinctrl_get_group(pctldev, offset, group_index);
+
+ if (!group)
+ return -EINVAL;
+@@ -319,7 +345,11 @@ static int tegra_pinctrl_gpio_request_enable(struct pinctrl_dev *pctldev,
+ if (group->mux_reg < 0 || group->sfsel_bit < 0)
+ return -EINVAL;
+
++ config = tegra_pinctrl_get_group_config(pctldev, offset, group_index);
++ if (!config)
++ return -EINVAL;
+ value = pmx_readl(pmx, group->mux_bank, group->mux_reg);
++ config->is_sfsel = (value & BIT(group->sfsel_bit)) != 0;
+ value &= ~BIT(group->sfsel_bit);
+ pmx_writel(pmx, value, group->mux_bank, group->mux_reg);
+
+@@ -332,12 +362,15 @@ static void tegra_pinctrl_gpio_disable_free(struct pinctrl_dev *pctldev,
+ {
+ struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+ const struct tegra_pingroup *group;
++ struct tegra_pingroup_config *config;
++ int group_index;
+ u32 value;
+
+ if (!pmx->soc->sfsel_in_mux)
+ return;
+
+- group = tegra_pinctrl_get_group(pctldev, offset);
++ group_index = tegra_pinctrl_get_group_index(pctldev, offset);
++ group = tegra_pinctrl_get_group(pctldev, offset, group_index);
+
+ if (!group)
+ return;
+@@ -345,8 +378,12 @@ static void tegra_pinctrl_gpio_disable_free(struct pinctrl_dev *pctldev,
+ if (group->mux_reg < 0 || group->sfsel_bit < 0)
+ return;
+
++ config = tegra_pinctrl_get_group_config(pctldev, offset, group_index);
++ if (!config)
++ return;
+ value = pmx_readl(pmx, group->mux_bank, group->mux_reg);
+- value |= BIT(group->sfsel_bit);
++ if (config->is_sfsel)
++ value |= BIT(group->sfsel_bit);
+ pmx_writel(pmx, value, group->mux_bank, group->mux_reg);
+ }
+
+@@ -791,6 +828,12 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
+ pmx->dev = &pdev->dev;
+ pmx->soc = soc_data;
+
++ pmx->pingroup_configs = devm_kcalloc(&pdev->dev,
++ pmx->soc->ngroups, sizeof(*pmx->pingroup_configs),
++ GFP_KERNEL);
++ if (!pmx->pingroup_configs)
++ return -ENOMEM;
++
+ /*
+ * Each mux group will appear in 4 functions' list of groups.
+ * This over-allocates slightly, since not all groups are mux groups.
+diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.h b/drivers/pinctrl/tegra/pinctrl-tegra.h
+index b3289bdf727d8..b97136685f7a8 100644
+--- a/drivers/pinctrl/tegra/pinctrl-tegra.h
++++ b/drivers/pinctrl/tegra/pinctrl-tegra.h
+@@ -8,6 +8,10 @@
+ #ifndef __PINMUX_TEGRA_H__
+ #define __PINMUX_TEGRA_H__
+
++struct tegra_pingroup_config {
++ bool is_sfsel;
++};
++
+ struct tegra_pmx {
+ struct device *dev;
+ struct pinctrl_dev *pctl;
+@@ -21,6 +25,8 @@ struct tegra_pmx {
+ int nbanks;
+ void __iomem **regs;
+ u32 *backup_regs;
++ /* Array of size soc->ngroups */
++ struct tegra_pingroup_config *pingroup_configs;
+ };
+
+ enum tegra_pinconf_param {
+--
+2.39.5
+
--- /dev/null
+From 2f6bdbaac46e46f466031836f83dece625380100 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 18 Apr 2025 20:06:08 +0600
+Subject: platform/x86: asus-wmi: Disable OOBE state after resume from
+ hibernation
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Pavel Nikulin <pavel@noa-labs.com>
+
+[ Upstream commit 77bdac73754e4c0c564c1ca80fe3d9c93b0e715a ]
+
+ASUS firmware resets OOBE state during S4 suspend, so the keyboard
+blinks during resume from hibernation. This patch disables OOBE state
+after resume from hibernation.
+
+Signed-off-by: Pavel Nikulin <pavel@noa-labs.com>
+Link: https://lore.kernel.org/r/20250418140706.1691-1-pavel@noa-labs.com
+Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/platform/x86/asus-wmi.c | 11 ++++++++++-
+ 1 file changed, 10 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
+index f66d152e265da..47cc766624d7b 100644
+--- a/drivers/platform/x86/asus-wmi.c
++++ b/drivers/platform/x86/asus-wmi.c
+@@ -304,6 +304,7 @@ struct asus_wmi {
+
+ u32 kbd_rgb_dev;
+ bool kbd_rgb_state_available;
++ bool oobe_state_available;
+
+ u8 throttle_thermal_policy_mode;
+ u32 throttle_thermal_policy_dev;
+@@ -1826,7 +1827,7 @@ static int asus_wmi_led_init(struct asus_wmi *asus)
+ goto error;
+ }
+
+- if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_OOBE)) {
++ if (asus->oobe_state_available) {
+ /*
+ * Disable OOBE state, so that e.g. the keyboard backlight
+ * works.
+@@ -4723,6 +4724,7 @@ static int asus_wmi_add(struct platform_device *pdev)
+ asus->egpu_enable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_EGPU);
+ asus->dgpu_disable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_DGPU);
+ asus->kbd_rgb_state_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_STATE);
++ asus->oobe_state_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_OOBE);
+ asus->ally_mcu_usb_switch = acpi_has_method(NULL, ASUS_USB0_PWR_EC0_CSEE)
+ && dmi_check_system(asus_ally_mcu_quirk);
+
+@@ -4971,6 +4973,13 @@ static int asus_hotk_restore(struct device *device)
+ }
+ if (!IS_ERR_OR_NULL(asus->kbd_led.dev))
+ kbd_led_update(asus);
++ if (asus->oobe_state_available) {
++ /*
++ * Disable OOBE state, so that e.g. the keyboard backlight
++ * works.
++ */
++ asus_wmi_set_devstate(ASUS_WMI_DEVID_OOBE, 1, NULL);
++ }
+
+ if (asus_wmi_has_fnlock_key(asus))
+ asus_wmi_fnlock_update(asus);
+--
+2.39.5
+
--- /dev/null
+From 73866bb954d397a9d516ae528ef345748f8d59cb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 18 Apr 2025 09:07:38 +0200
+Subject: platform/x86: ideapad-laptop: add support for some new buttons
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Gašper Nemgar <gasper.nemgar@gmail.com>
+
+[ Upstream commit 02c6e43397c39edd0c172859bf8c851b46be09a8 ]
+
+Add entries to unsupported WMI codes in ideapad_keymap[] and one
+check for WMI code 0x13d to trigger platform_profile_cycle().
+
+Signed-off-by: Gašper Nemgar <gasper.nemgar@gmail.com>
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
+Link: https://lore.kernel.org/r/20250418070738.7171-1-gasper.nemgar@gmail.com
+[ij: joined nested if ()s & major tweaks to changelog]
+Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/platform/x86/ideapad-laptop.c | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
+index 30bd366d7b58a..b740c7bb81015 100644
+--- a/drivers/platform/x86/ideapad-laptop.c
++++ b/drivers/platform/x86/ideapad-laptop.c
+@@ -1308,6 +1308,16 @@ static const struct key_entry ideapad_keymap[] = {
+ /* Specific to some newer models */
+ { KE_KEY, 0x3e | IDEAPAD_WMI_KEY, { KEY_MICMUTE } },
+ { KE_KEY, 0x3f | IDEAPAD_WMI_KEY, { KEY_RFKILL } },
++ /* Star- (User Assignable Key) */
++ { KE_KEY, 0x44 | IDEAPAD_WMI_KEY, { KEY_PROG1 } },
++ /* Eye */
++ { KE_KEY, 0x45 | IDEAPAD_WMI_KEY, { KEY_PROG3 } },
++ /* Performance toggle also Fn+Q, handled inside ideapad_wmi_notify() */
++ { KE_KEY, 0x3d | IDEAPAD_WMI_KEY, { KEY_PROG4 } },
++ /* shift + prtsc */
++ { KE_KEY, 0x2d | IDEAPAD_WMI_KEY, { KEY_CUT } },
++ { KE_KEY, 0x29 | IDEAPAD_WMI_KEY, { KEY_TOUCHPAD_TOGGLE } },
++ { KE_KEY, 0x2a | IDEAPAD_WMI_KEY, { KEY_ROOT_MENU } },
+
+ { KE_END },
+ };
+@@ -2094,6 +2104,12 @@ static void ideapad_wmi_notify(struct wmi_device *wdev, union acpi_object *data)
+ dev_dbg(&wdev->dev, "WMI fn-key event: 0x%llx\n",
+ data->integer.value);
+
++ /* performance button triggered by 0x3d */
++ if (data->integer.value == 0x3d && priv->dytc) {
++ platform_profile_cycle();
++ break;
++ }
++
+ /* 0x02 FnLock, 0x03 Esc */
+ if (data->integer.value == 0x02 || data->integer.value == 0x03)
+ ideapad_fn_lock_led_notify(priv, data->integer.value == 0x02);
+--
+2.39.5
+
--- /dev/null
+From ad0f5950300153f41b584020458be6fde6ab8dad Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 21 Apr 2025 09:43:32 +0530
+Subject: platform/x86/intel: hid: Add Pantherlake support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Saranya Gopal <saranya.gopal@intel.com>
+
+[ Upstream commit 12df9ec3e1955aed6a0c839f2375cd8e5d5150cf ]
+
+Add Pantherlake ACPI device ID to the Intel HID driver.
+
+While there, clean up the device ID table to remove the ", 0" parts.
+
+Suggested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Signed-off-by: Saranya Gopal <saranya.gopal@intel.com>
+Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Link: https://lore.kernel.org/r/20250421041332.830136-1-saranya.gopal@intel.com
+Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/platform/x86/intel/hid.c | 21 +++++++++++----------
+ 1 file changed, 11 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/platform/x86/intel/hid.c b/drivers/platform/x86/intel/hid.c
+index 88a1a9ff2f344..0b5e43444ed60 100644
+--- a/drivers/platform/x86/intel/hid.c
++++ b/drivers/platform/x86/intel/hid.c
+@@ -44,16 +44,17 @@ MODULE_LICENSE("GPL");
+ MODULE_AUTHOR("Alex Hung");
+
+ static const struct acpi_device_id intel_hid_ids[] = {
+- {"INT33D5", 0},
+- {"INTC1051", 0},
+- {"INTC1054", 0},
+- {"INTC1070", 0},
+- {"INTC1076", 0},
+- {"INTC1077", 0},
+- {"INTC1078", 0},
+- {"INTC107B", 0},
+- {"INTC10CB", 0},
+- {"", 0},
++ { "INT33D5" },
++ { "INTC1051" },
++ { "INTC1054" },
++ { "INTC1070" },
++ { "INTC1076" },
++ { "INTC1077" },
++ { "INTC1078" },
++ { "INTC107B" },
++ { "INTC10CB" },
++ { "INTC10CC" },
++ { }
+ };
+ MODULE_DEVICE_TABLE(acpi, intel_hid_ids);
+
+--
+2.39.5
+
--- /dev/null
+From 0d5d4ef580d5aef2179eaca41a58383da5a39ace Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 24 Feb 2025 15:00:49 +0800
+Subject: PM: sleep: Suppress sleeping parent warning in special case
+
+From: Xu Yang <xu.yang_2@nxp.com>
+
+[ Upstream commit e8195f0630f1c4c2465074fe81b5fda19efd3148 ]
+
+Currently, if power.no_callbacks is set, device_prepare() will also set
+power.direct_complete for the device. If power.direct_complete is set
+in device_resume(), the clearing of power.is_prepared will be skipped
+and if new children appear under the device at that point, a warning
+will be printed.
+
+After commit (f76b168b6f11 PM: Rename dev_pm_info.in_suspend to
+is_prepared), power.is_prepared is generally cleared in device_resume()
+before invoking the resume callback for the device which allows that
+callback to add new children without triggering the warning, but this
+does not happen for devices with power.direct_complete set.
+
+This problem is visible in USB where usb_set_interface() can be called
+before device_complete() clears power.is_prepared for interface devices
+and since ep devices are added then, the warning is printed:
+
+ usb 1-1: reset high-speed USB device number 3 using ci_hdrc
+ ep_81: PM: parent 1-1:1.1 should not be sleeping
+ PM: resume devices took 0.936 seconds
+
+Since it is legitimate to add the ep devices at that point, the
+warning above is not particularly useful, so get rid of it by
+clearing power.is_prepared in device_resume() for devices with
+power.direct_complete set if they have no PM callbacks, in which
+case they need not actually resume for the new children to work.
+
+Suggested-by: Rafael J. Wysocki <rafael@kernel.org>
+Signed-off-by: Xu Yang <xu.yang_2@nxp.com>
+Link: https://patch.msgid.link/20250224070049.3338646-1-xu.yang_2@nxp.com
+[ rjw: New subject, changelog edits, rephrased new code comment ]
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/base/power/main.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
+index 23be2d1b04079..37fe251b4c591 100644
+--- a/drivers/base/power/main.c
++++ b/drivers/base/power/main.c
+@@ -933,6 +933,13 @@ static void device_resume(struct device *dev, pm_message_t state, bool async)
+ goto Complete;
+
+ if (dev->power.direct_complete) {
++ /*
++ * Allow new children to be added under the device after this
++ * point if it has no PM callbacks.
++ */
++ if (dev->power.no_pm_callbacks)
++ dev->power.is_prepared = false;
++
+ /* Match the pm_runtime_disable() in device_suspend(). */
+ pm_runtime_enable(dev);
+ goto Complete;
+--
+2.39.5
+
--- /dev/null
+From 2c462087fcefe0dc4f1c8b4e92738cf1f6f6817d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Feb 2025 20:18:32 +0100
+Subject: pmdomain: imx: gpcv2: use proper helper for property detection
+
+From: Ahmad Fatoum <a.fatoum@pengutronix.de>
+
+[ Upstream commit 6568cb40e73163fa25e2779f7234b169b2e1a32e ]
+
+Starting with commit c141ecc3cecd7 ("of: Warn when of_property_read_bool()
+is used on non-boolean properties"), probing the gpcv2 device on i.MX8M
+SoCs leads to warnings when LOCKDEP is enabled.
+
+Fix this by checking property presence with of_property_present as
+intended.
+
+Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
+Link: https://lore.kernel.org/r/20250218-gpcv2-of-property-present-v1-1-3bb1a9789654@pengutronix.de
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pmdomain/imx/gpcv2.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/pmdomain/imx/gpcv2.c b/drivers/pmdomain/imx/gpcv2.c
+index 958d34d4821b1..105fcaf13a34c 100644
+--- a/drivers/pmdomain/imx/gpcv2.c
++++ b/drivers/pmdomain/imx/gpcv2.c
+@@ -1361,7 +1361,7 @@ static int imx_pgc_domain_probe(struct platform_device *pdev)
+ }
+
+ if (IS_ENABLED(CONFIG_LOCKDEP) &&
+- of_property_read_bool(domain->dev->of_node, "power-domains"))
++ of_property_present(domain->dev->of_node, "power-domains"))
+ lockdep_set_subclass(&domain->genpd.mlock, 1);
+
+ ret = of_genpd_add_provider_simple(domain->dev->of_node,
+--
+2.39.5
+
--- /dev/null
+From 451ac17b0c01a9c04f2e0cad1cd7eccfb7c230c3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 20 Mar 2025 12:45:01 -0400
+Subject: pNFS/flexfiles: Report ENETDOWN as a connection error
+
+From: Trond Myklebust <trond.myklebust@hammerspace.com>
+
+[ Upstream commit aa42add73ce9b9e3714723d385c254b75814e335 ]
+
+If the client should see an ENETDOWN when trying to connect to the data
+server, it might still be able to talk to the metadata server through
+another NIC. If so, report the error.
+
+Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Tested-by: Jeff Layton <jlayton@kernel.org>
+Acked-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/nfs/flexfilelayout/flexfilelayout.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c
+index 98b45b636be33..646cda8e2e75b 100644
+--- a/fs/nfs/flexfilelayout/flexfilelayout.c
++++ b/fs/nfs/flexfilelayout/flexfilelayout.c
+@@ -1264,6 +1264,7 @@ static void ff_layout_io_track_ds_error(struct pnfs_layout_segment *lseg,
+ case -ECONNRESET:
+ case -EHOSTDOWN:
+ case -EHOSTUNREACH:
++ case -ENETDOWN:
+ case -ENETUNREACH:
+ case -EADDRINUSE:
+ case -ENOBUFS:
+--
+2.39.5
+
--- /dev/null
+From a8be94f05a86a3b0c29af4e3485ff9498a9fec01 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 10 Mar 2025 15:24:33 -0700
+Subject: PNP: Expand length of fixup id string
+
+From: Kees Cook <kees@kernel.org>
+
+[ Upstream commit 425b1c97b07f2290700f708edabef32861e2b2db ]
+
+GCC 15's -Wunterminated-string-initialization saw that "id" was not
+including the required trailing NUL character. Instead of marking "id"
+with __nonstring[1], expand the length of the string as it is used in
+(debugging) format strings that expect a properly formed C string.
+
+Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117178 [1]
+Signed-off-by: Kees Cook <kees@kernel.org>
+Link: https://patch.msgid.link/20250310222432.work.826-kees@kernel.org
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/pnp.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/include/linux/pnp.h b/include/linux/pnp.h
+index b7a7158aaf65e..23fe3eaf242d6 100644
+--- a/include/linux/pnp.h
++++ b/include/linux/pnp.h
+@@ -290,7 +290,7 @@ static inline void pnp_set_drvdata(struct pnp_dev *pdev, void *data)
+ }
+
+ struct pnp_fixup {
+- char id[7];
++ char id[8];
+ void (*quirk_function) (struct pnp_dev *dev); /* fixup function */
+ };
+
+--
+2.39.5
+
--- /dev/null
+From 54f9853297f1f7d76e42a6a92442ef6de2c79a6c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 8 Mar 2025 17:48:17 +0100
+Subject: posix-timers: Add cond_resched() to posix_timer_add() search loop
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit 5f2909c6cd13564a07ae692a95457f52295c4f22 ]
+
+With a large number of POSIX timers the search for a valid ID might cause a
+soft lockup on PREEMPT_NONE/VOLUNTARY kernels.
+
+Add cond_resched() to the loop to prevent that.
+
+[ tglx: Split out from Eric's series ]
+
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
+Link: https://lore.kernel.org/all/20250214135911.2037402-2-edumazet@google.com
+Link: https://lore.kernel.org/all/20250308155623.635612865@linutronix.de
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/time/posix-timers.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c
+index 1b675aee99a98..7f8644e047558 100644
+--- a/kernel/time/posix-timers.c
++++ b/kernel/time/posix-timers.c
+@@ -118,6 +118,7 @@ static int posix_timer_add(struct k_itimer *timer)
+ return id;
+ }
+ spin_unlock(&hash_lock);
++ cond_resched();
+ }
+ /* POSIX return code when no timer ID could be allocated */
+ return -EAGAIN;
+--
+2.39.5
+
--- /dev/null
+From 5dee821ca1160182f7ecb6573872768443b3f882 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 8 Mar 2025 17:48:10 +0100
+Subject: posix-timers: Ensure that timer initialization is fully visible
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+[ Upstream commit 2389c6efd3ad8edb3bcce0019b4edcc7d9c7de19 ]
+
+Frederic pointed out that the memory operations to initialize the timer are
+not guaranteed to be visible, when __lock_timer() observes timer::it_signal
+valid under timer::it_lock:
+
+ T0 T1
+ --------- -----------
+ do_timer_create()
+ // A
+ new_timer->.... = ....
+ spin_lock(current->sighand)
+ // B
+ WRITE_ONCE(new_timer->it_signal, current->signal)
+ spin_unlock(current->sighand)
+ sys_timer_*()
+ t = __lock_timer()
+ spin_lock(&timr->it_lock)
+ // observes B
+ if (timr->it_signal == current->signal)
+ return timr;
+ if (!t)
+ return;
+ // Is not guaranteed to observe A
+
+Protect the write of timer::it_signal, which makes the timer valid, with
+timer::it_lock as well. This guarantees that T1 must observe the
+initialization A completely, when it observes the valid signal pointer
+under timer::it_lock. sighand::siglock must still be taken to protect the
+signal::posix_timers list.
+
+Reported-by: Frederic Weisbecker <frederic@kernel.org>
+Suggested-by: Frederic Weisbecker <frederic@kernel.org>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
+Link: https://lore.kernel.org/all/20250308155623.507944489@linutronix.de
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/time/posix-timers.c | 21 ++++++++++++++-------
+ 1 file changed, 14 insertions(+), 7 deletions(-)
+
+diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c
+index 7f8644e047558..15ed343693101 100644
+--- a/kernel/time/posix-timers.c
++++ b/kernel/time/posix-timers.c
+@@ -463,14 +463,21 @@ static int do_timer_create(clockid_t which_clock, struct sigevent *event,
+ if (error)
+ goto out;
+
+- spin_lock_irq(¤t->sighand->siglock);
+- /* This makes the timer valid in the hash table */
+- WRITE_ONCE(new_timer->it_signal, current->signal);
+- hlist_add_head(&new_timer->list, ¤t->signal->posix_timers);
+- spin_unlock_irq(¤t->sighand->siglock);
+ /*
+- * After unlocking sighand::siglock @new_timer is subject to
+- * concurrent removal and cannot be touched anymore
++ * timer::it_lock ensures that __lock_timer() observes a fully
++ * initialized timer when it observes a valid timer::it_signal.
++ *
++ * sighand::siglock is required to protect signal::posix_timers.
++ */
++ scoped_guard (spinlock_irq, &new_timer->it_lock) {
++ guard(spinlock)(¤t->sighand->siglock);
++ /* This makes the timer valid in the hash table */
++ WRITE_ONCE(new_timer->it_signal, current->signal);
++ hlist_add_head(&new_timer->list, ¤t->signal->posix_timers);
++ }
++ /*
++ * After unlocking @new_timer is subject to concurrent removal and
++ * cannot be touched anymore
+ */
+ return 0;
+ out:
+--
+2.39.5
+
--- /dev/null
+From 4bfbf33bcab0c092bf735a3ff3aed13d13102b70 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 14 Feb 2025 14:12:20 -0800
+Subject: posix-timers: Invoke cond_resched() during exit_itimers()
+
+From: Benjamin Segall <bsegall@google.com>
+
+[ Upstream commit f99c5bb396b8d1424ed229d1ffa6f596e3b9c36b ]
+
+exit_itimers() loops through every timer in the process to delete it. This
+requires taking the system-wide hash_lock for each of these timers, and
+contends with other processes trying to create or delete timers.
+
+When a process creates hundreds of thousands of timers, and then exits
+while other processes contend with it, this can trigger softlockups on
+CONFIG_PREEMPT=n.
+
+Add a cond_resched() invocation into the loop to allow the system to make
+progress.
+
+Signed-off-by: Ben Segall <bsegall@google.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Link: https://lore.kernel.org/all/xm2634gg2n23.fsf@google.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/time/posix-timers.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c
+index 15ed343693101..43b08a04898a8 100644
+--- a/kernel/time/posix-timers.c
++++ b/kernel/time/posix-timers.c
+@@ -1107,8 +1107,10 @@ void exit_itimers(struct task_struct *tsk)
+ spin_unlock_irq(&tsk->sighand->siglock);
+
+ /* The timers are not longer accessible via tsk::signal */
+- while (!hlist_empty(&timers))
++ while (!hlist_empty(&timers)) {
+ itimer_delete(hlist_entry(timers.first, struct k_itimer, list));
++ cond_resched();
++ }
+
+ /*
+ * There should be no timers on the ignored list. itimer_delete() has
+--
+2.39.5
+
--- /dev/null
+From 16229371f5b52d4b44551de83221aa3721738460 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Feb 2025 09:58:33 -0600
+Subject: power: supply: axp20x_battery: Update temp sensor for AXP717 from
+ device tree
+
+From: Chris Morgan <macromorgan@hotmail.com>
+
+[ Upstream commit bbcfe510ecd47f2db4c8653c7dfa9dc7a55b1583 ]
+
+Allow a boolean property of "x-powers,no-thermistor" to specify devices
+where the ts pin is not connected to anything. This works around an
+issue found with some devices where the efuse is not programmed
+correctly from the factory or when the register gets set erroneously.
+
+Signed-off-by: Chris Morgan <macromorgan@hotmail.com>
+Tested-by: Philippe Simons <simons.philippe@gmail.com>
+Link: https://lore.kernel.org/r/20250204155835.161973-4-macroalpha82@gmail.com
+Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/power/supply/axp20x_battery.c | 21 +++++++++++++++++++++
+ 1 file changed, 21 insertions(+)
+
+diff --git a/drivers/power/supply/axp20x_battery.c b/drivers/power/supply/axp20x_battery.c
+index 3c3158f31a484..f4cf129a0b683 100644
+--- a/drivers/power/supply/axp20x_battery.c
++++ b/drivers/power/supply/axp20x_battery.c
+@@ -89,6 +89,8 @@
+ #define AXP717_BAT_CC_MIN_UA 0
+ #define AXP717_BAT_CC_MAX_UA 3008000
+
++#define AXP717_TS_PIN_DISABLE BIT(4)
++
+ struct axp20x_batt_ps;
+
+ struct axp_data {
+@@ -117,6 +119,7 @@ struct axp20x_batt_ps {
+ /* Maximum constant charge current */
+ unsigned int max_ccc;
+ const struct axp_data *data;
++ bool ts_disable;
+ };
+
+ static int axp20x_battery_get_max_voltage(struct axp20x_batt_ps *axp20x_batt,
+@@ -984,6 +987,24 @@ static void axp717_set_battery_info(struct platform_device *pdev,
+ int ccc = info->constant_charge_current_max_ua;
+ int val;
+
++ axp_batt->ts_disable = (device_property_read_bool(axp_batt->dev,
++ "x-powers,no-thermistor"));
++
++ /*
++ * Under rare conditions an incorrectly programmed efuse for
++ * the temp sensor on the PMIC may trigger a fault condition.
++ * Allow users to hard-code if the ts pin is not used to work
++ * around this problem. Note that this requires the battery
++ * be correctly defined in the device tree with a monitored
++ * battery node.
++ */
++ if (axp_batt->ts_disable) {
++ regmap_update_bits(axp_batt->regmap,
++ AXP717_TS_PIN_CFG,
++ AXP717_TS_PIN_DISABLE,
++ AXP717_TS_PIN_DISABLE);
++ }
++
+ if (vmin > 0 && axp717_set_voltage_min_design(axp_batt, vmin))
+ dev_err(&pdev->dev,
+ "couldn't set voltage_min_design\n");
+--
+2.39.5
+
--- /dev/null
+From b8e7d25b817a294cc98954a6370e5e165bc9b4d9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Jan 2025 18:19:09 +0100
+Subject: powerpc/prom_init: Fixup missing #size-cells on PowerBook6,7
+
+From: Andreas Schwab <schwab@linux-m68k.org>
+
+[ Upstream commit 7e67ef889c9ab7246547db73d524459f47403a77 ]
+
+Similar to the PowerMac3,1, the PowerBook6,7 is missing the #size-cells
+property on the i2s node.
+
+Depends-on: commit 045b14ca5c36 ("of: WARN on deprecated #address-cells/#size-cells handling")
+Signed-off-by: Andreas Schwab <schwab@linux-m68k.org>
+Acked-by: Rob Herring (Arm) <robh@kernel.org>
+[maddy: added "commit" work in depends-on to avoid checkpatch error]
+Signed-off-by: Madhavan Srinivasan <maddy@linux.ibm.com>
+Link: https://patch.msgid.link/875xmizl6a.fsf@igel.home
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/powerpc/kernel/prom_init.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
+index 57082fac46687..fe4659ba8c22a 100644
+--- a/arch/powerpc/kernel/prom_init.c
++++ b/arch/powerpc/kernel/prom_init.c
+@@ -2889,11 +2889,11 @@ static void __init fixup_device_tree_pmac(void)
+ char type[8];
+ phandle node;
+
+- // Some pmacs are missing #size-cells on escc nodes
++ // Some pmacs are missing #size-cells on escc or i2s nodes
+ for (node = 0; prom_next_node(&node); ) {
+ type[0] = '\0';
+ prom_getprop(node, "device_type", type, sizeof(type));
+- if (prom_strcmp(type, "escc"))
++ if (prom_strcmp(type, "escc") && prom_strcmp(type, "i2s"))
+ continue;
+
+ if (prom_getproplen(node, "#size-cells") != PROM_ERROR)
+--
+2.39.5
+
--- /dev/null
+From 8358716a4e6e3020214056e372fc7cfed698fcc1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 8 Jan 2025 10:48:14 -0600
+Subject: powerpc/pseries/iommu: create DDW for devices with DMA mask less than
+ 64-bits
+
+From: Gaurav Batra <gbatra@linux.ibm.com>
+
+[ Upstream commit 67dfc11982f7e3c37f0977e74671da2391b29181 ]
+
+Starting with PAPR level 2.13, platform supports placing PHB in limited
+address mode. Devices that support DMA masks less that 64-bit but greater
+than 32-bits are placed in limited address mode. In this mode, the
+starting DMA address returned by the DDW is 4GB.
+
+When the device driver calls dma_supported, with mask less then 64-bit, the
+PowerPC IOMMU driver places PHB in the Limited Addressing Mode before
+creating DDW.
+
+Signed-off-by: Gaurav Batra <gbatra@linux.ibm.com>
+Signed-off-by: Madhavan Srinivasan <maddy@linux.ibm.com>
+Link: https://patch.msgid.link/20250108164814.73250-1-gbatra@linux.ibm.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/powerpc/platforms/pseries/iommu.c | 110 +++++++++++++++++++++----
+ 1 file changed, 94 insertions(+), 16 deletions(-)
+
+diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
+index 8f32340960e21..d6ebc19fb99c5 100644
+--- a/arch/powerpc/platforms/pseries/iommu.c
++++ b/arch/powerpc/platforms/pseries/iommu.c
+@@ -52,7 +52,8 @@ enum {
+ enum {
+ DDW_EXT_SIZE = 0,
+ DDW_EXT_RESET_DMA_WIN = 1,
+- DDW_EXT_QUERY_OUT_SIZE = 2
++ DDW_EXT_QUERY_OUT_SIZE = 2,
++ DDW_EXT_LIMITED_ADDR_MODE = 3
+ };
+
+ static struct iommu_table *iommu_pseries_alloc_table(int node)
+@@ -1327,6 +1328,54 @@ static void reset_dma_window(struct pci_dev *dev, struct device_node *par_dn)
+ ret);
+ }
+
++/*
++ * Platforms support placing PHB in limited address mode starting with LoPAR
++ * level 2.13 implement. In this mode, the DMA address returned by DDW is over
++ * 4GB but, less than 64-bits. This benefits IO adapters that don't support
++ * 64-bits for DMA addresses.
++ */
++static int limited_dma_window(struct pci_dev *dev, struct device_node *par_dn)
++{
++ int ret;
++ u32 cfg_addr, reset_dma_win, las_supported;
++ u64 buid;
++ struct device_node *dn;
++ struct pci_dn *pdn;
++
++ ret = ddw_read_ext(par_dn, DDW_EXT_RESET_DMA_WIN, &reset_dma_win);
++ if (ret)
++ goto out;
++
++ ret = ddw_read_ext(par_dn, DDW_EXT_LIMITED_ADDR_MODE, &las_supported);
++
++ /* Limited Address Space extension available on the platform but DDW in
++ * limited addressing mode not supported
++ */
++ if (!ret && !las_supported)
++ ret = -EPROTO;
++
++ if (ret) {
++ dev_info(&dev->dev, "Limited Address Space for DDW not Supported, err: %d", ret);
++ goto out;
++ }
++
++ dn = pci_device_to_OF_node(dev);
++ pdn = PCI_DN(dn);
++ buid = pdn->phb->buid;
++ cfg_addr = (pdn->busno << 16) | (pdn->devfn << 8);
++
++ ret = rtas_call(reset_dma_win, 4, 1, NULL, cfg_addr, BUID_HI(buid),
++ BUID_LO(buid), 1);
++ if (ret)
++ dev_info(&dev->dev,
++ "ibm,reset-pe-dma-windows(%x) for Limited Addr Support: %x %x %x returned %d ",
++ reset_dma_win, cfg_addr, BUID_HI(buid), BUID_LO(buid),
++ ret);
++
++out:
++ return ret;
++}
++
+ /* Return largest page shift based on "IO Page Sizes" output of ibm,query-pe-dma-window. */
+ static int iommu_get_page_shift(u32 query_page_size)
+ {
+@@ -1394,7 +1443,7 @@ static struct property *ddw_property_create(const char *propname, u32 liobn, u64
+ *
+ * returns true if can map all pages (direct mapping), false otherwise..
+ */
+-static bool enable_ddw(struct pci_dev *dev, struct device_node *pdn)
++static bool enable_ddw(struct pci_dev *dev, struct device_node *pdn, u64 dma_mask)
+ {
+ int len = 0, ret;
+ int max_ram_len = order_base_2(ddw_memory_hotplug_max());
+@@ -1413,6 +1462,9 @@ static bool enable_ddw(struct pci_dev *dev, struct device_node *pdn)
+ bool pmem_present;
+ struct pci_dn *pci = PCI_DN(pdn);
+ struct property *default_win = NULL;
++ bool limited_addr_req = false, limited_addr_enabled = false;
++ int dev_max_ddw;
++ int ddw_sz;
+
+ dn = of_find_node_by_type(NULL, "ibm,pmemory");
+ pmem_present = dn != NULL;
+@@ -1439,7 +1491,6 @@ static bool enable_ddw(struct pci_dev *dev, struct device_node *pdn)
+ * the ibm,ddw-applicable property holds the tokens for:
+ * ibm,query-pe-dma-window
+ * ibm,create-pe-dma-window
+- * ibm,remove-pe-dma-window
+ * for the given node in that order.
+ * the property is actually in the parent, not the PE
+ */
+@@ -1459,6 +1510,20 @@ static bool enable_ddw(struct pci_dev *dev, struct device_node *pdn)
+ if (ret != 0)
+ goto out_failed;
+
++ /* DMA Limited Addressing required? This is when the driver has
++ * requested to create DDW but supports mask which is less than 64-bits
++ */
++ limited_addr_req = (dma_mask != DMA_BIT_MASK(64));
++
++ /* place the PHB in Limited Addressing mode */
++ if (limited_addr_req) {
++ if (limited_dma_window(dev, pdn))
++ goto out_failed;
++
++ /* PHB is in Limited address mode */
++ limited_addr_enabled = true;
++ }
++
+ /*
+ * If there is no window available, remove the default DMA window,
+ * if it's present. This will make all the resources available to the
+@@ -1505,6 +1570,15 @@ static bool enable_ddw(struct pci_dev *dev, struct device_node *pdn)
+ goto out_failed;
+ }
+
++ /* Maximum DMA window size that the device can address (in log2) */
++ dev_max_ddw = fls64(dma_mask);
++
++ /* If the device DMA mask is less than 64-bits, make sure the DMA window
++ * size is not bigger than what the device can access
++ */
++ ddw_sz = min(order_base_2(query.largest_available_block << page_shift),
++ dev_max_ddw);
++
+ /*
+ * The "ibm,pmemory" can appear anywhere in the address space.
+ * Assuming it is still backed by page structs, try MAX_PHYSMEM_BITS
+@@ -1513,23 +1587,21 @@ static bool enable_ddw(struct pci_dev *dev, struct device_node *pdn)
+ */
+ len = max_ram_len;
+ if (pmem_present) {
+- if (query.largest_available_block >=
+- (1ULL << (MAX_PHYSMEM_BITS - page_shift)))
++ if (ddw_sz >= MAX_PHYSMEM_BITS)
+ len = MAX_PHYSMEM_BITS;
+ else
+ dev_info(&dev->dev, "Skipping ibm,pmemory");
+ }
+
+ /* check if the available block * number of ptes will map everything */
+- if (query.largest_available_block < (1ULL << (len - page_shift))) {
++ if (ddw_sz < len) {
+ dev_dbg(&dev->dev,
+ "can't map partition max 0x%llx with %llu %llu-sized pages\n",
+ 1ULL << len,
+ query.largest_available_block,
+ 1ULL << page_shift);
+
+- len = order_base_2(query.largest_available_block << page_shift);
+-
++ len = ddw_sz;
+ dynamic_mapping = true;
+ } else {
+ direct_mapping = !default_win_removed ||
+@@ -1543,8 +1615,9 @@ static bool enable_ddw(struct pci_dev *dev, struct device_node *pdn)
+ */
+ if (default_win_removed && pmem_present && !direct_mapping) {
+ /* DDW is big enough to be split */
+- if ((query.largest_available_block << page_shift) >=
+- MIN_DDW_VPMEM_DMA_WINDOW + (1ULL << max_ram_len)) {
++ if ((1ULL << ddw_sz) >=
++ MIN_DDW_VPMEM_DMA_WINDOW + (1ULL << max_ram_len)) {
++
+ direct_mapping = true;
+
+ /* offset of the Dynamic part of DDW */
+@@ -1555,8 +1628,7 @@ static bool enable_ddw(struct pci_dev *dev, struct device_node *pdn)
+ dynamic_mapping = true;
+
+ /* create max size DDW possible */
+- len = order_base_2(query.largest_available_block
+- << page_shift);
++ len = ddw_sz;
+ }
+ }
+
+@@ -1685,7 +1757,7 @@ static bool enable_ddw(struct pci_dev *dev, struct device_node *pdn)
+ __remove_dma_window(pdn, ddw_avail, create.liobn);
+
+ out_failed:
+- if (default_win_removed)
++ if (default_win_removed || limited_addr_enabled)
+ reset_dma_window(dev, pdn);
+
+ fpdn = kzalloc(sizeof(*fpdn), GFP_KERNEL);
+@@ -1704,6 +1776,9 @@ static bool enable_ddw(struct pci_dev *dev, struct device_node *pdn)
+ dev->dev.bus_dma_limit = dev->dev.archdata.dma_offset +
+ (1ULL << max_ram_len);
+
++ dev_info(&dev->dev, "lsa_required: %x, lsa_enabled: %x, direct mapping: %x\n",
++ limited_addr_req, limited_addr_enabled, direct_mapping);
++
+ return direct_mapping;
+ }
+
+@@ -1829,8 +1904,11 @@ static bool iommu_bypass_supported_pSeriesLP(struct pci_dev *pdev, u64 dma_mask)
+ {
+ struct device_node *dn = pci_device_to_OF_node(pdev), *pdn;
+
+- /* only attempt to use a new window if 64-bit DMA is requested */
+- if (dma_mask < DMA_BIT_MASK(64))
++ /* For DDW, DMA mask should be more than 32-bits. For mask more then
++ * 32-bits but less then 64-bits, DMA addressing is supported in
++ * Limited Addressing mode.
++ */
++ if (dma_mask <= DMA_BIT_MASK(32))
+ return false;
+
+ dev_dbg(&pdev->dev, "node is %pOF\n", dn);
+@@ -1843,7 +1921,7 @@ static bool iommu_bypass_supported_pSeriesLP(struct pci_dev *pdev, u64 dma_mask)
+ */
+ pdn = pci_dma_find(dn, NULL);
+ if (pdn && PCI_DN(pdn))
+- return enable_ddw(pdev, pdn);
++ return enable_ddw(pdev, pdn, dma_mask);
+
+ return false;
+ }
+--
+2.39.5
+
--- /dev/null
+From 1fbfc79441ae608a10f614018a4b1ce2437cd04f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jan 2025 12:38:54 -0600
+Subject: powerpc/pseries/iommu: memory notifier incorrectly adds TCEs for
+ pmemory
+
+From: Gaurav Batra <gbatra@linux.ibm.com>
+
+[ Upstream commit 6aa989ab2bd0d37540c812b4270006ff794662e7 ]
+
+iommu_mem_notifier() is invoked when RAM is dynamically added/removed. This
+notifier call is responsible to add/remove TCEs from the Dynamic DMA Window
+(DDW) when TCEs are pre-mapped. TCEs are pre-mapped only for RAM and not
+for persistent memory (pmemory). For DMA buffers in pmemory, TCEs are
+dynamically mapped when the device driver instructs to do so.
+
+The issue is 'daxctl' command is capable of adding pmemory as "System RAM"
+after LPAR boot. The command to do so is -
+
+daxctl reconfigure-device --mode=system-ram dax0.0 --force
+
+This will dynamically add pmemory range to LPAR RAM eventually invoking
+iommu_mem_notifier(). The address range of pmemory is way beyond the Max
+RAM that the LPAR can have. Which means, this range is beyond the DDW
+created for the device, at device initialization time.
+
+As a result when TCEs are pre-mapped for the pmemory range, by
+iommu_mem_notifier(), PHYP HCALL returns H_PARAMETER. This failed the
+command, daxctl, to add pmemory as RAM.
+
+The solution is to not pre-map TCEs for pmemory.
+
+Signed-off-by: Gaurav Batra <gbatra@linux.ibm.com>
+Tested-by: Donet Tom <donettom@linux.ibm.com>
+Reviewed-by: Donet Tom <donettom@linux.ibm.com>
+Signed-off-by: Madhavan Srinivasan <maddy@linux.ibm.com>
+Link: https://patch.msgid.link/20250130183854.92258-1-gbatra@linux.ibm.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/powerpc/include/asm/mmzone.h | 1 +
+ arch/powerpc/mm/numa.c | 2 +-
+ arch/powerpc/platforms/pseries/iommu.c | 29 ++++++++++++++------------
+ 3 files changed, 18 insertions(+), 14 deletions(-)
+
+diff --git a/arch/powerpc/include/asm/mmzone.h b/arch/powerpc/include/asm/mmzone.h
+index d99863cd6cde4..049152f8d597a 100644
+--- a/arch/powerpc/include/asm/mmzone.h
++++ b/arch/powerpc/include/asm/mmzone.h
+@@ -29,6 +29,7 @@ extern cpumask_var_t node_to_cpumask_map[];
+ #ifdef CONFIG_MEMORY_HOTPLUG
+ extern unsigned long max_pfn;
+ u64 memory_hotplug_max(void);
++u64 hot_add_drconf_memory_max(void);
+ #else
+ #define memory_hotplug_max() memblock_end_of_DRAM()
+ #endif
+diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
+index 3c1da08304d03..603a0f652ba61 100644
+--- a/arch/powerpc/mm/numa.c
++++ b/arch/powerpc/mm/numa.c
+@@ -1336,7 +1336,7 @@ int hot_add_scn_to_nid(unsigned long scn_addr)
+ return nid;
+ }
+
+-static u64 hot_add_drconf_memory_max(void)
++u64 hot_add_drconf_memory_max(void)
+ {
+ struct device_node *memory = NULL;
+ struct device_node *dn = NULL;
+diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
+index ae6f7a235d8b2..8f32340960e21 100644
+--- a/arch/powerpc/platforms/pseries/iommu.c
++++ b/arch/powerpc/platforms/pseries/iommu.c
+@@ -1284,17 +1284,13 @@ static LIST_HEAD(failed_ddw_pdn_list);
+
+ static phys_addr_t ddw_memory_hotplug_max(void)
+ {
+- resource_size_t max_addr = memory_hotplug_max();
+- struct device_node *memory;
++ resource_size_t max_addr;
+
+- for_each_node_by_type(memory, "memory") {
+- struct resource res;
+-
+- if (of_address_to_resource(memory, 0, &res))
+- continue;
+-
+- max_addr = max_t(resource_size_t, max_addr, res.end + 1);
+- }
++#if defined(CONFIG_NUMA) && defined(CONFIG_MEMORY_HOTPLUG)
++ max_addr = hot_add_drconf_memory_max();
++#else
++ max_addr = memblock_end_of_DRAM();
++#endif
+
+ return max_addr;
+ }
+@@ -1600,7 +1596,7 @@ static bool enable_ddw(struct pci_dev *dev, struct device_node *pdn)
+
+ if (direct_mapping) {
+ /* DDW maps the whole partition, so enable direct DMA mapping */
+- ret = walk_system_ram_range(0, memblock_end_of_DRAM() >> PAGE_SHIFT,
++ ret = walk_system_ram_range(0, ddw_memory_hotplug_max() >> PAGE_SHIFT,
+ win64->value, tce_setrange_multi_pSeriesLP_walk);
+ if (ret) {
+ dev_info(&dev->dev, "failed to map DMA window for %pOF: %d\n",
+@@ -2349,11 +2345,17 @@ static int iommu_mem_notifier(struct notifier_block *nb, unsigned long action,
+ struct memory_notify *arg = data;
+ int ret = 0;
+
++ /* This notifier can get called when onlining persistent memory as well.
++ * TCEs are not pre-mapped for persistent memory. Persistent memory will
++ * always be above ddw_memory_hotplug_max()
++ */
++
+ switch (action) {
+ case MEM_GOING_ONLINE:
+ spin_lock(&dma_win_list_lock);
+ list_for_each_entry(window, &dma_win_list, list) {
+- if (window->direct) {
++ if (window->direct && (arg->start_pfn << PAGE_SHIFT) <
++ ddw_memory_hotplug_max()) {
+ ret |= tce_setrange_multi_pSeriesLP(arg->start_pfn,
+ arg->nr_pages, window->prop);
+ }
+@@ -2365,7 +2367,8 @@ static int iommu_mem_notifier(struct notifier_block *nb, unsigned long action,
+ case MEM_OFFLINE:
+ spin_lock(&dma_win_list_lock);
+ list_for_each_entry(window, &dma_win_list, list) {
+- if (window->direct) {
++ if (window->direct && (arg->start_pfn << PAGE_SHIFT) <
++ ddw_memory_hotplug_max()) {
+ ret |= tce_clearrange_multi_pSeriesLP(arg->start_pfn,
+ arg->nr_pages, window->prop);
+ }
+--
+2.39.5
+
--- /dev/null
+From 8e6bfa71e2461e583456123e2842878a229aa981 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 19 Feb 2025 09:36:15 +0530
+Subject: pps: generators: replace copy of pps-gen info struct with const
+ pointer
+
+From: Subramanian Mohan <subramanian.mohan@intel.com>
+
+[ Upstream commit ac9c5170a18162d45c6edd1f0fa2d2b2504bc2cb ]
+
+Some PPS generator drivers may need to retrieve a pointer to their
+internal data while executing the PPS generator enable() method.
+
+During the driver registration the pps_gen_device pointer is returned
+from the framework, and for that reason, there is difficulty in
+getting generator driver data back in the enable function. We won't be
+able to use container_of macro as it results in static assert, and we
+might end up in using static pointer.
+
+To solve the issue and to get back the generator driver data back, we
+should not copy the struct pps_gen_source_info within the struct
+pps_gen_device during the registration stage, but simply save the
+pointer of the driver one. In this manner, driver may get a pointer
+to their internal data as shown below:
+
+struct pps_gen_foo_data_s {
+ ...
+ struct pps_gen_source_info gen_info;
+ struct pps_gen_device *pps_gen;
+ ...
+};
+
+static int __init pps_gen_foo_init(void)
+{
+ struct pps_gen_foo_data_s *foo;
+ ...
+ foo->pps_gen = pps_gen_register_source(&foo->gen_info);
+ ...
+}
+
+Then, in the enable() method, we can retrieve the pointer to the main
+struct by using the code below:
+
+static int pps_gen_foo_enable(struct pps_gen_device *pps_gen, bool enable)
+{
+ struct pps_gen_foo_data_s *foo = container_of(pps_gen->info,
+ struct pps_gen_foo_data_s, gen_info);
+ ...
+}
+
+Signed-off-by: Rodolfo Giometti <giometti@enneenne.com>
+Tested-by: Subramanian Mohan <subramanian.mohan@intel.com>
+Suggested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Signed-off-by: Subramanian Mohan <subramanian.mohan@intel.com>
+Link: https://lore.kernel.org/r/20250219040618.70962-2-subramanian.mohan@intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ Documentation/driver-api/pps.rst | 3 +--
+ drivers/pps/generators/pps_gen-dummy.c | 2 +-
+ drivers/pps/generators/pps_gen.c | 14 +++++++-------
+ drivers/pps/generators/sysfs.c | 6 +++---
+ include/linux/pps_gen_kernel.h | 4 ++--
+ 5 files changed, 14 insertions(+), 15 deletions(-)
+
+diff --git a/Documentation/driver-api/pps.rst b/Documentation/driver-api/pps.rst
+index 71ad04c82d6cf..04f1b88778fc5 100644
+--- a/Documentation/driver-api/pps.rst
++++ b/Documentation/driver-api/pps.rst
+@@ -206,8 +206,7 @@ To do so the class pps-gen has been added. PPS generators can be
+ registered in the kernel by defining a struct pps_gen_source_info as
+ follows::
+
+- static struct pps_gen_source_info pps_gen_dummy_info = {
+- .name = "dummy",
++ static const struct pps_gen_source_info pps_gen_dummy_info = {
+ .use_system_clock = true,
+ .get_time = pps_gen_dummy_get_time,
+ .enable = pps_gen_dummy_enable,
+diff --git a/drivers/pps/generators/pps_gen-dummy.c b/drivers/pps/generators/pps_gen-dummy.c
+index b284c200cbe50..55de4aecf35ed 100644
+--- a/drivers/pps/generators/pps_gen-dummy.c
++++ b/drivers/pps/generators/pps_gen-dummy.c
+@@ -61,7 +61,7 @@ static int pps_gen_dummy_enable(struct pps_gen_device *pps_gen, bool enable)
+ * The PPS info struct
+ */
+
+-static struct pps_gen_source_info pps_gen_dummy_info = {
++static const struct pps_gen_source_info pps_gen_dummy_info = {
+ .use_system_clock = true,
+ .get_time = pps_gen_dummy_get_time,
+ .enable = pps_gen_dummy_enable,
+diff --git a/drivers/pps/generators/pps_gen.c b/drivers/pps/generators/pps_gen.c
+index ca592f1736f46..5b8bb454913cd 100644
+--- a/drivers/pps/generators/pps_gen.c
++++ b/drivers/pps/generators/pps_gen.c
+@@ -66,7 +66,7 @@ static long pps_gen_cdev_ioctl(struct file *file,
+ if (ret)
+ return -EFAULT;
+
+- ret = pps_gen->info.enable(pps_gen, status);
++ ret = pps_gen->info->enable(pps_gen, status);
+ if (ret)
+ return ret;
+ pps_gen->enabled = status;
+@@ -76,7 +76,7 @@ static long pps_gen_cdev_ioctl(struct file *file,
+ case PPS_GEN_USESYSTEMCLOCK:
+ dev_dbg(pps_gen->dev, "PPS_GEN_USESYSTEMCLOCK\n");
+
+- ret = put_user(pps_gen->info.use_system_clock, uiuarg);
++ ret = put_user(pps_gen->info->use_system_clock, uiuarg);
+ if (ret)
+ return -EFAULT;
+
+@@ -175,7 +175,7 @@ static int pps_gen_register_cdev(struct pps_gen_device *pps_gen)
+ devt = MKDEV(MAJOR(pps_gen_devt), pps_gen->id);
+
+ cdev_init(&pps_gen->cdev, &pps_gen_cdev_fops);
+- pps_gen->cdev.owner = pps_gen->info.owner;
++ pps_gen->cdev.owner = pps_gen->info->owner;
+
+ err = cdev_add(&pps_gen->cdev, devt, 1);
+ if (err) {
+@@ -183,8 +183,8 @@ static int pps_gen_register_cdev(struct pps_gen_device *pps_gen)
+ MAJOR(pps_gen_devt), pps_gen->id);
+ goto free_ida;
+ }
+- pps_gen->dev = device_create(pps_gen_class, pps_gen->info.parent, devt,
+- pps_gen, "pps-gen%d", pps_gen->id);
++ pps_gen->dev = device_create(pps_gen_class, pps_gen->info->parent, devt,
++ pps_gen, "pps-gen%d", pps_gen->id);
+ if (IS_ERR(pps_gen->dev)) {
+ err = PTR_ERR(pps_gen->dev);
+ goto del_cdev;
+@@ -225,7 +225,7 @@ static void pps_gen_unregister_cdev(struct pps_gen_device *pps_gen)
+ * Return: the PPS generator device in case of success, and ERR_PTR(errno)
+ * otherwise.
+ */
+-struct pps_gen_device *pps_gen_register_source(struct pps_gen_source_info *info)
++struct pps_gen_device *pps_gen_register_source(const struct pps_gen_source_info *info)
+ {
+ struct pps_gen_device *pps_gen;
+ int err;
+@@ -235,7 +235,7 @@ struct pps_gen_device *pps_gen_register_source(struct pps_gen_source_info *info)
+ err = -ENOMEM;
+ goto pps_gen_register_source_exit;
+ }
+- pps_gen->info = *info;
++ pps_gen->info = info;
+ pps_gen->enabled = false;
+
+ init_waitqueue_head(&pps_gen->queue);
+diff --git a/drivers/pps/generators/sysfs.c b/drivers/pps/generators/sysfs.c
+index faf8b1c6d2026..6d6bc0006feae 100644
+--- a/drivers/pps/generators/sysfs.c
++++ b/drivers/pps/generators/sysfs.c
+@@ -19,7 +19,7 @@ static ssize_t system_show(struct device *dev, struct device_attribute *attr,
+ {
+ struct pps_gen_device *pps_gen = dev_get_drvdata(dev);
+
+- return sysfs_emit(buf, "%d\n", pps_gen->info.use_system_clock);
++ return sysfs_emit(buf, "%d\n", pps_gen->info->use_system_clock);
+ }
+ static DEVICE_ATTR_RO(system);
+
+@@ -30,7 +30,7 @@ static ssize_t time_show(struct device *dev, struct device_attribute *attr,
+ struct timespec64 time;
+ int ret;
+
+- ret = pps_gen->info.get_time(pps_gen, &time);
++ ret = pps_gen->info->get_time(pps_gen, &time);
+ if (ret)
+ return ret;
+
+@@ -49,7 +49,7 @@ static ssize_t enable_store(struct device *dev, struct device_attribute *attr,
+ if (ret)
+ return ret;
+
+- ret = pps_gen->info.enable(pps_gen, status);
++ ret = pps_gen->info->enable(pps_gen, status);
+ if (ret)
+ return ret;
+ pps_gen->enabled = status;
+diff --git a/include/linux/pps_gen_kernel.h b/include/linux/pps_gen_kernel.h
+index 022ea0ac44402..6214c8aa2e020 100644
+--- a/include/linux/pps_gen_kernel.h
++++ b/include/linux/pps_gen_kernel.h
+@@ -43,7 +43,7 @@ struct pps_gen_source_info {
+
+ /* The main struct */
+ struct pps_gen_device {
+- struct pps_gen_source_info info; /* PSS generator info */
++ const struct pps_gen_source_info *info; /* PSS generator info */
+ bool enabled; /* PSS generator status */
+
+ unsigned int event;
+@@ -70,7 +70,7 @@ extern const struct attribute_group *pps_gen_groups[];
+ */
+
+ extern struct pps_gen_device *pps_gen_register_source(
+- struct pps_gen_source_info *info);
++ const struct pps_gen_source_info *info);
+ extern void pps_gen_unregister_source(struct pps_gen_device *pps_gen);
+ extern void pps_gen_event(struct pps_gen_device *pps_gen,
+ unsigned int event, void *data);
+--
+2.39.5
+
--- /dev/null
+From 0ba11f5899d2bcc85999ef2570fbc5e8aaa57ee1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Feb 2025 16:59:05 -0300
+Subject: printk: Check CON_SUSPEND when unblanking a console
+
+From: Marcos Paulo de Souza <mpdesouza@suse.com>
+
+[ Upstream commit 72c96a2dacc0fb056d13a5f02b0845c4c910fe54 ]
+
+The commit 9e70a5e109a4 ("printk: Add per-console suspended state")
+introduced the CON_SUSPENDED flag for consoles. The suspended consoles
+will stop receiving messages, so don't unblank suspended consoles
+because it won't be showing anything either way.
+
+Signed-off-by: Marcos Paulo de Souza <mpdesouza@suse.com>
+Reviewed-by: Petr Mladek <pmladek@suse.com>
+Reviewed-by: John Ogness <john.ogness@linutronix.de>
+Link: https://lore.kernel.org/r/20250226-printk-renaming-v1-5-0b878577f2e6@suse.com
+Signed-off-by: Petr Mladek <pmladek@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/printk/printk.c | 14 ++++++++++++--
+ 1 file changed, 12 insertions(+), 2 deletions(-)
+
+diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
+index 057db78876cd9..13d4210d8862f 100644
+--- a/kernel/printk/printk.c
++++ b/kernel/printk/printk.c
+@@ -3340,7 +3340,12 @@ void console_unblank(void)
+ */
+ cookie = console_srcu_read_lock();
+ for_each_console_srcu(c) {
+- if ((console_srcu_read_flags(c) & CON_ENABLED) && c->unblank) {
++ short flags = console_srcu_read_flags(c);
++
++ if (flags & CON_SUSPENDED)
++ continue;
++
++ if ((flags & CON_ENABLED) && c->unblank) {
+ found_unblank = true;
+ break;
+ }
+@@ -3377,7 +3382,12 @@ void console_unblank(void)
+
+ cookie = console_srcu_read_lock();
+ for_each_console_srcu(c) {
+- if ((console_srcu_read_flags(c) & CON_ENABLED) && c->unblank)
++ short flags = console_srcu_read_flags(c);
++
++ if (flags & CON_SUSPENDED)
++ continue;
++
++ if ((flags & CON_ENABLED) && c->unblank)
+ c->unblank();
+ }
+ console_srcu_read_unlock(cookie);
+--
+2.39.5
+
--- /dev/null
+From f5fe211102d16dff51d226f87b041ee567092341 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Feb 2025 11:16:59 -0800
+Subject: pstore: Change kmsg_bytes storage size to u32
+
+From: Kees Cook <kees@kernel.org>
+
+[ Upstream commit 5674609535bafa834ab014d90d9bbe8e89223a0b ]
+
+The types around kmsg_bytes were inconsistent. The global was unsigned
+long, the argument to pstore_set_kmsg_bytes() was int, and the filesystem
+option was u32. Given other internal limits, there's not much sense
+in making a single pstore record larger than INT_MAX and it can't be
+negative, so use u32 everywhere. Additionally, use READ/WRITE_ONCE and a
+local variable in pstore_dump() to avoid kmsg_bytes changing during a
+dump.
+
+Link: https://lore.kernel.org/r/20250206191655.work.798-kees@kernel.org
+Signed-off-by: Kees Cook <kees@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/pstore/inode.c | 2 +-
+ fs/pstore/internal.h | 4 ++--
+ fs/pstore/platform.c | 11 ++++++-----
+ 3 files changed, 9 insertions(+), 8 deletions(-)
+
+diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c
+index 56815799ce798..9de6b280c4f41 100644
+--- a/fs/pstore/inode.c
++++ b/fs/pstore/inode.c
+@@ -265,7 +265,7 @@ static void parse_options(char *options)
+ static int pstore_show_options(struct seq_file *m, struct dentry *root)
+ {
+ if (kmsg_bytes != CONFIG_PSTORE_DEFAULT_KMSG_BYTES)
+- seq_printf(m, ",kmsg_bytes=%lu", kmsg_bytes);
++ seq_printf(m, ",kmsg_bytes=%u", kmsg_bytes);
+ return 0;
+ }
+
+diff --git a/fs/pstore/internal.h b/fs/pstore/internal.h
+index 801d6c0b170c3..a0fc511969100 100644
+--- a/fs/pstore/internal.h
++++ b/fs/pstore/internal.h
+@@ -6,7 +6,7 @@
+ #include <linux/time.h>
+ #include <linux/pstore.h>
+
+-extern unsigned long kmsg_bytes;
++extern unsigned int kmsg_bytes;
+
+ #ifdef CONFIG_PSTORE_FTRACE
+ extern void pstore_register_ftrace(void);
+@@ -35,7 +35,7 @@ static inline void pstore_unregister_pmsg(void) {}
+
+ extern struct pstore_info *psinfo;
+
+-extern void pstore_set_kmsg_bytes(int);
++extern void pstore_set_kmsg_bytes(unsigned int bytes);
+ extern void pstore_get_records(int);
+ extern void pstore_get_backend_records(struct pstore_info *psi,
+ struct dentry *root, int quiet);
+diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c
+index f56b066ab80ce..557cf9d40177f 100644
+--- a/fs/pstore/platform.c
++++ b/fs/pstore/platform.c
+@@ -92,8 +92,8 @@ module_param(compress, charp, 0444);
+ MODULE_PARM_DESC(compress, "compression to use");
+
+ /* How much of the kernel log to snapshot */
+-unsigned long kmsg_bytes = CONFIG_PSTORE_DEFAULT_KMSG_BYTES;
+-module_param(kmsg_bytes, ulong, 0444);
++unsigned int kmsg_bytes = CONFIG_PSTORE_DEFAULT_KMSG_BYTES;
++module_param(kmsg_bytes, uint, 0444);
+ MODULE_PARM_DESC(kmsg_bytes, "amount of kernel log to snapshot (in bytes)");
+
+ static void *compress_workspace;
+@@ -107,9 +107,9 @@ static void *compress_workspace;
+ static char *big_oops_buf;
+ static size_t max_compressed_size;
+
+-void pstore_set_kmsg_bytes(int bytes)
++void pstore_set_kmsg_bytes(unsigned int bytes)
+ {
+- kmsg_bytes = bytes;
++ WRITE_ONCE(kmsg_bytes, bytes);
+ }
+
+ /* Tag each group of saved records with a sequence number */
+@@ -278,6 +278,7 @@ static void pstore_dump(struct kmsg_dumper *dumper,
+ struct kmsg_dump_detail *detail)
+ {
+ struct kmsg_dump_iter iter;
++ unsigned int remaining = READ_ONCE(kmsg_bytes);
+ unsigned long total = 0;
+ const char *why;
+ unsigned int part = 1;
+@@ -300,7 +301,7 @@ static void pstore_dump(struct kmsg_dumper *dumper,
+ kmsg_dump_rewind(&iter);
+
+ oopscount++;
+- while (total < kmsg_bytes) {
++ while (total < remaining) {
+ char *dst;
+ size_t dst_size;
+ int header_size;
+--
+2.39.5
+
--- /dev/null
+From 6466f721e5b1a5650bb9ce23f1fe7cb3f9195c6f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Feb 2025 23:40:33 +0100
+Subject: r8152: add vendor/device ID pair for Dell Alienware AW1022z
+
+From: Aleksander Jan Bajkowski <olek2@wp.pl>
+
+[ Upstream commit 848b09d53d923b4caee5491f57a5c5b22d81febc ]
+
+The Dell AW1022z is an RTL8156B based 2.5G Ethernet controller.
+
+Add the vendor and product ID values to the driver. This makes Ethernet
+work with the adapter.
+
+Signed-off-by: Aleksander Jan Bajkowski <olek2@wp.pl>
+Link: https://patch.msgid.link/20250206224033.980115-1-olek2@wp.pl
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/usb/r8152.c | 1 +
+ include/linux/usb/r8152.h | 1 +
+ 2 files changed, 2 insertions(+)
+
+diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
+index 96fa3857d8e25..2cab046749a92 100644
+--- a/drivers/net/usb/r8152.c
++++ b/drivers/net/usb/r8152.c
+@@ -10085,6 +10085,7 @@ static const struct usb_device_id rtl8152_table[] = {
+ { USB_DEVICE(VENDOR_ID_NVIDIA, 0x09ff) },
+ { USB_DEVICE(VENDOR_ID_TPLINK, 0x0601) },
+ { USB_DEVICE(VENDOR_ID_DLINK, 0xb301) },
++ { USB_DEVICE(VENDOR_ID_DELL, 0xb097) },
+ { USB_DEVICE(VENDOR_ID_ASUS, 0x1976) },
+ {}
+ };
+diff --git a/include/linux/usb/r8152.h b/include/linux/usb/r8152.h
+index 33a4c146dc19c..2ca60828f28bb 100644
+--- a/include/linux/usb/r8152.h
++++ b/include/linux/usb/r8152.h
+@@ -30,6 +30,7 @@
+ #define VENDOR_ID_NVIDIA 0x0955
+ #define VENDOR_ID_TPLINK 0x2357
+ #define VENDOR_ID_DLINK 0x2001
++#define VENDOR_ID_DELL 0x413c
+ #define VENDOR_ID_ASUS 0x0b05
+
+ #if IS_REACHABLE(CONFIG_USB_RTL8152)
+--
+2.39.5
+
--- /dev/null
+From e86d8b777dd87d4ee563313e27eadc7a72a287e2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Mar 2025 16:37:21 +0800
+Subject: r8169: disable RTL8126 ZRX-DC timeout
+
+From: ChunHao Lin <hau@realtek.com>
+
+[ Upstream commit b48688ea3c9ac8d5d910c6e91fb7f80d846581f0 ]
+
+Disable it due to it dose not meet ZRX-DC specification. If it is enabled,
+device will exit L1 substate every 100ms. Disable it for saving more power
+in L1 substate.
+
+Signed-off-by: ChunHao Lin <hau@realtek.com>
+Reviewed-by: Heiner Kallweit <hkallweit1@gmail.com>
+Link: https://patch.msgid.link/20250318083721.4127-3-hau@realtek.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/realtek/r8169_main.c | 27 +++++++++++++++++++++++
+ 1 file changed, 27 insertions(+)
+
+diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
+index 5a5eba49c6515..4ead966727734 100644
+--- a/drivers/net/ethernet/realtek/r8169_main.c
++++ b/drivers/net/ethernet/realtek/r8169_main.c
+@@ -2850,6 +2850,32 @@ static u32 rtl_csi_read(struct rtl8169_private *tp, int addr)
+ RTL_R32(tp, CSIDR) : ~0;
+ }
+
++static void rtl_disable_zrxdc_timeout(struct rtl8169_private *tp)
++{
++ struct pci_dev *pdev = tp->pci_dev;
++ u32 csi;
++ int rc;
++ u8 val;
++
++#define RTL_GEN3_RELATED_OFF 0x0890
++#define RTL_GEN3_ZRXDC_NONCOMPL 0x1
++ if (pdev->cfg_size > RTL_GEN3_RELATED_OFF) {
++ rc = pci_read_config_byte(pdev, RTL_GEN3_RELATED_OFF, &val);
++ if (rc == PCIBIOS_SUCCESSFUL) {
++ val &= ~RTL_GEN3_ZRXDC_NONCOMPL;
++ rc = pci_write_config_byte(pdev, RTL_GEN3_RELATED_OFF,
++ val);
++ if (rc == PCIBIOS_SUCCESSFUL)
++ return;
++ }
++ }
++
++ netdev_notice_once(tp->dev,
++ "No native access to PCI extended config space, falling back to CSI\n");
++ csi = rtl_csi_read(tp, RTL_GEN3_RELATED_OFF);
++ rtl_csi_write(tp, RTL_GEN3_RELATED_OFF, csi & ~RTL_GEN3_ZRXDC_NONCOMPL);
++}
++
+ static void rtl_set_aspm_entry_latency(struct rtl8169_private *tp, u8 val)
+ {
+ struct pci_dev *pdev = tp->pci_dev;
+@@ -3822,6 +3848,7 @@ static void rtl_hw_start_8125d(struct rtl8169_private *tp)
+
+ static void rtl_hw_start_8126a(struct rtl8169_private *tp)
+ {
++ rtl_disable_zrxdc_timeout(tp);
+ rtl_set_def_aspm_entry_latency(tp);
+ rtl_hw_start_8125_common(tp);
+ }
+--
+2.39.5
+
--- /dev/null
+From 38c499a39c23b72200322570626cfa1002876b08 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Feb 2025 07:58:17 +0100
+Subject: r8169: don't scan PHY addresses > 0
+
+From: Heiner Kallweit <hkallweit1@gmail.com>
+
+[ Upstream commit faac69a4ae5abb49e62c79c66b51bb905c9aa5ec ]
+
+The PHY address is a dummy, because r8169 PHY access registers
+don't support a PHY address. Therefore scan address 0 only.
+
+Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Link: https://patch.msgid.link/830637dd-4016-4a68-92b3-618fcac6589d@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/realtek/r8169_main.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
+index 485ecd62e585d..267105ba92744 100644
+--- a/drivers/net/ethernet/realtek/r8169_main.c
++++ b/drivers/net/ethernet/realtek/r8169_main.c
+@@ -5250,6 +5250,7 @@ static int r8169_mdio_register(struct rtl8169_private *tp)
+ new_bus->priv = tp;
+ new_bus->parent = &pdev->dev;
+ new_bus->irq[0] = PHY_MAC_INTERRUPT;
++ new_bus->phy_mask = GENMASK(31, 1);
+ snprintf(new_bus->id, MII_BUS_ID_SIZE, "r8169-%x-%x",
+ pci_domain_nr(pdev->bus), pci_dev_id(pdev));
+
+--
+2.39.5
+
--- /dev/null
+From a7e800108e7c4499d31b3cbee30e398a8ed4ae1f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 7 Mar 2025 08:29:47 +0100
+Subject: r8169: increase max jumbo packet size on RTL8125/RTL8126
+
+From: Heiner Kallweit <hkallweit1@gmail.com>
+
+[ Upstream commit 473367a5ffe1607a61be481e2feda684eb5faea9 ]
+
+Realtek confirmed that all RTL8125/RTL8126 chip versions support up to
+16K jumbo packets. Reflect this in the driver.
+
+Tested by Rui on RTL8125B with 12K jumbo packets.
+
+Suggested-by: Rui Salvaterra <rsalvaterra@gmail.com>
+Tested-by: Rui Salvaterra <rsalvaterra@gmail.com>
+Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/396762ad-cc65-4e60-b01e-8847db89e98b@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/realtek/r8169_main.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
+index 4ead966727734..485ecd62e585d 100644
+--- a/drivers/net/ethernet/realtek/r8169_main.c
++++ b/drivers/net/ethernet/realtek/r8169_main.c
+@@ -89,6 +89,7 @@
+ #define JUMBO_6K (6 * SZ_1K - VLAN_ETH_HLEN - ETH_FCS_LEN)
+ #define JUMBO_7K (7 * SZ_1K - VLAN_ETH_HLEN - ETH_FCS_LEN)
+ #define JUMBO_9K (9 * SZ_1K - VLAN_ETH_HLEN - ETH_FCS_LEN)
++#define JUMBO_16K (SZ_16K - VLAN_ETH_HLEN - ETH_FCS_LEN)
+
+ static const struct {
+ const char *name;
+@@ -5353,6 +5354,9 @@ static int rtl_jumbo_max(struct rtl8169_private *tp)
+ /* RTL8168c */
+ case RTL_GIGA_MAC_VER_18 ... RTL_GIGA_MAC_VER_24:
+ return JUMBO_6K;
++ /* RTL8125/8126 */
++ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71:
++ return JUMBO_16K;
+ default:
+ return JUMBO_9K;
+ }
+--
+2.39.5
+
--- /dev/null
+From 8d22e22abaad92094a73b91327cb61d91923f17e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 12 Dec 2024 14:15:07 -0800
+Subject: rcu: Fix get_state_synchronize_rcu_full() GP-start detection
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Paul E. McKenney <paulmck@kernel.org>
+
+[ Upstream commit 85aad7cc417877054c65bd490dc037b087ef21b4 ]
+
+The get_state_synchronize_rcu_full() and poll_state_synchronize_rcu_full()
+functions use the root rcu_node structure's ->gp_seq field to detect
+the beginnings and ends of grace periods, respectively. This choice is
+necessary for the poll_state_synchronize_rcu_full() function because
+(give or take counter wrap), the following sequence is guaranteed not
+to trigger:
+
+ get_state_synchronize_rcu_full(&rgos);
+ synchronize_rcu();
+ WARN_ON_ONCE(!poll_state_synchronize_rcu_full(&rgos));
+
+The RCU callbacks that awaken synchronize_rcu() instances are
+guaranteed not to be invoked before the root rcu_node structure's
+->gp_seq field is updated to indicate the end of the grace period.
+However, these callbacks might start being invoked immediately
+thereafter, in particular, before rcu_state.gp_seq has been updated.
+Therefore, poll_state_synchronize_rcu_full() must refer to the
+root rcu_node structure's ->gp_seq field. Because this field is
+updated under this structure's ->lock, any code following a call to
+poll_state_synchronize_rcu_full() will be fully ordered after the
+full grace-period computation, as is required by RCU's memory-ordering
+semantics.
+
+By symmetry, the get_state_synchronize_rcu_full() function should also
+use this same root rcu_node structure's ->gp_seq field. But it turns out
+that symmetry is profoundly (though extremely infrequently) destructive
+in this case. To see this, consider the following sequence of events:
+
+1. CPU 0 starts a new grace period, and updates rcu_state.gp_seq
+ accordingly.
+
+2. As its first step of grace-period initialization, CPU 0 examines
+ the current CPU hotplug state and decides that it need not wait
+ for CPU 1, which is currently offline.
+
+3. CPU 1 comes online, and updates its state. But this does not
+ affect the current grace period, but rather the one after that.
+ After all, CPU 1 was offline when the current grace period
+ started, so all pre-existing RCU readers on CPU 1 must have
+ completed or been preempted before it last went offline.
+ The current grace period therefore has nothing it needs to wait
+ for on CPU 1.
+
+4. CPU 1 switches to an rcutorture kthread which is running
+ rcutorture's rcu_torture_reader() function, which starts a new
+ RCU reader.
+
+5. CPU 2 is running rcutorture's rcu_torture_writer() function
+ and collects a new polled grace-period "cookie" using
+ get_state_synchronize_rcu_full(). Because the newly started
+ grace period has not completed initialization, the root rcu_node
+ structure's ->gp_seq field has not yet been updated to indicate
+ that this new grace period has already started.
+
+ This cookie is therefore set up for the end of the current grace
+ period (rather than the end of the following grace period).
+
+6. CPU 0 finishes grace-period initialization.
+
+7. If CPU 1’s rcutorture reader is preempted, it will be added to
+ the ->blkd_tasks list, but because CPU 1’s ->qsmask bit is not
+ set in CPU 1's leaf rcu_node structure, the ->gp_tasks pointer
+ will not be updated. Thus, this grace period will not wait on
+ it. Which is only fair, given that the CPU did not come online
+ until after the grace period officially started.
+
+8. CPUs 0 and 2 then detect the new grace period and then report
+ a quiescent state to the RCU core.
+
+9. Because CPU 1 was offline at the start of the current grace
+ period, CPUs 0 and 2 are the only CPUs that this grace period
+ needs to wait on. So the grace period ends and post-grace-period
+ cleanup starts. In particular, the root rcu_node structure's
+ ->gp_seq field is updated to indicate that this grace period
+ has now ended.
+
+10. CPU 2 continues running rcu_torture_writer() and sees that,
+ from the viewpoint of the root rcu_node structure consulted by
+ the poll_state_synchronize_rcu_full() function, the grace period
+ has ended. It therefore updates state accordingly.
+
+11. CPU 1 is still running the same RCU reader, which notices this
+ update and thus complains about the too-short grace period.
+
+The fix is for the get_state_synchronize_rcu_full() function to use
+rcu_state.gp_seq instead of the root rcu_node structure's ->gp_seq field.
+With this change in place, if step 5's cookie indicates that the grace
+period has not yet started, then any prior code executed by CPU 2 must
+have happened before CPU 1 came online. This will in turn prevent CPU
+1's code in steps 3 and 11 from spanning CPU 2's grace-period wait,
+thus preventing CPU 1 from being subjected to a too-short grace period.
+
+This commit therefore makes this change. Note that there is no change to
+the poll_state_synchronize_rcu_full() function, which as noted above,
+must continue to use the root rcu_node structure's ->gp_seq field.
+This is of course an asymmetry between these two functions, but is an
+asymmetry that is absolutely required for correct operation. It is a
+common human tendency to greatly value symmetry, and sometimes symmetry
+is a wonderful thing. Other times, symmetry results in poor performance.
+But in this case, symmetry is just plain wrong.
+
+Nevertheless, the asymmetry does require an additional adjustment.
+It is possible for get_state_synchronize_rcu_full() to see a given
+grace period as having started, but for an immediately following
+poll_state_synchronize_rcu_full() to see it as having not yet started.
+Given the current rcu_seq_done_exact() implementation, this will
+result in a false-positive indication that the grace period is done
+from poll_state_synchronize_rcu_full(). This is dealt with by making
+rcu_seq_done_exact() reach back three grace periods rather than just
+two of them.
+
+However, simply changing get_state_synchronize_rcu_full() function to
+use rcu_state.gp_seq instead of the root rcu_node structure's ->gp_seq
+field results in a theoretical bug in kernels booted with
+rcutree.rcu_normal_wake_from_gp=1 due to the following sequence of
+events:
+
+o The rcu_gp_init() function invokes rcu_seq_start() to officially
+ start a new grace period.
+
+o A new RCU reader begins, referencing X from some RCU-protected
+ list. The new grace period is not obligated to wait for this
+ reader.
+
+o An updater removes X, then calls synchronize_rcu(), which queues
+ a wait element.
+
+o The grace period ends, awakening the updater, which frees X
+ while the reader is still referencing it.
+
+The reason that this is theoretical is that although the grace period
+has officially started, none of the CPUs are officially aware of this,
+and thus will have to assume that the RCU reader pre-dated the start of
+the grace period. Detailed explanation can be found at [2] and [3].
+
+Except for kernels built with CONFIG_PROVE_RCU=y, which use the polled
+grace-period APIs, which can and do complain bitterly when this sequence
+of events occurs. Not only that, there might be some future RCU
+grace-period mechanism that pulls this sequence of events from theory
+into practice. This commit therefore also pulls the call to
+rcu_sr_normal_gp_init() to precede that to rcu_seq_start().
+
+Although this fixes commit 91a967fd6934 ("rcu: Add full-sized polling
+for get_completed*() and poll_state*()"), it is not clear that it is
+worth backporting this commit. First, it took me many weeks to convince
+rcutorture to reproduce this more frequently than once per year.
+Second, this cannot be reproduced at all without frequent CPU-hotplug
+operations, as in waiting all of 50 milliseconds from the end of the
+previous operation until starting the next one. Third, the TREE03.boot
+settings cause multi-millisecond delays during RCU grace-period
+initialization, which greatly increase the probability of the above
+sequence of events. (Don't do this in production workloads!) Fourth,
+the TREE03 rcutorture scenario was modified to use four-CPU guest OSes,
+to have a single-rcu_node combining tree, no testing of RCU priority
+boosting, and no random preemption, and these modifications were
+necessary to reproduce this issue in a reasonable timeframe. Fifth,
+extremely heavy use of get_state_synchronize_rcu_full() and/or
+poll_state_synchronize_rcu_full() is required to reproduce this, and as
+of v6.12, only kfree_rcu() uses it, and even then not particularly
+heavily.
+
+[boqun: Apply the fix [1], and add the comment before the moved
+rcu_sr_normal_gp_init(). Additional links are added for explanation.]
+
+Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
+Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
+Reviewed-by: Joel Fernandes (Google) <joel@joelfernandes.org>
+Tested-by: Uladzislau Rezki (Sony) <urezki@gmail.com>
+Link: https://lore.kernel.org/rcu/d90bd6d9-d15c-4b9b-8a69-95336e74e8f4@paulmck-laptop/ [1]
+Link: https://lore.kernel.org/rcu/20250303001507.GA3994772@joelnvbox/ [2]
+Link: https://lore.kernel.org/rcu/Z8bcUsZ9IpRi1QoP@pc636/ [3]
+Reviewed-by: Joel Fernandes <joelagnelf@nvidia.com>
+Signed-off-by: Boqun Feng <boqun.feng@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/rcu/rcu.h | 2 +-
+ kernel/rcu/tree.c | 15 +++++++++++----
+ 2 files changed, 12 insertions(+), 5 deletions(-)
+
+diff --git a/kernel/rcu/rcu.h b/kernel/rcu/rcu.h
+index feb3ac1dc5d59..f87c9d6d36fcb 100644
+--- a/kernel/rcu/rcu.h
++++ b/kernel/rcu/rcu.h
+@@ -162,7 +162,7 @@ static inline bool rcu_seq_done_exact(unsigned long *sp, unsigned long s)
+ {
+ unsigned long cur_s = READ_ONCE(*sp);
+
+- return ULONG_CMP_GE(cur_s, s) || ULONG_CMP_LT(cur_s, s - (2 * RCU_SEQ_STATE_MASK + 1));
++ return ULONG_CMP_GE(cur_s, s) || ULONG_CMP_LT(cur_s, s - (3 * RCU_SEQ_STATE_MASK + 1));
+ }
+
+ /*
+diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
+index 475f31deed141..b7bf9db9bb461 100644
+--- a/kernel/rcu/tree.c
++++ b/kernel/rcu/tree.c
+@@ -1801,10 +1801,14 @@ static noinline_for_stack bool rcu_gp_init(void)
+
+ /* Advance to a new grace period and initialize state. */
+ record_gp_stall_check_time();
++ /*
++ * A new wait segment must be started before gp_seq advanced, so
++ * that previous gp waiters won't observe the new gp_seq.
++ */
++ start_new_poll = rcu_sr_normal_gp_init();
+ /* Record GP times before starting GP, hence rcu_seq_start(). */
+ rcu_seq_start(&rcu_state.gp_seq);
+ ASSERT_EXCLUSIVE_WRITER(rcu_state.gp_seq);
+- start_new_poll = rcu_sr_normal_gp_init();
+ trace_rcu_grace_period(rcu_state.name, rcu_state.gp_seq, TPS("start"));
+ rcu_poll_gp_seq_start(&rcu_state.gp_seq_polled_snap);
+ raw_spin_unlock_irq_rcu_node(rnp);
+@@ -3357,14 +3361,17 @@ EXPORT_SYMBOL_GPL(get_state_synchronize_rcu);
+ */
+ void get_state_synchronize_rcu_full(struct rcu_gp_oldstate *rgosp)
+ {
+- struct rcu_node *rnp = rcu_get_root();
+-
+ /*
+ * Any prior manipulation of RCU-protected data must happen
+ * before the loads from ->gp_seq and ->expedited_sequence.
+ */
+ smp_mb(); /* ^^^ */
+- rgosp->rgos_norm = rcu_seq_snap(&rnp->gp_seq);
++
++ // Yes, rcu_state.gp_seq, not rnp_root->gp_seq, the latter's use
++ // in poll_state_synchronize_rcu_full() notwithstanding. Use of
++ // the latter here would result in too-short grace periods due to
++ // interactions with newly onlined CPUs.
++ rgosp->rgos_norm = rcu_seq_snap(&rcu_state.gp_seq);
+ rgosp->rgos_exp = rcu_seq_snap(&rcu_state.expedited_sequence);
+ }
+ EXPORT_SYMBOL_GPL(get_state_synchronize_rcu_full);
+--
+2.39.5
+
--- /dev/null
+From ce4bc94a69f774d11aec8804f7db6152a3173471 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 12 Dec 2024 20:06:52 -0800
+Subject: rcu: fix header guard for rcu_all_qs()
+
+From: Ankur Arora <ankur.a.arora@oracle.com>
+
+[ Upstream commit ad6b5b73ff565e88aca7a7d1286788d80c97ba71 ]
+
+rcu_all_qs() is defined for !CONFIG_PREEMPT_RCU but the declaration
+is conditioned on CONFIG_PREEMPTION.
+
+With CONFIG_PREEMPT_LAZY, CONFIG_PREEMPTION=y does not imply
+CONFIG_PREEMPT_RCU=y.
+
+Decouple the two.
+
+Cc: Paul E. McKenney <paulmck@kernel.org>
+Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
+Reviewed-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Signed-off-by: Ankur Arora <ankur.a.arora@oracle.com>
+Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
+Signed-off-by: Boqun Feng <boqun.feng@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/rcutree.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h
+index 27d86d9127817..aad586f15ed0c 100644
+--- a/include/linux/rcutree.h
++++ b/include/linux/rcutree.h
+@@ -103,7 +103,7 @@ extern int rcu_scheduler_active;
+ void rcu_end_inkernel_boot(void);
+ bool rcu_inkernel_boot_has_ended(void);
+ bool rcu_is_watching(void);
+-#ifndef CONFIG_PREEMPTION
++#ifndef CONFIG_PREEMPT_RCU
+ void rcu_all_qs(void);
+ #endif
+
+--
+2.39.5
+
--- /dev/null
+From cdc8f290dcc3e04807b018e254ca07510bf3d087 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 12 Dec 2024 20:06:56 -0800
+Subject: rcu: handle quiescent states for PREEMPT_RCU=n, PREEMPT_COUNT=y
+
+From: Ankur Arora <ankur.a.arora@oracle.com>
+
+[ Upstream commit 83b28cfe796464ebbde1cf7916c126da6d572685 ]
+
+With PREEMPT_RCU=n, cond_resched() provides urgently needed quiescent
+states for read-side critical sections via rcu_all_qs().
+One reason why this was needed: lacking preempt-count, the tick
+handler has no way of knowing whether it is executing in a
+read-side critical section or not.
+
+With (PREEMPT_LAZY=y, PREEMPT_DYNAMIC=n), we get (PREEMPT_COUNT=y,
+PREEMPT_RCU=n). In this configuration cond_resched() is a stub and
+does not provide quiescent states via rcu_all_qs().
+(PREEMPT_RCU=y provides this information via rcu_read_unlock() and
+its nesting counter.)
+
+So, use the availability of preempt_count() to report quiescent states
+in rcu_flavor_sched_clock_irq().
+
+Suggested-by: Paul E. McKenney <paulmck@kernel.org>
+Reviewed-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Signed-off-by: Ankur Arora <ankur.a.arora@oracle.com>
+Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
+Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
+Signed-off-by: Boqun Feng <boqun.feng@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/rcu/tree_plugin.h | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
+index 3600152b858e8..4328ff3252a35 100644
+--- a/kernel/rcu/tree_plugin.h
++++ b/kernel/rcu/tree_plugin.h
+@@ -975,13 +975,16 @@ static void rcu_preempt_check_blocked_tasks(struct rcu_node *rnp)
+ */
+ static void rcu_flavor_sched_clock_irq(int user)
+ {
+- if (user || rcu_is_cpu_rrupt_from_idle()) {
++ if (user || rcu_is_cpu_rrupt_from_idle() ||
++ (IS_ENABLED(CONFIG_PREEMPT_COUNT) &&
++ (preempt_count() == HARDIRQ_OFFSET))) {
+
+ /*
+ * Get here if this CPU took its interrupt from user
+- * mode or from the idle loop, and if this is not a
+- * nested interrupt. In this case, the CPU is in
+- * a quiescent state, so note it.
++ * mode, from the idle loop without this being a nested
++ * interrupt, or while not holding the task preempt count
++ * (with PREEMPT_COUNT=y). In this case, the CPU is in a
++ * quiescent state, so note it.
+ *
+ * No memory barrier is required here because rcu_qs()
+ * references only CPU-local variables that other CPUs
+--
+2.39.5
+
--- /dev/null
+From a5b0fc1e2557608d72ee4328033ddc7eb3c001c2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 12 Dec 2024 20:06:55 -0800
+Subject: rcu: handle unstable rdp in rcu_read_unlock_strict()
+
+From: Ankur Arora <ankur.a.arora@oracle.com>
+
+[ Upstream commit fcf0e25ad4c8d14d2faab4d9a17040f31efce205 ]
+
+rcu_read_unlock_strict() can be called with preemption enabled
+which can make for an unstable rdp and a racy norm value.
+
+Fix this by dropping the preempt-count in __rcu_read_unlock()
+after the call to rcu_read_unlock_strict(), adjusting the
+preempt-count check appropriately.
+
+Suggested-by: Frederic Weisbecker <frederic@kernel.org>
+Signed-off-by: Ankur Arora <ankur.a.arora@oracle.com>
+Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
+Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
+Signed-off-by: Boqun Feng <boqun.feng@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/rcupdate.h | 2 +-
+ kernel/rcu/tree_plugin.h | 11 ++++++++++-
+ 2 files changed, 11 insertions(+), 2 deletions(-)
+
+diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
+index bd69ddc102fbc..0844ab3288519 100644
+--- a/include/linux/rcupdate.h
++++ b/include/linux/rcupdate.h
+@@ -95,9 +95,9 @@ static inline void __rcu_read_lock(void)
+
+ static inline void __rcu_read_unlock(void)
+ {
+- preempt_enable();
+ if (IS_ENABLED(CONFIG_RCU_STRICT_GRACE_PERIOD))
+ rcu_read_unlock_strict();
++ preempt_enable();
+ }
+
+ static inline int rcu_preempt_depth(void)
+diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
+index 4328ff3252a35..3c0bbbbb686fe 100644
+--- a/kernel/rcu/tree_plugin.h
++++ b/kernel/rcu/tree_plugin.h
+@@ -833,8 +833,17 @@ void rcu_read_unlock_strict(void)
+ {
+ struct rcu_data *rdp;
+
+- if (irqs_disabled() || preempt_count() || !rcu_state.gp_kthread)
++ if (irqs_disabled() || in_atomic_preempt_off() || !rcu_state.gp_kthread)
+ return;
++
++ /*
++ * rcu_report_qs_rdp() can only be invoked with a stable rdp and
++ * from the local CPU.
++ *
++ * The in_atomic_preempt_off() check ensures that we come here holding
++ * the last preempt_count (which will get dropped once we return to
++ * __rcu_read_unlock().
++ */
+ rdp = this_cpu_ptr(&rcu_data);
+ rdp->cpu_no_qs.b.norm = false;
+ rcu_report_qs_rdp(rdp);
+--
+2.39.5
+
--- /dev/null
+From 91959f035883f7bb4401aa40b78824d19f67761a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 17 Feb 2025 14:16:23 +0000
+Subject: RDMA/core: Fix best page size finding when it can cross SG entries
+
+From: Michael Margolin <mrgolin@amazon.com>
+
+[ Upstream commit 486055f5e09df959ad4e3aa4ee75b5c91ddeec2e ]
+
+A single scatter-gather entry is limited by a 32 bits "length" field
+that is practically 4GB - PAGE_SIZE. This means that even when the
+memory is physically contiguous, we might need more than one entry to
+represent it. Additionally when using dmabuf, the sg_table might be
+originated outside the subsystem and optimized for other needs.
+
+For instance an SGT of 16GB GPU continuous memory might look like this:
+(a real life example)
+
+dma_address 34401400000, length fffff000
+dma_address 345013ff000, length fffff000
+dma_address 346013fe000, length fffff000
+dma_address 347013fd000, length fffff000
+dma_address 348013fc000, length 4000
+
+Since ib_umem_find_best_pgsz works within SG entries, in the above case
+we will result with the worst possible 4KB page size.
+
+Fix this by taking into consideration only the alignment of addresses of
+real discontinuity points rather than treating SG entries as such, and
+adjust the page iterator to correctly handle cross SG entry pages.
+
+There is currently an assumption that drivers do not ask for pages
+bigger than maximal DMA size supported by their devices.
+
+Reviewed-by: Firas Jahjah <firasj@amazon.com>
+Reviewed-by: Yonatan Nachum <ynachum@amazon.com>
+Signed-off-by: Michael Margolin <mrgolin@amazon.com>
+Link: https://patch.msgid.link/20250217141623.12428-1-mrgolin@amazon.com
+Signed-off-by: Leon Romanovsky <leon@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/infiniband/core/umem.c | 36 ++++++++++++++++++++++++---------
+ drivers/infiniband/core/verbs.c | 11 +++++-----
+ 2 files changed, 32 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c
+index 07c571c7b6999..c5b6863947605 100644
+--- a/drivers/infiniband/core/umem.c
++++ b/drivers/infiniband/core/umem.c
+@@ -80,9 +80,12 @@ unsigned long ib_umem_find_best_pgsz(struct ib_umem *umem,
+ unsigned long pgsz_bitmap,
+ unsigned long virt)
+ {
+- struct scatterlist *sg;
++ unsigned long curr_len = 0;
++ dma_addr_t curr_base = ~0;
+ unsigned long va, pgoff;
++ struct scatterlist *sg;
+ dma_addr_t mask;
++ dma_addr_t end;
+ int i;
+
+ umem->iova = va = virt;
+@@ -107,17 +110,30 @@ unsigned long ib_umem_find_best_pgsz(struct ib_umem *umem,
+ pgoff = umem->address & ~PAGE_MASK;
+
+ for_each_sgtable_dma_sg(&umem->sgt_append.sgt, sg, i) {
+- /* Walk SGL and reduce max page size if VA/PA bits differ
+- * for any address.
++ /* If the current entry is physically contiguous with the previous
++ * one, no need to take its start addresses into consideration.
+ */
+- mask |= (sg_dma_address(sg) + pgoff) ^ va;
++ if (check_add_overflow(curr_base, curr_len, &end) ||
++ end != sg_dma_address(sg)) {
++
++ curr_base = sg_dma_address(sg);
++ curr_len = 0;
++
++ /* Reduce max page size if VA/PA bits differ */
++ mask |= (curr_base + pgoff) ^ va;
++
++ /* The alignment of any VA matching a discontinuity point
++ * in the physical memory sets the maximum possible page
++ * size as this must be a starting point of a new page that
++ * needs to be aligned.
++ */
++ if (i != 0)
++ mask |= va;
++ }
++
++ curr_len += sg_dma_len(sg);
+ va += sg_dma_len(sg) - pgoff;
+- /* Except for the last entry, the ending iova alignment sets
+- * the maximum possible page size as the low bits of the iova
+- * must be zero when starting the next chunk.
+- */
+- if (i != (umem->sgt_append.sgt.nents - 1))
+- mask |= va;
++
+ pgoff = 0;
+ }
+
+diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c
+index 473ee0831307c..dc40001072a5e 100644
+--- a/drivers/infiniband/core/verbs.c
++++ b/drivers/infiniband/core/verbs.c
+@@ -3109,22 +3109,23 @@ EXPORT_SYMBOL(__rdma_block_iter_start);
+ bool __rdma_block_iter_next(struct ib_block_iter *biter)
+ {
+ unsigned int block_offset;
+- unsigned int sg_delta;
++ unsigned int delta;
+
+ if (!biter->__sg_nents || !biter->__sg)
+ return false;
+
+ biter->__dma_addr = sg_dma_address(biter->__sg) + biter->__sg_advance;
+ block_offset = biter->__dma_addr & (BIT_ULL(biter->__pg_bit) - 1);
+- sg_delta = BIT_ULL(biter->__pg_bit) - block_offset;
++ delta = BIT_ULL(biter->__pg_bit) - block_offset;
+
+- if (sg_dma_len(biter->__sg) - biter->__sg_advance > sg_delta) {
+- biter->__sg_advance += sg_delta;
+- } else {
++ while (biter->__sg_nents && biter->__sg &&
++ sg_dma_len(biter->__sg) - biter->__sg_advance <= delta) {
++ delta -= sg_dma_len(biter->__sg) - biter->__sg_advance;
+ biter->__sg_advance = 0;
+ biter->__sg = sg_next(biter->__sg);
+ biter->__sg_nents--;
+ }
++ biter->__sg_advance += delta;
+
+ return true;
+ }
+--
+2.39.5
+
--- /dev/null
+From fbc0e117ab41b2ae3b76bfed430dc6db5d7be472 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Feb 2025 15:54:13 +0200
+Subject: RDMA/uverbs: Propagate errors from rdma_lookup_get_uobject()
+
+From: Maher Sanalla <msanalla@nvidia.com>
+
+[ Upstream commit 81f8f7454ad9e0bf95efdec6542afdc9a6ab1e24 ]
+
+Currently, the IB uverbs API calls uobj_get_uobj_read(), which in turn
+uses the rdma_lookup_get_uobject() helper to retrieve user objects.
+In case of failure, uobj_get_uobj_read() returns NULL, overriding the
+error code from rdma_lookup_get_uobject(). The IB uverbs API then
+translates this NULL to -EINVAL, masking the actual error and
+complicating debugging. For example, applications calling ibv_modify_qp
+that fails with EBUSY when retrieving the QP uobject will see the
+overridden error code EINVAL instead, masking the actual error.
+
+Furthermore, based on rdma-core commit:
+"2a22f1ced5f3 ("Merge pull request #1568 from jakemoroni/master")"
+Kernel's IB uverbs return values are either ignored and passed on as is
+to application or overridden with other errnos in a few cases.
+
+Thus, to improve error reporting and debuggability, propagate the
+original error from rdma_lookup_get_uobject() instead of replacing it
+with EINVAL.
+
+Signed-off-by: Maher Sanalla <msanalla@nvidia.com>
+Link: https://patch.msgid.link/64f9d3711b183984e939962c2f83383904f97dfb.1740577869.git.leon@kernel.org
+Signed-off-by: Leon Romanovsky <leon@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/infiniband/core/uverbs_cmd.c | 144 ++++++++++++++-------------
+ include/rdma/uverbs_std_types.h | 2 +-
+ 2 files changed, 77 insertions(+), 69 deletions(-)
+
+diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
+index 5ad14c39d48c9..de75dcc0947c7 100644
+--- a/drivers/infiniband/core/uverbs_cmd.c
++++ b/drivers/infiniband/core/uverbs_cmd.c
+@@ -716,8 +716,8 @@ static int ib_uverbs_reg_mr(struct uverbs_attr_bundle *attrs)
+ goto err_free;
+
+ pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle, attrs);
+- if (!pd) {
+- ret = -EINVAL;
++ if (IS_ERR(pd)) {
++ ret = PTR_ERR(pd);
+ goto err_free;
+ }
+
+@@ -807,8 +807,8 @@ static int ib_uverbs_rereg_mr(struct uverbs_attr_bundle *attrs)
+ if (cmd.flags & IB_MR_REREG_PD) {
+ new_pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle,
+ attrs);
+- if (!new_pd) {
+- ret = -EINVAL;
++ if (IS_ERR(new_pd)) {
++ ret = PTR_ERR(new_pd);
+ goto put_uobjs;
+ }
+ } else {
+@@ -917,8 +917,8 @@ static int ib_uverbs_alloc_mw(struct uverbs_attr_bundle *attrs)
+ return PTR_ERR(uobj);
+
+ pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle, attrs);
+- if (!pd) {
+- ret = -EINVAL;
++ if (IS_ERR(pd)) {
++ ret = PTR_ERR(pd);
+ goto err_free;
+ }
+
+@@ -1125,8 +1125,8 @@ static int ib_uverbs_resize_cq(struct uverbs_attr_bundle *attrs)
+ return ret;
+
+ cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, attrs);
+- if (!cq)
+- return -EINVAL;
++ if (IS_ERR(cq))
++ return PTR_ERR(cq);
+
+ ret = cq->device->ops.resize_cq(cq, cmd.cqe, &attrs->driver_udata);
+ if (ret)
+@@ -1187,8 +1187,8 @@ static int ib_uverbs_poll_cq(struct uverbs_attr_bundle *attrs)
+ return ret;
+
+ cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, attrs);
+- if (!cq)
+- return -EINVAL;
++ if (IS_ERR(cq))
++ return PTR_ERR(cq);
+
+ /* we copy a struct ib_uverbs_poll_cq_resp to user space */
+ header_ptr = attrs->ucore.outbuf;
+@@ -1236,8 +1236,8 @@ static int ib_uverbs_req_notify_cq(struct uverbs_attr_bundle *attrs)
+ return ret;
+
+ cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, attrs);
+- if (!cq)
+- return -EINVAL;
++ if (IS_ERR(cq))
++ return PTR_ERR(cq);
+
+ ib_req_notify_cq(cq, cmd.solicited_only ?
+ IB_CQ_SOLICITED : IB_CQ_NEXT_COMP);
+@@ -1319,8 +1319,8 @@ static int create_qp(struct uverbs_attr_bundle *attrs,
+ ind_tbl = uobj_get_obj_read(rwq_ind_table,
+ UVERBS_OBJECT_RWQ_IND_TBL,
+ cmd->rwq_ind_tbl_handle, attrs);
+- if (!ind_tbl) {
+- ret = -EINVAL;
++ if (IS_ERR(ind_tbl)) {
++ ret = PTR_ERR(ind_tbl);
+ goto err_put;
+ }
+
+@@ -1358,8 +1358,10 @@ static int create_qp(struct uverbs_attr_bundle *attrs,
+ if (cmd->is_srq) {
+ srq = uobj_get_obj_read(srq, UVERBS_OBJECT_SRQ,
+ cmd->srq_handle, attrs);
+- if (!srq || srq->srq_type == IB_SRQT_XRC) {
+- ret = -EINVAL;
++ if (IS_ERR(srq) ||
++ srq->srq_type == IB_SRQT_XRC) {
++ ret = IS_ERR(srq) ? PTR_ERR(srq) :
++ -EINVAL;
+ goto err_put;
+ }
+ }
+@@ -1369,23 +1371,29 @@ static int create_qp(struct uverbs_attr_bundle *attrs,
+ rcq = uobj_get_obj_read(
+ cq, UVERBS_OBJECT_CQ,
+ cmd->recv_cq_handle, attrs);
+- if (!rcq) {
+- ret = -EINVAL;
++ if (IS_ERR(rcq)) {
++ ret = PTR_ERR(rcq);
+ goto err_put;
+ }
+ }
+ }
+ }
+
+- if (has_sq)
++ if (has_sq) {
+ scq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ,
+ cmd->send_cq_handle, attrs);
++ if (IS_ERR(scq)) {
++ ret = PTR_ERR(scq);
++ goto err_put;
++ }
++ }
++
+ if (!ind_tbl && cmd->qp_type != IB_QPT_XRC_INI)
+ rcq = rcq ?: scq;
+ pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd->pd_handle,
+ attrs);
+- if (!pd || (!scq && has_sq)) {
+- ret = -EINVAL;
++ if (IS_ERR(pd)) {
++ ret = PTR_ERR(pd);
+ goto err_put;
+ }
+
+@@ -1480,18 +1488,18 @@ static int create_qp(struct uverbs_attr_bundle *attrs,
+ err_put:
+ if (!IS_ERR(xrcd_uobj))
+ uobj_put_read(xrcd_uobj);
+- if (pd)
++ if (!IS_ERR_OR_NULL(pd))
+ uobj_put_obj_read(pd);
+- if (scq)
++ if (!IS_ERR_OR_NULL(scq))
+ rdma_lookup_put_uobject(&scq->uobject->uevent.uobject,
+ UVERBS_LOOKUP_READ);
+- if (rcq && rcq != scq)
++ if (!IS_ERR_OR_NULL(rcq) && rcq != scq)
+ rdma_lookup_put_uobject(&rcq->uobject->uevent.uobject,
+ UVERBS_LOOKUP_READ);
+- if (srq)
++ if (!IS_ERR_OR_NULL(srq))
+ rdma_lookup_put_uobject(&srq->uobject->uevent.uobject,
+ UVERBS_LOOKUP_READ);
+- if (ind_tbl)
++ if (!IS_ERR_OR_NULL(ind_tbl))
+ uobj_put_obj_read(ind_tbl);
+
+ uobj_alloc_abort(&obj->uevent.uobject, attrs);
+@@ -1653,8 +1661,8 @@ static int ib_uverbs_query_qp(struct uverbs_attr_bundle *attrs)
+ }
+
+ qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs);
+- if (!qp) {
+- ret = -EINVAL;
++ if (IS_ERR(qp)) {
++ ret = PTR_ERR(qp);
+ goto out;
+ }
+
+@@ -1759,8 +1767,8 @@ static int modify_qp(struct uverbs_attr_bundle *attrs,
+
+ qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd->base.qp_handle,
+ attrs);
+- if (!qp) {
+- ret = -EINVAL;
++ if (IS_ERR(qp)) {
++ ret = PTR_ERR(qp);
+ goto out;
+ }
+
+@@ -2026,8 +2034,8 @@ static int ib_uverbs_post_send(struct uverbs_attr_bundle *attrs)
+ return -ENOMEM;
+
+ qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs);
+- if (!qp) {
+- ret = -EINVAL;
++ if (IS_ERR(qp)) {
++ ret = PTR_ERR(qp);
+ goto out;
+ }
+
+@@ -2064,9 +2072,9 @@ static int ib_uverbs_post_send(struct uverbs_attr_bundle *attrs)
+
+ ud->ah = uobj_get_obj_read(ah, UVERBS_OBJECT_AH,
+ user_wr->wr.ud.ah, attrs);
+- if (!ud->ah) {
++ if (IS_ERR(ud->ah)) {
++ ret = PTR_ERR(ud->ah);
+ kfree(ud);
+- ret = -EINVAL;
+ goto out_put;
+ }
+ ud->remote_qpn = user_wr->wr.ud.remote_qpn;
+@@ -2303,8 +2311,8 @@ static int ib_uverbs_post_recv(struct uverbs_attr_bundle *attrs)
+ return PTR_ERR(wr);
+
+ qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs);
+- if (!qp) {
+- ret = -EINVAL;
++ if (IS_ERR(qp)) {
++ ret = PTR_ERR(qp);
+ goto out;
+ }
+
+@@ -2354,8 +2362,8 @@ static int ib_uverbs_post_srq_recv(struct uverbs_attr_bundle *attrs)
+ return PTR_ERR(wr);
+
+ srq = uobj_get_obj_read(srq, UVERBS_OBJECT_SRQ, cmd.srq_handle, attrs);
+- if (!srq) {
+- ret = -EINVAL;
++ if (IS_ERR(srq)) {
++ ret = PTR_ERR(srq);
+ goto out;
+ }
+
+@@ -2411,8 +2419,8 @@ static int ib_uverbs_create_ah(struct uverbs_attr_bundle *attrs)
+ }
+
+ pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle, attrs);
+- if (!pd) {
+- ret = -EINVAL;
++ if (IS_ERR(pd)) {
++ ret = PTR_ERR(pd);
+ goto err;
+ }
+
+@@ -2481,8 +2489,8 @@ static int ib_uverbs_attach_mcast(struct uverbs_attr_bundle *attrs)
+ return ret;
+
+ qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs);
+- if (!qp)
+- return -EINVAL;
++ if (IS_ERR(qp))
++ return PTR_ERR(qp);
+
+ obj = qp->uobject;
+
+@@ -2531,8 +2539,8 @@ static int ib_uverbs_detach_mcast(struct uverbs_attr_bundle *attrs)
+ return ret;
+
+ qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs);
+- if (!qp)
+- return -EINVAL;
++ if (IS_ERR(qp))
++ return PTR_ERR(qp);
+
+ obj = qp->uobject;
+ mutex_lock(&obj->mcast_lock);
+@@ -2666,8 +2674,8 @@ static int kern_spec_to_ib_spec_action(struct uverbs_attr_bundle *attrs,
+ UVERBS_OBJECT_FLOW_ACTION,
+ kern_spec->action.handle,
+ attrs);
+- if (!ib_spec->action.act)
+- return -EINVAL;
++ if (IS_ERR(ib_spec->action.act))
++ return PTR_ERR(ib_spec->action.act);
+ ib_spec->action.size =
+ sizeof(struct ib_flow_spec_action_handle);
+ flow_resources_add(uflow_res,
+@@ -2684,8 +2692,8 @@ static int kern_spec_to_ib_spec_action(struct uverbs_attr_bundle *attrs,
+ UVERBS_OBJECT_COUNTERS,
+ kern_spec->flow_count.handle,
+ attrs);
+- if (!ib_spec->flow_count.counters)
+- return -EINVAL;
++ if (IS_ERR(ib_spec->flow_count.counters))
++ return PTR_ERR(ib_spec->flow_count.counters);
+ ib_spec->flow_count.size =
+ sizeof(struct ib_flow_spec_action_count);
+ flow_resources_add(uflow_res,
+@@ -2903,14 +2911,14 @@ static int ib_uverbs_ex_create_wq(struct uverbs_attr_bundle *attrs)
+ return PTR_ERR(obj);
+
+ pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle, attrs);
+- if (!pd) {
+- err = -EINVAL;
++ if (IS_ERR(pd)) {
++ err = PTR_ERR(pd);
+ goto err_uobj;
+ }
+
+ cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, attrs);
+- if (!cq) {
+- err = -EINVAL;
++ if (IS_ERR(cq)) {
++ err = PTR_ERR(cq);
+ goto err_put_pd;
+ }
+
+@@ -3011,8 +3019,8 @@ static int ib_uverbs_ex_modify_wq(struct uverbs_attr_bundle *attrs)
+ return -EINVAL;
+
+ wq = uobj_get_obj_read(wq, UVERBS_OBJECT_WQ, cmd.wq_handle, attrs);
+- if (!wq)
+- return -EINVAL;
++ if (IS_ERR(wq))
++ return PTR_ERR(wq);
+
+ if (cmd.attr_mask & IB_WQ_FLAGS) {
+ wq_attr.flags = cmd.flags;
+@@ -3095,8 +3103,8 @@ static int ib_uverbs_ex_create_rwq_ind_table(struct uverbs_attr_bundle *attrs)
+ num_read_wqs++) {
+ wq = uobj_get_obj_read(wq, UVERBS_OBJECT_WQ,
+ wqs_handles[num_read_wqs], attrs);
+- if (!wq) {
+- err = -EINVAL;
++ if (IS_ERR(wq)) {
++ err = PTR_ERR(wq);
+ goto put_wqs;
+ }
+
+@@ -3251,8 +3259,8 @@ static int ib_uverbs_ex_create_flow(struct uverbs_attr_bundle *attrs)
+ }
+
+ qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs);
+- if (!qp) {
+- err = -EINVAL;
++ if (IS_ERR(qp)) {
++ err = PTR_ERR(qp);
+ goto err_uobj;
+ }
+
+@@ -3398,15 +3406,15 @@ static int __uverbs_create_xsrq(struct uverbs_attr_bundle *attrs,
+ if (ib_srq_has_cq(cmd->srq_type)) {
+ attr.ext.cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ,
+ cmd->cq_handle, attrs);
+- if (!attr.ext.cq) {
+- ret = -EINVAL;
++ if (IS_ERR(attr.ext.cq)) {
++ ret = PTR_ERR(attr.ext.cq);
+ goto err_put_xrcd;
+ }
+ }
+
+ pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd->pd_handle, attrs);
+- if (!pd) {
+- ret = -EINVAL;
++ if (IS_ERR(pd)) {
++ ret = PTR_ERR(pd);
+ goto err_put_cq;
+ }
+
+@@ -3513,8 +3521,8 @@ static int ib_uverbs_modify_srq(struct uverbs_attr_bundle *attrs)
+ return ret;
+
+ srq = uobj_get_obj_read(srq, UVERBS_OBJECT_SRQ, cmd.srq_handle, attrs);
+- if (!srq)
+- return -EINVAL;
++ if (IS_ERR(srq))
++ return PTR_ERR(srq);
+
+ attr.max_wr = cmd.max_wr;
+ attr.srq_limit = cmd.srq_limit;
+@@ -3541,8 +3549,8 @@ static int ib_uverbs_query_srq(struct uverbs_attr_bundle *attrs)
+ return ret;
+
+ srq = uobj_get_obj_read(srq, UVERBS_OBJECT_SRQ, cmd.srq_handle, attrs);
+- if (!srq)
+- return -EINVAL;
++ if (IS_ERR(srq))
++ return PTR_ERR(srq);
+
+ ret = ib_query_srq(srq, &attr);
+
+@@ -3667,8 +3675,8 @@ static int ib_uverbs_ex_modify_cq(struct uverbs_attr_bundle *attrs)
+ return -EOPNOTSUPP;
+
+ cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, attrs);
+- if (!cq)
+- return -EINVAL;
++ if (IS_ERR(cq))
++ return PTR_ERR(cq);
+
+ ret = rdma_set_cq_moderation(cq, cmd.attr.cq_count, cmd.attr.cq_period);
+
+diff --git a/include/rdma/uverbs_std_types.h b/include/rdma/uverbs_std_types.h
+index fe05121169589..555ea3d142a46 100644
+--- a/include/rdma/uverbs_std_types.h
++++ b/include/rdma/uverbs_std_types.h
+@@ -34,7 +34,7 @@
+ static inline void *_uobj_get_obj_read(struct ib_uobject *uobj)
+ {
+ if (IS_ERR(uobj))
+- return NULL;
++ return ERR_CAST(uobj);
+ return uobj->object;
+ }
+ #define uobj_get_obj_read(_object, _type, _id, _attrs) \
+--
+2.39.5
+
--- /dev/null
+From 88d1e94e5eaedcb1e8338d755d3299d208e8a87a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jan 2025 17:31:43 +0000
+Subject: regulator: ad5398: Add device tree support
+
+From: Isaac Scott <isaac.scott@ideasonboard.com>
+
+[ Upstream commit 5a6a461079decea452fdcae955bccecf92e07e97 ]
+
+Previously, the ad5398 driver used only platform_data, which is
+deprecated in favour of device tree. This caused the AD5398 to fail to
+probe as it could not load its init_data. If the AD5398 has a device
+tree node, pull the init_data from there using
+of_get_regulator_init_data.
+
+Signed-off-by: Isaac Scott <isaac.scott@ideasonboard.com>
+Acked-by: Michael Hennerich <michael.hennerich@analog.com>
+Link: https://patch.msgid.link/20250128173143.959600-4-isaac.scott@ideasonboard.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/regulator/ad5398.c | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/regulator/ad5398.c b/drivers/regulator/ad5398.c
+index 40f7dba42b5ad..404cbe32711e7 100644
+--- a/drivers/regulator/ad5398.c
++++ b/drivers/regulator/ad5398.c
+@@ -14,6 +14,7 @@
+ #include <linux/platform_device.h>
+ #include <linux/regulator/driver.h>
+ #include <linux/regulator/machine.h>
++#include <linux/regulator/of_regulator.h>
+
+ #define AD5398_CURRENT_EN_MASK 0x8000
+
+@@ -221,15 +222,20 @@ static int ad5398_probe(struct i2c_client *client)
+ const struct ad5398_current_data_format *df =
+ (struct ad5398_current_data_format *)id->driver_data;
+
+- if (!init_data)
+- return -EINVAL;
+-
+ chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ config.dev = &client->dev;
++ if (client->dev.of_node)
++ init_data = of_get_regulator_init_data(&client->dev,
++ client->dev.of_node,
++ &ad5398_reg);
++ if (!init_data)
++ return -EINVAL;
++
+ config.init_data = init_data;
++ config.of_node = client->dev.of_node;
+ config.driver_data = chip;
+
+ chip->client = client;
+--
+2.39.5
+
--- /dev/null
+From 79ae2d6e2ec622378c2f50a17e337b9d487afb54 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Feb 2025 20:56:48 +0100
+Subject: remoteproc: qcom_wcnss: Handle platforms with only single power
+ domain
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Matti Lehtimäki <matti.lehtimaki@gmail.com>
+
+[ Upstream commit 65991ea8a6d1e68effdc01d95ebe39f1653f7b71 ]
+
+Both MSM8974 and MSM8226 have only CX as power domain with MX & PX being
+handled as regulators. Handle this case by reodering pd_names to have CX
+first, and handling that the driver core will already attach a single
+power domain internally.
+
+Signed-off-by: Matti Lehtimäki <matti.lehtimaki@gmail.com>
+[luca: minor changes]
+Signed-off-by: Luca Weiss <luca@lucaweiss.eu>
+Link: https://lore.kernel.org/r/20250206-wcnss-singlepd-v2-2-9a53ee953dee@lucaweiss.eu
+[bjorn: Added missing braces to else after multi-statement if]
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/remoteproc/qcom_wcnss.c | 33 ++++++++++++++++++++++++++-------
+ 1 file changed, 26 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
+index 5b5664603eed2..775b056d795a8 100644
+--- a/drivers/remoteproc/qcom_wcnss.c
++++ b/drivers/remoteproc/qcom_wcnss.c
+@@ -117,10 +117,10 @@ static const struct wcnss_data pronto_v1_data = {
+ .pmu_offset = 0x1004,
+ .spare_offset = 0x1088,
+
+- .pd_names = { "mx", "cx" },
++ .pd_names = { "cx", "mx" },
+ .vregs = (struct wcnss_vreg_info[]) {
+- { "vddmx", 950000, 1150000, 0 },
+ { "vddcx", .super_turbo = true},
++ { "vddmx", 950000, 1150000, 0 },
+ { "vddpx", 1800000, 1800000, 0 },
+ },
+ .num_pd_vregs = 2,
+@@ -131,10 +131,10 @@ static const struct wcnss_data pronto_v2_data = {
+ .pmu_offset = 0x1004,
+ .spare_offset = 0x1088,
+
+- .pd_names = { "mx", "cx" },
++ .pd_names = { "cx", "mx" },
+ .vregs = (struct wcnss_vreg_info[]) {
+- { "vddmx", 1287500, 1287500, 0 },
+ { "vddcx", .super_turbo = true },
++ { "vddmx", 1287500, 1287500, 0 },
+ { "vddpx", 1800000, 1800000, 0 },
+ },
+ .num_pd_vregs = 2,
+@@ -397,8 +397,17 @@ static irqreturn_t wcnss_stop_ack_interrupt(int irq, void *dev)
+ static int wcnss_init_pds(struct qcom_wcnss *wcnss,
+ const char * const pd_names[WCNSS_MAX_PDS])
+ {
++ struct device *dev = wcnss->dev;
+ int i, ret;
+
++ /* Handle single power domain */
++ if (dev->pm_domain) {
++ wcnss->pds[0] = dev;
++ wcnss->num_pds = 1;
++ pm_runtime_enable(dev);
++ return 0;
++ }
++
+ for (i = 0; i < WCNSS_MAX_PDS; i++) {
+ if (!pd_names[i])
+ break;
+@@ -418,8 +427,15 @@ static int wcnss_init_pds(struct qcom_wcnss *wcnss,
+
+ static void wcnss_release_pds(struct qcom_wcnss *wcnss)
+ {
++ struct device *dev = wcnss->dev;
+ int i;
+
++ /* Handle single power domain */
++ if (wcnss->num_pds == 1 && dev->pm_domain) {
++ pm_runtime_disable(dev);
++ return;
++ }
++
+ for (i = 0; i < wcnss->num_pds; i++)
+ dev_pm_domain_detach(wcnss->pds[i], false);
+ }
+@@ -437,10 +453,13 @@ static int wcnss_init_regulators(struct qcom_wcnss *wcnss,
+ * the regulators for the power domains. For old device trees we need to
+ * reserve extra space to manage them through the regulator interface.
+ */
+- if (wcnss->num_pds)
+- info += num_pd_vregs;
+- else
++ if (wcnss->num_pds) {
++ info += wcnss->num_pds;
++ /* Handle single power domain case */
++ num_vregs += num_pd_vregs - wcnss->num_pds;
++ } else {
+ num_vregs += num_pd_vregs;
++ }
+
+ bulk = devm_kcalloc(wcnss->dev,
+ num_vregs, sizeof(struct regulator_bulk_data),
+--
+2.39.5
+
--- /dev/null
+From b7eaabcbc077d065af9776dc08dc9929bd0d2a72 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 21 Jan 2025 13:29:51 +0800
+Subject: Revert "drm/amd/display: Exit idle optimizations before attempt to
+ access PHY"
+
+From: Brandon Syu <Brandon.Syu@amd.com>
+
+[ Upstream commit be704e5ef4bd66dee9bb3f876964327e3a247d31 ]
+
+This reverts commit de612738e9771bd66aeb20044486c457c512f684.
+
+Reason to revert: screen flashes or gray screen appeared half of the
+screen after resume from S4/S5.
+
+Reviewed-by: Charlene Liu <charlene.liu@amd.com>
+Signed-off-by: Brandon Syu <Brandon.Syu@amd.com>
+Signed-off-by: Alex Hung <alex.hung@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c | 5 -----
+ 1 file changed, 5 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
+index 94ceccfc04982..2f5f3e749a1ab 100644
+--- a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
++++ b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
+@@ -1889,7 +1889,6 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context)
+ bool can_apply_edp_fast_boot = false;
+ bool can_apply_seamless_boot = false;
+ bool keep_edp_vdd_on = false;
+- struct dc_bios *dcb = dc->ctx->dc_bios;
+ DC_LOGGER_INIT();
+
+
+@@ -1966,8 +1965,6 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context)
+ hws->funcs.edp_backlight_control(edp_link_with_sink, false);
+ }
+ /*resume from S3, no vbios posting, no need to power down again*/
+- if (dcb && dcb->funcs && !dcb->funcs->is_accelerated_mode(dcb))
+- clk_mgr_exit_optimized_pwr_state(dc, dc->clk_mgr);
+
+ power_down_all_hw_blocks(dc);
+
+@@ -1980,8 +1977,6 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context)
+ disable_vga_and_power_gate_all_controllers(dc);
+ if (edp_link_with_sink && !keep_edp_vdd_on)
+ dc->hwss.edp_power_control(edp_link_with_sink, false);
+- if (dcb && dcb->funcs && !dcb->funcs->is_accelerated_mode(dcb))
+- clk_mgr_optimize_pwr_state(dc, dc->clk_mgr);
+ }
+ bios_set_scratch_acc_mode_change(dc->ctx->dc_bios, 1);
+ }
+--
+2.39.5
+
--- /dev/null
+From 86c8fd69f744a04040ad5c0faf672c06c248ba94 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jan 2025 11:46:52 -0500
+Subject: Revert "drm/amd/display: Request HW cursor on DCN3.2 with SubVP"
+
+From: Leo Zeng <Leo.Zeng@amd.com>
+
+[ Upstream commit 8ae6dfc0b61b170cf13832d4cfe2a0c744e621a7 ]
+
+This reverts commit 13437c91606c9232c747475e202fe3827cd53264.
+
+Reason to revert: idle power regression found in testing.
+
+Reviewed-by: Dillon Varone <dillon.varone@amd.com>
+Signed-off-by: Leo Zeng <Leo.Zeng@amd.com>
+Signed-off-by: Roman Li <roman.li@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
+index 56dda686e2992..6f490d8d7038c 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
+@@ -626,7 +626,6 @@ static bool dcn32_assign_subvp_pipe(struct dc *dc,
+ * - Not TMZ surface
+ */
+ if (pipe->plane_state && !pipe->top_pipe && !pipe->prev_odm_pipe && !dcn32_is_center_timing(pipe) &&
+- !pipe->stream->hw_cursor_req &&
+ !(pipe->stream->timing.pix_clk_100hz / 10000 > DCN3_2_MAX_SUBVP_PIXEL_RATE_MHZ) &&
+ (!dcn32_is_psr_capable(pipe) || (context->stream_count == 1 && dc->caps.dmub_caps.subvp_psr)) &&
+ dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_NONE &&
+--
+2.39.5
+
--- /dev/null
+From 46f1d6670a502013aae3f53ca5cd000a55b78d65 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Mar 2025 11:45:40 -0500
+Subject: ring-buffer: Use kaslr address instead of text delta
+
+From: Steven Rostedt <rostedt@goodmis.org>
+
+[ Upstream commit bcba8d4dbe6880ce9883409df486de35d3946704 ]
+
+Instead of saving off the text and data pointers and using them to compare
+with the current boot's text and data pointers, just save off the KASLR
+offset. Then that can be used to figure out how to read the previous boots
+buffer.
+
+The last_boot_info will now show this offset, but only if it is for a
+previous boot:
+
+ ~# cat instances/boot_mapped/last_boot_info
+ 39000000 [kernel]
+
+ ~# echo function > instances/boot_mapped/current_tracer
+ ~# cat instances/boot_mapped/last_boot_info
+ # Current
+
+If the KASLR offset saved is for the current boot, the last_boot_info will
+show the value of "current".
+
+Cc: Mark Rutland <mark.rutland@arm.com>
+Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+Cc: Andrew Morton <akpm@linux-foundation.org>
+Link: https://lore.kernel.org/20250305164608.274956504@goodmis.org
+Reviewed-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/ring_buffer.h | 3 +--
+ kernel/trace/ring_buffer.c | 31 ++++++++++++-------------------
+ kernel/trace/trace.c | 30 +++++++++++++++++++++---------
+ kernel/trace/trace.h | 9 +++++----
+ 4 files changed, 39 insertions(+), 34 deletions(-)
+
+diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h
+index 17fbb78552952..8de035f4f0d9a 100644
+--- a/include/linux/ring_buffer.h
++++ b/include/linux/ring_buffer.h
+@@ -94,8 +94,7 @@ struct trace_buffer *__ring_buffer_alloc_range(unsigned long size, unsigned flag
+ unsigned long range_size,
+ struct lock_class_key *key);
+
+-bool ring_buffer_last_boot_delta(struct trace_buffer *buffer, long *text,
+- long *data);
++bool ring_buffer_last_boot_delta(struct trace_buffer *buffer, unsigned long *kaslr_addr);
+
+ /*
+ * Because the ring buffer is generic, if other users of the ring buffer get
+diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
+index f76bee67a792c..9b1db04c74e25 100644
+--- a/kernel/trace/ring_buffer.c
++++ b/kernel/trace/ring_buffer.c
+@@ -31,6 +31,7 @@
+
+ #include <asm/local64.h>
+ #include <asm/local.h>
++#include <asm/setup.h>
+
+ #include "trace.h"
+
+@@ -49,8 +50,7 @@ static void update_pages_handler(struct work_struct *work);
+ struct ring_buffer_meta {
+ int magic;
+ int struct_size;
+- unsigned long text_addr;
+- unsigned long data_addr;
++ unsigned long kaslr_addr;
+ unsigned long first_buffer;
+ unsigned long head_buffer;
+ unsigned long commit_buffer;
+@@ -550,8 +550,7 @@ struct trace_buffer {
+ unsigned long range_addr_start;
+ unsigned long range_addr_end;
+
+- long last_text_delta;
+- long last_data_delta;
++ unsigned long kaslr_addr;
+
+ unsigned int subbuf_size;
+ unsigned int subbuf_order;
+@@ -1893,16 +1892,13 @@ static void rb_meta_validate_events(struct ring_buffer_per_cpu *cpu_buffer)
+ }
+ }
+
+-/* Used to calculate data delta */
+-static char rb_data_ptr[] = "";
+-
+-#define THIS_TEXT_PTR ((unsigned long)rb_meta_init_text_addr)
+-#define THIS_DATA_PTR ((unsigned long)rb_data_ptr)
+-
+ static void rb_meta_init_text_addr(struct ring_buffer_meta *meta)
+ {
+- meta->text_addr = THIS_TEXT_PTR;
+- meta->data_addr = THIS_DATA_PTR;
++#ifdef CONFIG_RANDOMIZE_BASE
++ meta->kaslr_addr = kaslr_offset();
++#else
++ meta->kaslr_addr = 0;
++#endif
+ }
+
+ static void rb_range_meta_init(struct trace_buffer *buffer, int nr_pages)
+@@ -1930,8 +1926,7 @@ static void rb_range_meta_init(struct trace_buffer *buffer, int nr_pages)
+ meta->first_buffer += delta;
+ meta->head_buffer += delta;
+ meta->commit_buffer += delta;
+- buffer->last_text_delta = THIS_TEXT_PTR - meta->text_addr;
+- buffer->last_data_delta = THIS_DATA_PTR - meta->data_addr;
++ buffer->kaslr_addr = meta->kaslr_addr;
+ continue;
+ }
+
+@@ -2484,17 +2479,15 @@ struct trace_buffer *__ring_buffer_alloc_range(unsigned long size, unsigned flag
+ *
+ * Returns: The true if the delta is non zero
+ */
+-bool ring_buffer_last_boot_delta(struct trace_buffer *buffer, long *text,
+- long *data)
++bool ring_buffer_last_boot_delta(struct trace_buffer *buffer, unsigned long *kaslr_addr)
+ {
+ if (!buffer)
+ return false;
+
+- if (!buffer->last_text_delta)
++ if (!buffer->kaslr_addr)
+ return false;
+
+- *text = buffer->last_text_delta;
+- *data = buffer->last_data_delta;
++ *kaslr_addr = buffer->kaslr_addr;
+
+ return true;
+ }
+diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
+index 814626bb410b2..c3f1365ec9609 100644
+--- a/kernel/trace/trace.c
++++ b/kernel/trace/trace.c
+@@ -50,7 +50,7 @@
+ #include <linux/irq_work.h>
+ #include <linux/workqueue.h>
+
+-#include <asm/setup.h> /* COMMAND_LINE_SIZE */
++#include <asm/setup.h> /* COMMAND_LINE_SIZE and kaslr_offset() */
+
+ #include "trace.h"
+ #include "trace_output.h"
+@@ -4193,7 +4193,7 @@ static enum print_line_t print_trace_fmt(struct trace_iterator *iter)
+ * safe to use if the array has delta offsets
+ * Force printing via the fields.
+ */
+- if ((tr->text_delta || tr->data_delta) &&
++ if ((tr->text_delta) &&
+ event->type > __TRACE_LAST_TYPE)
+ return print_event_fields(iter, event);
+
+@@ -5990,7 +5990,7 @@ ssize_t tracing_resize_ring_buffer(struct trace_array *tr,
+
+ static void update_last_data(struct trace_array *tr)
+ {
+- if (!tr->text_delta && !tr->data_delta)
++ if (!(tr->flags & TRACE_ARRAY_FL_LAST_BOOT))
+ return;
+
+ /*
+@@ -6003,7 +6003,8 @@ static void update_last_data(struct trace_array *tr)
+
+ /* Using current data now */
+ tr->text_delta = 0;
+- tr->data_delta = 0;
++
++ tr->flags &= ~TRACE_ARRAY_FL_LAST_BOOT;
+ }
+
+ /**
+@@ -6822,8 +6823,17 @@ tracing_last_boot_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t
+
+ seq_buf_init(&seq, buf, 64);
+
+- seq_buf_printf(&seq, "text delta:\t%ld\n", tr->text_delta);
+- seq_buf_printf(&seq, "data delta:\t%ld\n", tr->data_delta);
++ /*
++ * Do not leak KASLR address. This only shows the KASLR address of
++ * the last boot. When the ring buffer is started, the LAST_BOOT
++ * flag gets cleared, and this should only report "current".
++ * Otherwise it shows the KASLR address from the previous boot which
++ * should not be the same as the current boot.
++ */
++ if (tr->flags & TRACE_ARRAY_FL_LAST_BOOT)
++ seq_buf_printf(&seq, "%lx\t[kernel]\n", tr->kaslr_addr);
++ else
++ seq_buf_puts(&seq, "# Current\n");
+
+ return simple_read_from_buffer(ubuf, cnt, ppos, buf, seq_buf_used(&seq));
+ }
+@@ -9211,8 +9221,10 @@ allocate_trace_buffer(struct trace_array *tr, struct array_buffer *buf, int size
+ tr->range_addr_start,
+ tr->range_addr_size);
+
+- ring_buffer_last_boot_delta(buf->buffer,
+- &tr->text_delta, &tr->data_delta);
++#ifdef CONFIG_RANDOMIZE_BASE
++ if (ring_buffer_last_boot_delta(buf->buffer, &tr->kaslr_addr))
++ tr->text_delta = kaslr_offset() - tr->kaslr_addr;
++#endif
+ /*
+ * This is basically the same as a mapped buffer,
+ * with the same restrictions.
+@@ -10470,7 +10482,7 @@ __init static void enable_instances(void)
+ * to it.
+ */
+ if (start) {
+- tr->flags |= TRACE_ARRAY_FL_BOOT;
++ tr->flags |= TRACE_ARRAY_FL_BOOT | TRACE_ARRAY_FL_LAST_BOOT;
+ tr->ref++;
+ }
+
+diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
+index 9c21ba45b7af6..abe8169c3e879 100644
+--- a/kernel/trace/trace.h
++++ b/kernel/trace/trace.h
+@@ -348,8 +348,8 @@ struct trace_array {
+ unsigned int mapped;
+ unsigned long range_addr_start;
+ unsigned long range_addr_size;
++ unsigned long kaslr_addr;
+ long text_delta;
+- long data_delta;
+
+ struct trace_pid_list __rcu *filtered_pids;
+ struct trace_pid_list __rcu *filtered_no_pids;
+@@ -433,9 +433,10 @@ struct trace_array {
+ };
+
+ enum {
+- TRACE_ARRAY_FL_GLOBAL = BIT(0),
+- TRACE_ARRAY_FL_BOOT = BIT(1),
+- TRACE_ARRAY_FL_MOD_INIT = BIT(2),
++ TRACE_ARRAY_FL_GLOBAL = BIT(0),
++ TRACE_ARRAY_FL_BOOT = BIT(1),
++ TRACE_ARRAY_FL_LAST_BOOT = BIT(2),
++ TRACE_ARRAY_FL_MOD_INIT = BIT(3),
+ };
+
+ #ifdef CONFIG_MODULES
+--
+2.39.5
+
--- /dev/null
+From 83c3b01bf2256da135b68ca5367043c784d171b9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 12 Mar 2025 13:11:44 +0000
+Subject: RISC-V: add vector extension validation checks
+
+From: Conor Dooley <conor.dooley@microchip.com>
+
+[ Upstream commit 9324571e9eea231321acf0a3d0fbc85a6e0f6ff6 ]
+
+Using Clement's new validation callbacks, support checking that
+dependencies have been satisfied for the vector extensions. From the
+kernel's perfective, it's not required to differentiate between the
+conditions for all the various vector subsets - it's the firmware's job
+to not report impossible combinations. Instead, the kernel only has to
+check that the correct config options are enabled and to enforce its
+requirement of the d extension being present for FPU support.
+
+Since vector will now be disabled proactively, there's no need to clear
+the bit in elf_hwcap in riscv_fill_hwcap() any longer.
+
+Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
+Reviewed-by: Alexandre Ghiti <alexghiti@rivosinc.com>
+Link: https://lore.kernel.org/r/20250312-eclair-affluent-55b098c3602b@spud
+Signed-off-by: Alexandre Ghiti <alexghiti@rivosinc.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/riscv/include/asm/cpufeature.h | 3 ++
+ arch/riscv/kernel/cpufeature.c | 60 +++++++++++++++++++----------
+ 2 files changed, 43 insertions(+), 20 deletions(-)
+
+diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
+index 19defdc2002d8..f56b409361fbe 100644
+--- a/arch/riscv/include/asm/cpufeature.h
++++ b/arch/riscv/include/asm/cpufeature.h
+@@ -56,6 +56,9 @@ void __init riscv_user_isa_enable(void);
+ #define __RISCV_ISA_EXT_BUNDLE(_name, _bundled_exts) \
+ _RISCV_ISA_EXT_DATA(_name, RISCV_ISA_EXT_INVALID, _bundled_exts, \
+ ARRAY_SIZE(_bundled_exts), NULL)
++#define __RISCV_ISA_EXT_BUNDLE_VALIDATE(_name, _bundled_exts, _validate) \
++ _RISCV_ISA_EXT_DATA(_name, RISCV_ISA_EXT_INVALID, _bundled_exts, \
++ ARRAY_SIZE(_bundled_exts), _validate)
+
+ /* Used to declare extensions that are a superset of other extensions (Zvbb for instance) */
+ #define __RISCV_ISA_EXT_SUPERSET(_name, _id, _sub_exts) \
+diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
+index 40ac72e407b68..76a3b34d7a707 100644
+--- a/arch/riscv/kernel/cpufeature.c
++++ b/arch/riscv/kernel/cpufeature.c
+@@ -109,6 +109,38 @@ static int riscv_ext_zicboz_validate(const struct riscv_isa_ext_data *data,
+ return 0;
+ }
+
++static int riscv_ext_vector_x_validate(const struct riscv_isa_ext_data *data,
++ const unsigned long *isa_bitmap)
++{
++ if (!IS_ENABLED(CONFIG_RISCV_ISA_V))
++ return -EINVAL;
++
++ return 0;
++}
++
++static int riscv_ext_vector_float_validate(const struct riscv_isa_ext_data *data,
++ const unsigned long *isa_bitmap)
++{
++ if (!IS_ENABLED(CONFIG_RISCV_ISA_V))
++ return -EINVAL;
++
++ if (!IS_ENABLED(CONFIG_FPU))
++ return -EINVAL;
++
++ /*
++ * The kernel doesn't support systems that don't implement both of
++ * F and D, so if any of the vector extensions that do floating point
++ * are to be usable, both floating point extensions need to be usable.
++ *
++ * Since this function validates vector only, and v/Zve* are probed
++ * after f/d, there's no need for a deferral here.
++ */
++ if (!__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_d))
++ return -EINVAL;
++
++ return 0;
++}
++
+ static int riscv_ext_zca_depends(const struct riscv_isa_ext_data *data,
+ const unsigned long *isa_bitmap)
+ {
+@@ -326,12 +358,10 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
+ __RISCV_ISA_EXT_DATA(d, RISCV_ISA_EXT_d),
+ __RISCV_ISA_EXT_DATA(q, RISCV_ISA_EXT_q),
+ __RISCV_ISA_EXT_SUPERSET(c, RISCV_ISA_EXT_c, riscv_c_exts),
+- __RISCV_ISA_EXT_SUPERSET(v, RISCV_ISA_EXT_v, riscv_v_exts),
++ __RISCV_ISA_EXT_SUPERSET_VALIDATE(v, RISCV_ISA_EXT_v, riscv_v_exts, riscv_ext_vector_float_validate),
+ __RISCV_ISA_EXT_DATA(h, RISCV_ISA_EXT_h),
+- __RISCV_ISA_EXT_SUPERSET_VALIDATE(zicbom, RISCV_ISA_EXT_ZICBOM, riscv_xlinuxenvcfg_exts,
+- riscv_ext_zicbom_validate),
+- __RISCV_ISA_EXT_SUPERSET_VALIDATE(zicboz, RISCV_ISA_EXT_ZICBOZ, riscv_xlinuxenvcfg_exts,
+- riscv_ext_zicboz_validate),
++ __RISCV_ISA_EXT_SUPERSET_VALIDATE(zicbom, RISCV_ISA_EXT_ZICBOM, riscv_xlinuxenvcfg_exts, riscv_ext_zicbom_validate),
++ __RISCV_ISA_EXT_SUPERSET_VALIDATE(zicboz, RISCV_ISA_EXT_ZICBOZ, riscv_xlinuxenvcfg_exts, riscv_ext_zicboz_validate),
+ __RISCV_ISA_EXT_DATA(ziccrse, RISCV_ISA_EXT_ZICCRSE),
+ __RISCV_ISA_EXT_DATA(zicntr, RISCV_ISA_EXT_ZICNTR),
+ __RISCV_ISA_EXT_DATA(zicond, RISCV_ISA_EXT_ZICOND),
+@@ -372,11 +402,11 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
+ __RISCV_ISA_EXT_DATA(ztso, RISCV_ISA_EXT_ZTSO),
+ __RISCV_ISA_EXT_SUPERSET(zvbb, RISCV_ISA_EXT_ZVBB, riscv_zvbb_exts),
+ __RISCV_ISA_EXT_DATA(zvbc, RISCV_ISA_EXT_ZVBC),
+- __RISCV_ISA_EXT_SUPERSET(zve32f, RISCV_ISA_EXT_ZVE32F, riscv_zve32f_exts),
+- __RISCV_ISA_EXT_DATA(zve32x, RISCV_ISA_EXT_ZVE32X),
+- __RISCV_ISA_EXT_SUPERSET(zve64d, RISCV_ISA_EXT_ZVE64D, riscv_zve64d_exts),
+- __RISCV_ISA_EXT_SUPERSET(zve64f, RISCV_ISA_EXT_ZVE64F, riscv_zve64f_exts),
+- __RISCV_ISA_EXT_SUPERSET(zve64x, RISCV_ISA_EXT_ZVE64X, riscv_zve64x_exts),
++ __RISCV_ISA_EXT_SUPERSET_VALIDATE(zve32f, RISCV_ISA_EXT_ZVE32F, riscv_zve32f_exts, riscv_ext_vector_float_validate),
++ __RISCV_ISA_EXT_DATA_VALIDATE(zve32x, RISCV_ISA_EXT_ZVE32X, riscv_ext_vector_x_validate),
++ __RISCV_ISA_EXT_SUPERSET_VALIDATE(zve64d, RISCV_ISA_EXT_ZVE64D, riscv_zve64d_exts, riscv_ext_vector_float_validate),
++ __RISCV_ISA_EXT_SUPERSET_VALIDATE(zve64f, RISCV_ISA_EXT_ZVE64F, riscv_zve64f_exts, riscv_ext_vector_float_validate),
++ __RISCV_ISA_EXT_SUPERSET_VALIDATE(zve64x, RISCV_ISA_EXT_ZVE64X, riscv_zve64x_exts, riscv_ext_vector_x_validate),
+ __RISCV_ISA_EXT_DATA(zvfh, RISCV_ISA_EXT_ZVFH),
+ __RISCV_ISA_EXT_DATA(zvfhmin, RISCV_ISA_EXT_ZVFHMIN),
+ __RISCV_ISA_EXT_DATA(zvkb, RISCV_ISA_EXT_ZVKB),
+@@ -960,16 +990,6 @@ void __init riscv_fill_hwcap(void)
+ riscv_v_setup_vsize();
+ }
+
+- if (elf_hwcap & COMPAT_HWCAP_ISA_V) {
+- /*
+- * ISA string in device tree might have 'v' flag, but
+- * CONFIG_RISCV_ISA_V is disabled in kernel.
+- * Clear V flag in elf_hwcap if CONFIG_RISCV_ISA_V is disabled.
+- */
+- if (!IS_ENABLED(CONFIG_RISCV_ISA_V))
+- elf_hwcap &= ~COMPAT_HWCAP_ISA_V;
+- }
+-
+ memset(print_str, 0, sizeof(print_str));
+ for (i = 0, j = 0; i < NUM_ALPHA_EXTS; i++)
+ if (riscv_isa[0] & BIT_MASK(i))
+--
+2.39.5
+
--- /dev/null
+From e06c1f5291f6398765f253c344e846364a828dfc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 26 Oct 2024 10:13:54 -0700
+Subject: riscv: Allow NOMMU kernels to access all of RAM
+
+From: Samuel Holland <samuel.holland@sifive.com>
+
+[ Upstream commit 2c0391b29b27f315c1b4c29ffde66f50b29fab99 ]
+
+NOMMU kernels currently cannot access memory below the kernel link
+address. Remove this restriction by setting PAGE_OFFSET to the actual
+start of RAM, as determined from the devicetree. The kernel link address
+must be a constant, so keep using CONFIG_PAGE_OFFSET for that purpose.
+
+Signed-off-by: Samuel Holland <samuel.holland@sifive.com>
+Reviewed-by: Jesse Taube <mr.bossman075@gmail.com>
+Link: https://lore.kernel.org/r/20241026171441.3047904-3-samuel.holland@sifive.com
+Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/riscv/include/asm/page.h | 12 ++++--------
+ arch/riscv/include/asm/pgtable.h | 2 +-
+ 2 files changed, 5 insertions(+), 9 deletions(-)
+
+diff --git a/arch/riscv/include/asm/page.h b/arch/riscv/include/asm/page.h
+index 125f5ecd95652..6409fd78ae6fa 100644
+--- a/arch/riscv/include/asm/page.h
++++ b/arch/riscv/include/asm/page.h
+@@ -24,12 +24,9 @@
+ * When not using MMU this corresponds to the first free page in
+ * physical memory (aligned on a page boundary).
+ */
+-#ifdef CONFIG_64BIT
+ #ifdef CONFIG_MMU
++#ifdef CONFIG_64BIT
+ #define PAGE_OFFSET kernel_map.page_offset
+-#else
+-#define PAGE_OFFSET _AC(CONFIG_PAGE_OFFSET, UL)
+-#endif
+ /*
+ * By default, CONFIG_PAGE_OFFSET value corresponds to SV57 address space so
+ * define the PAGE_OFFSET value for SV48 and SV39.
+@@ -39,6 +36,9 @@
+ #else
+ #define PAGE_OFFSET _AC(CONFIG_PAGE_OFFSET, UL)
+ #endif /* CONFIG_64BIT */
++#else
++#define PAGE_OFFSET ((unsigned long)phys_ram_base)
++#endif /* CONFIG_MMU */
+
+ #ifndef __ASSEMBLY__
+
+@@ -95,11 +95,7 @@ typedef struct page *pgtable_t;
+ #define MIN_MEMBLOCK_ADDR 0
+ #endif
+
+-#ifdef CONFIG_MMU
+ #define ARCH_PFN_OFFSET (PFN_DOWN((unsigned long)phys_ram_base))
+-#else
+-#define ARCH_PFN_OFFSET (PAGE_OFFSET >> PAGE_SHIFT)
+-#endif /* CONFIG_MMU */
+
+ struct kernel_mapping {
+ unsigned long page_offset;
+diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
+index 050fdc49b5ad7..eb7b25ef556ec 100644
+--- a/arch/riscv/include/asm/pgtable.h
++++ b/arch/riscv/include/asm/pgtable.h
+@@ -12,7 +12,7 @@
+ #include <asm/pgtable-bits.h>
+
+ #ifndef CONFIG_MMU
+-#define KERNEL_LINK_ADDR PAGE_OFFSET
++#define KERNEL_LINK_ADDR _AC(CONFIG_PAGE_OFFSET, UL)
+ #define KERN_VIRT_SIZE (UL(-1))
+ #else
+
+--
+2.39.5
+
--- /dev/null
+From fccd8283797d4dd02c472d4bbe8c82fae4b1c405 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Jan 2025 15:24:24 +0100
+Subject: riscv: Call secondary mmu notifier when flushing the tlb
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Alexandre Ghiti <alexghiti@rivosinc.com>
+
+[ Upstream commit d9be2b9b60497a82aeceec3a98d8b37fdd2960f2 ]
+
+This is required to allow the IOMMU driver to correctly flush its own
+TLB.
+
+Reviewed-by: Clément Léger <cleger@rivosinc.com>
+Reviewed-by: Samuel Holland <samuel.holland@sifive.com>
+Link: https://lore.kernel.org/r/20250113142424.30487-1-alexghiti@rivosinc.com
+Signed-off-by: Alexandre Ghiti <alexghiti@rivosinc.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/riscv/mm/tlbflush.c | 37 ++++++++++++++++++++++---------------
+ 1 file changed, 22 insertions(+), 15 deletions(-)
+
+diff --git a/arch/riscv/mm/tlbflush.c b/arch/riscv/mm/tlbflush.c
+index 9b6e86ce38674..bb77607c87aa2 100644
+--- a/arch/riscv/mm/tlbflush.c
++++ b/arch/riscv/mm/tlbflush.c
+@@ -4,6 +4,7 @@
+ #include <linux/smp.h>
+ #include <linux/sched.h>
+ #include <linux/hugetlb.h>
++#include <linux/mmu_notifier.h>
+ #include <asm/sbi.h>
+ #include <asm/mmu_context.h>
+
+@@ -78,10 +79,17 @@ static void __ipi_flush_tlb_range_asid(void *info)
+ local_flush_tlb_range_asid(d->start, d->size, d->stride, d->asid);
+ }
+
+-static void __flush_tlb_range(const struct cpumask *cmask, unsigned long asid,
++static inline unsigned long get_mm_asid(struct mm_struct *mm)
++{
++ return mm ? cntx2asid(atomic_long_read(&mm->context.id)) : FLUSH_TLB_NO_ASID;
++}
++
++static void __flush_tlb_range(struct mm_struct *mm,
++ const struct cpumask *cmask,
+ unsigned long start, unsigned long size,
+ unsigned long stride)
+ {
++ unsigned long asid = get_mm_asid(mm);
+ unsigned int cpu;
+
+ if (cpumask_empty(cmask))
+@@ -105,30 +113,26 @@ static void __flush_tlb_range(const struct cpumask *cmask, unsigned long asid,
+ }
+
+ put_cpu();
+-}
+
+-static inline unsigned long get_mm_asid(struct mm_struct *mm)
+-{
+- return cntx2asid(atomic_long_read(&mm->context.id));
++ if (mm)
++ mmu_notifier_arch_invalidate_secondary_tlbs(mm, start, start + size);
+ }
+
+ void flush_tlb_mm(struct mm_struct *mm)
+ {
+- __flush_tlb_range(mm_cpumask(mm), get_mm_asid(mm),
+- 0, FLUSH_TLB_MAX_SIZE, PAGE_SIZE);
++ __flush_tlb_range(mm, mm_cpumask(mm), 0, FLUSH_TLB_MAX_SIZE, PAGE_SIZE);
+ }
+
+ void flush_tlb_mm_range(struct mm_struct *mm,
+ unsigned long start, unsigned long end,
+ unsigned int page_size)
+ {
+- __flush_tlb_range(mm_cpumask(mm), get_mm_asid(mm),
+- start, end - start, page_size);
++ __flush_tlb_range(mm, mm_cpumask(mm), start, end - start, page_size);
+ }
+
+ void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
+ {
+- __flush_tlb_range(mm_cpumask(vma->vm_mm), get_mm_asid(vma->vm_mm),
++ __flush_tlb_range(vma->vm_mm, mm_cpumask(vma->vm_mm),
+ addr, PAGE_SIZE, PAGE_SIZE);
+ }
+
+@@ -161,13 +165,13 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
+ }
+ }
+
+- __flush_tlb_range(mm_cpumask(vma->vm_mm), get_mm_asid(vma->vm_mm),
++ __flush_tlb_range(vma->vm_mm, mm_cpumask(vma->vm_mm),
+ start, end - start, stride_size);
+ }
+
+ void flush_tlb_kernel_range(unsigned long start, unsigned long end)
+ {
+- __flush_tlb_range(cpu_online_mask, FLUSH_TLB_NO_ASID,
++ __flush_tlb_range(NULL, cpu_online_mask,
+ start, end - start, PAGE_SIZE);
+ }
+
+@@ -175,7 +179,7 @@ void flush_tlb_kernel_range(unsigned long start, unsigned long end)
+ void flush_pmd_tlb_range(struct vm_area_struct *vma, unsigned long start,
+ unsigned long end)
+ {
+- __flush_tlb_range(mm_cpumask(vma->vm_mm), get_mm_asid(vma->vm_mm),
++ __flush_tlb_range(vma->vm_mm, mm_cpumask(vma->vm_mm),
+ start, end - start, PMD_SIZE);
+ }
+ #endif
+@@ -189,7 +193,10 @@ void arch_tlbbatch_add_pending(struct arch_tlbflush_unmap_batch *batch,
+ struct mm_struct *mm,
+ unsigned long uaddr)
+ {
++ unsigned long start = uaddr & PAGE_MASK;
++
+ cpumask_or(&batch->cpumask, &batch->cpumask, mm_cpumask(mm));
++ mmu_notifier_arch_invalidate_secondary_tlbs(mm, start, start + PAGE_SIZE);
+ }
+
+ void arch_flush_tlb_batched_pending(struct mm_struct *mm)
+@@ -199,7 +206,7 @@ void arch_flush_tlb_batched_pending(struct mm_struct *mm)
+
+ void arch_tlbbatch_flush(struct arch_tlbflush_unmap_batch *batch)
+ {
+- __flush_tlb_range(&batch->cpumask, FLUSH_TLB_NO_ASID, 0,
+- FLUSH_TLB_MAX_SIZE, PAGE_SIZE);
++ __flush_tlb_range(NULL, &batch->cpumask,
++ 0, FLUSH_TLB_MAX_SIZE, PAGE_SIZE);
+ cpumask_clear(&batch->cpumask);
+ }
+--
+2.39.5
+
--- /dev/null
+From 51d343033e69cdff34b7480312c2954d1f23ee99 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Mar 2025 16:12:21 -0500
+Subject: rseq: Fix segfault on registration when rseq_cs is non-zero
+
+From: Michael Jeanson <mjeanson@efficios.com>
+
+[ Upstream commit fd881d0a085fc54354414aed990ccf05f282ba53 ]
+
+The rseq_cs field is documented as being set to 0 by user-space prior to
+registration, however this is not currently enforced by the kernel. This
+can result in a segfault on return to user-space if the value stored in
+the rseq_cs field doesn't point to a valid struct rseq_cs.
+
+The correct solution to this would be to fail the rseq registration when
+the rseq_cs field is non-zero. However, some older versions of glibc
+will reuse the rseq area of previous threads without clearing the
+rseq_cs field and will also terminate the process if the rseq
+registration fails in a secondary thread. This wasn't caught in testing
+because in this case the leftover rseq_cs does point to a valid struct
+rseq_cs.
+
+What we can do is clear the rseq_cs field on registration when it's
+non-zero which will prevent segfaults on registration and won't break
+the glibc versions that reuse rseq areas on thread creation.
+
+Signed-off-by: Michael Jeanson <mjeanson@efficios.com>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Reviewed-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Link: https://lore.kernel.org/r/20250306211223.109455-1-mjeanson@efficios.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/rseq.c | 60 ++++++++++++++++++++++++++++++++++++++++-----------
+ 1 file changed, 48 insertions(+), 12 deletions(-)
+
+diff --git a/kernel/rseq.c b/kernel/rseq.c
+index a7d81229eda04..b7a1ec327e811 100644
+--- a/kernel/rseq.c
++++ b/kernel/rseq.c
+@@ -236,6 +236,29 @@ static int rseq_reset_rseq_cpu_node_id(struct task_struct *t)
+ return -EFAULT;
+ }
+
++/*
++ * Get the user-space pointer value stored in the 'rseq_cs' field.
++ */
++static int rseq_get_rseq_cs_ptr_val(struct rseq __user *rseq, u64 *rseq_cs)
++{
++ if (!rseq_cs)
++ return -EFAULT;
++
++#ifdef CONFIG_64BIT
++ if (get_user(*rseq_cs, &rseq->rseq_cs))
++ return -EFAULT;
++#else
++ if (copy_from_user(rseq_cs, &rseq->rseq_cs, sizeof(*rseq_cs)))
++ return -EFAULT;
++#endif
++
++ return 0;
++}
++
++/*
++ * If the rseq_cs field of 'struct rseq' contains a valid pointer to
++ * user-space, copy 'struct rseq_cs' from user-space and validate its fields.
++ */
+ static int rseq_get_rseq_cs(struct task_struct *t, struct rseq_cs *rseq_cs)
+ {
+ struct rseq_cs __user *urseq_cs;
+@@ -244,17 +267,16 @@ static int rseq_get_rseq_cs(struct task_struct *t, struct rseq_cs *rseq_cs)
+ u32 sig;
+ int ret;
+
+-#ifdef CONFIG_64BIT
+- if (get_user(ptr, &t->rseq->rseq_cs))
+- return -EFAULT;
+-#else
+- if (copy_from_user(&ptr, &t->rseq->rseq_cs, sizeof(ptr)))
+- return -EFAULT;
+-#endif
++ ret = rseq_get_rseq_cs_ptr_val(t->rseq, &ptr);
++ if (ret)
++ return ret;
++
++ /* If the rseq_cs pointer is NULL, return a cleared struct rseq_cs. */
+ if (!ptr) {
+ memset(rseq_cs, 0, sizeof(*rseq_cs));
+ return 0;
+ }
++ /* Check that the pointer value fits in the user-space process space. */
+ if (ptr >= TASK_SIZE)
+ return -EINVAL;
+ urseq_cs = (struct rseq_cs __user *)(unsigned long)ptr;
+@@ -330,7 +352,7 @@ static int rseq_need_restart(struct task_struct *t, u32 cs_flags)
+ return !!event_mask;
+ }
+
+-static int clear_rseq_cs(struct task_struct *t)
++static int clear_rseq_cs(struct rseq __user *rseq)
+ {
+ /*
+ * The rseq_cs field is set to NULL on preemption or signal
+@@ -341,9 +363,9 @@ static int clear_rseq_cs(struct task_struct *t)
+ * Set rseq_cs to NULL.
+ */
+ #ifdef CONFIG_64BIT
+- return put_user(0UL, &t->rseq->rseq_cs);
++ return put_user(0UL, &rseq->rseq_cs);
+ #else
+- if (clear_user(&t->rseq->rseq_cs, sizeof(t->rseq->rseq_cs)))
++ if (clear_user(&rseq->rseq_cs, sizeof(rseq->rseq_cs)))
+ return -EFAULT;
+ return 0;
+ #endif
+@@ -375,11 +397,11 @@ static int rseq_ip_fixup(struct pt_regs *regs)
+ * Clear the rseq_cs pointer and return.
+ */
+ if (!in_rseq_cs(ip, &rseq_cs))
+- return clear_rseq_cs(t);
++ return clear_rseq_cs(t->rseq);
+ ret = rseq_need_restart(t, rseq_cs.flags);
+ if (ret <= 0)
+ return ret;
+- ret = clear_rseq_cs(t);
++ ret = clear_rseq_cs(t->rseq);
+ if (ret)
+ return ret;
+ trace_rseq_ip_fixup(ip, rseq_cs.start_ip, rseq_cs.post_commit_offset,
+@@ -453,6 +475,7 @@ SYSCALL_DEFINE4(rseq, struct rseq __user *, rseq, u32, rseq_len,
+ int, flags, u32, sig)
+ {
+ int ret;
++ u64 rseq_cs;
+
+ if (flags & RSEQ_FLAG_UNREGISTER) {
+ if (flags & ~RSEQ_FLAG_UNREGISTER)
+@@ -507,6 +530,19 @@ SYSCALL_DEFINE4(rseq, struct rseq __user *, rseq, u32, rseq_len,
+ return -EINVAL;
+ if (!access_ok(rseq, rseq_len))
+ return -EFAULT;
++
++ /*
++ * If the rseq_cs pointer is non-NULL on registration, clear it to
++ * avoid a potential segfault on return to user-space. The proper thing
++ * to do would have been to fail the registration but this would break
++ * older libcs that reuse the rseq area for new threads without
++ * clearing the fields.
++ */
++ if (rseq_get_rseq_cs_ptr_val(rseq, &rseq_cs))
++ return -EFAULT;
++ if (rseq_cs && clear_rseq_cs(rseq))
++ return -EFAULT;
++
+ #ifdef CONFIG_DEBUG_RSEQ
+ /*
+ * Initialize the in-kernel rseq fields copy for validation of
+--
+2.39.5
+
--- /dev/null
+From 4920866c0e2669b07cac195255ce76a224c7c105 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Mar 2025 23:37:44 +0100
+Subject: rtc: ds1307: stop disabling alarms on probe
+
+From: Alexandre Belloni <alexandre.belloni@bootlin.com>
+
+[ Upstream commit dcec12617ee61beed928e889607bf37e145bf86b ]
+
+It is a bad practice to disable alarms on probe or remove as this will
+prevent alarms across reboots.
+
+Link: https://lore.kernel.org/r/20250303223744.1135672-1-alexandre.belloni@bootlin.com
+Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/rtc/rtc-ds1307.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
+index 872e0b679be48..5efbe69bf5ca8 100644
+--- a/drivers/rtc/rtc-ds1307.c
++++ b/drivers/rtc/rtc-ds1307.c
+@@ -1807,10 +1807,8 @@ static int ds1307_probe(struct i2c_client *client)
+ * For some variants, be sure alarms can trigger when we're
+ * running on Vbackup (BBSQI/BBSQW)
+ */
+- if (want_irq || ds1307_can_wakeup_device) {
++ if (want_irq || ds1307_can_wakeup_device)
+ regs[0] |= DS1337_BIT_INTCN | chip->bbsqi_bit;
+- regs[0] &= ~(DS1337_BIT_A2IE | DS1337_BIT_A1IE);
+- }
+
+ regmap_write(ds1307->regmap, DS1337_REG_CONTROL,
+ regs[0]);
+--
+2.39.5
+
--- /dev/null
+From 3608956bb2054f168710482e04601310f4d90da6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Mar 2025 22:42:41 +0100
+Subject: rtc: rv3032: fix EERD location
+
+From: Alexandre Belloni <alexandre.belloni@bootlin.com>
+
+[ Upstream commit b0f9cb4a0706b0356e84d67e48500b77b343debe ]
+
+EERD is bit 2 in CTRL1
+
+Link: https://lore.kernel.org/r/20250306214243.1167692-1-alexandre.belloni@bootlin.com
+Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/rtc/rtc-rv3032.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/rtc/rtc-rv3032.c b/drivers/rtc/rtc-rv3032.c
+index 35b2e36b426a0..cb01038a2e27f 100644
+--- a/drivers/rtc/rtc-rv3032.c
++++ b/drivers/rtc/rtc-rv3032.c
+@@ -69,7 +69,7 @@
+ #define RV3032_CLKOUT2_FD_MSK GENMASK(6, 5)
+ #define RV3032_CLKOUT2_OS BIT(7)
+
+-#define RV3032_CTRL1_EERD BIT(3)
++#define RV3032_CTRL1_EERD BIT(2)
+ #define RV3032_CTRL1_WADA BIT(5)
+
+ #define RV3032_CTRL2_STOP BIT(0)
+--
+2.39.5
+
--- /dev/null
+From 529fbec7212ca6e2c639189fb16dabea4440f42a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 19 Feb 2025 20:50:27 +0800
+Subject: rtnetlink: Lookup device in target netns when creating link
+
+From: Xiao Liang <shaw.leon@gmail.com>
+
+[ Upstream commit ec061546c6cffbb8929495bba3953f0cc5e177fa ]
+
+When creating link, lookup for existing device in target net namespace
+instead of current one.
+For example, two links created by:
+
+ # ip link add dummy1 type dummy
+ # ip link add netns ns1 dummy1 type dummy
+
+should have no conflict since they are in different namespaces.
+
+Signed-off-by: Xiao Liang <shaw.leon@gmail.com>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Link: https://patch.msgid.link/20250219125039.18024-2-shaw.leon@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/core/rtnetlink.c | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
+index 80e006940f51a..ab7041150f295 100644
+--- a/net/core/rtnetlink.c
++++ b/net/core/rtnetlink.c
+@@ -3865,20 +3865,26 @@ static int __rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
+ {
+ struct nlattr ** const tb = tbs->tb;
+ struct net *net = sock_net(skb->sk);
++ struct net *device_net;
+ struct net_device *dev;
+ struct ifinfomsg *ifm;
+ bool link_specified;
+
++ /* When creating, lookup for existing device in target net namespace */
++ device_net = (nlh->nlmsg_flags & NLM_F_CREATE) &&
++ (nlh->nlmsg_flags & NLM_F_EXCL) ?
++ tgt_net : net;
++
+ ifm = nlmsg_data(nlh);
+ if (ifm->ifi_index > 0) {
+ link_specified = true;
+- dev = __dev_get_by_index(net, ifm->ifi_index);
++ dev = __dev_get_by_index(device_net, ifm->ifi_index);
+ } else if (ifm->ifi_index < 0) {
+ NL_SET_ERR_MSG(extack, "ifindex can't be negative");
+ return -EINVAL;
+ } else if (tb[IFLA_IFNAME] || tb[IFLA_ALT_IFNAME]) {
+ link_specified = true;
+- dev = rtnl_dev_get(net, tb);
++ dev = rtnl_dev_get(device_net, tb);
+ } else {
+ link_specified = false;
+ dev = NULL;
+--
+2.39.5
+
--- /dev/null
+From 9a37f90cdd12a3ba078d2becf1555cc16205f694 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Feb 2025 14:35:06 -0500
+Subject: rust/faux: Add missing parent argument to Registration::new()
+
+From: Lyude Paul <lyude@redhat.com>
+
+[ Upstream commit 95cb0cb546c2892b7a31ff2fce6573f201a214b8 ]
+
+A little late in the review of the faux device interface, we added the
+ability to specify a parent device when creating new faux devices - but
+this never got ported over to the rust bindings. So, let's add the missing
+argument now so we don't have to convert other users later down the line.
+
+Signed-off-by: Lyude Paul <lyude@redhat.com>
+Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Link: https://lore.kernel.org/r/20250227193522.198344-1-lyude@redhat.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ rust/kernel/faux.rs | 13 +++++++++++--
+ samples/rust/rust_driver_faux.rs | 2 +-
+ 2 files changed, 12 insertions(+), 3 deletions(-)
+
+diff --git a/rust/kernel/faux.rs b/rust/kernel/faux.rs
+index 5acc0c02d451f..68f53edf05d70 100644
+--- a/rust/kernel/faux.rs
++++ b/rust/kernel/faux.rs
+@@ -24,11 +24,20 @@
+
+ impl Registration {
+ /// Create and register a new faux device with the given name.
+- pub fn new(name: &CStr) -> Result<Self> {
++ pub fn new(name: &CStr, parent: Option<&device::Device>) -> Result<Self> {
+ // SAFETY:
+ // - `name` is copied by this function into its own storage
+ // - `faux_ops` is safe to leave NULL according to the C API
+- let dev = unsafe { bindings::faux_device_create(name.as_char_ptr(), null_mut(), null()) };
++ // - `parent` can be either NULL or a pointer to a `struct device`, and `faux_device_create`
++ // will take a reference to `parent` using `device_add` - ensuring that it remains valid
++ // for the lifetime of the faux device.
++ let dev = unsafe {
++ bindings::faux_device_create(
++ name.as_char_ptr(),
++ parent.map_or(null_mut(), |p| p.as_raw()),
++ null(),
++ )
++ };
+
+ // The above function will return either a valid device, or NULL on failure
+ // INVARIANT: The device will remain registered until faux_device_destroy() is called, which
+diff --git a/samples/rust/rust_driver_faux.rs b/samples/rust/rust_driver_faux.rs
+index 048c6cb98b29a..58a3a94121bff 100644
+--- a/samples/rust/rust_driver_faux.rs
++++ b/samples/rust/rust_driver_faux.rs
+@@ -20,7 +20,7 @@ impl Module for SampleModule {
+ fn init(_module: &'static ThisModule) -> Result<Self> {
+ pr_info!("Initialising Rust Faux Device Sample\n");
+
+- let reg = faux::Registration::new(c_str!("rust-faux-sample-device"))?;
++ let reg = faux::Registration::new(c_str!("rust-faux-sample-device"), None)?;
+
+ dev_info!(reg.as_ref(), "Hello from faux device!\n");
+
+--
+2.39.5
+
--- /dev/null
+From 76eb1508bbf45ef15ff2ffdce7a82c1f0ccb1621 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 15 Jan 2025 14:48:02 +0900
+Subject: s390/crash: Use note name macros
+
+From: Akihiko Odaki <akihiko.odaki@daynix.com>
+
+[ Upstream commit d4a760fb77fdac07efa3da4fa4a18f49f178d048 ]
+
+Use note name macros to match with the userspace's expectation.
+
+Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
+Acked-by: Heiko Carstens <hca@linux.ibm.com>
+Reviewed-by: Dave Martin <Dave.Martin@arm.com>
+Link: https://lore.kernel.org/r/20250115-elf-v5-5-0f9e55bbb2fc@daynix.com
+Signed-off-by: Kees Cook <kees@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/s390/kernel/crash_dump.c | 62 +++++++++++++----------------------
+ 1 file changed, 23 insertions(+), 39 deletions(-)
+
+diff --git a/arch/s390/kernel/crash_dump.c b/arch/s390/kernel/crash_dump.c
+index 276cb4c1e11be..4a981266b4833 100644
+--- a/arch/s390/kernel/crash_dump.c
++++ b/arch/s390/kernel/crash_dump.c
+@@ -246,15 +246,6 @@ bool is_kdump_kernel(void)
+ }
+ EXPORT_SYMBOL_GPL(is_kdump_kernel);
+
+-static const char *nt_name(Elf64_Word type)
+-{
+- const char *name = "LINUX";
+-
+- if (type == NT_PRPSINFO || type == NT_PRSTATUS || type == NT_PRFPREG)
+- name = KEXEC_CORE_NOTE_NAME;
+- return name;
+-}
+-
+ /*
+ * Initialize ELF note
+ */
+@@ -279,10 +270,8 @@ static void *nt_init_name(void *buf, Elf64_Word type, void *desc, int d_len,
+ return PTR_ADD(buf, len);
+ }
+
+-static inline void *nt_init(void *buf, Elf64_Word type, void *desc, int d_len)
+-{
+- return nt_init_name(buf, type, desc, d_len, nt_name(type));
+-}
++#define nt_init(buf, type, desc) \
++ nt_init_name(buf, NT_ ## type, &(desc), sizeof(desc), NN_ ## type)
+
+ /*
+ * Calculate the size of ELF note
+@@ -298,10 +287,7 @@ static size_t nt_size_name(int d_len, const char *name)
+ return size;
+ }
+
+-static inline size_t nt_size(Elf64_Word type, int d_len)
+-{
+- return nt_size_name(d_len, nt_name(type));
+-}
++#define nt_size(type, desc) nt_size_name(sizeof(desc), NN_ ## type)
+
+ /*
+ * Fill ELF notes for one CPU with save area registers
+@@ -322,18 +308,16 @@ static void *fill_cpu_elf_notes(void *ptr, int cpu, struct save_area *sa)
+ memcpy(&nt_fpregset.fpc, &sa->fpc, sizeof(sa->fpc));
+ memcpy(&nt_fpregset.fprs, &sa->fprs, sizeof(sa->fprs));
+ /* Create ELF notes for the CPU */
+- ptr = nt_init(ptr, NT_PRSTATUS, &nt_prstatus, sizeof(nt_prstatus));
+- ptr = nt_init(ptr, NT_PRFPREG, &nt_fpregset, sizeof(nt_fpregset));
+- ptr = nt_init(ptr, NT_S390_TIMER, &sa->timer, sizeof(sa->timer));
+- ptr = nt_init(ptr, NT_S390_TODCMP, &sa->todcmp, sizeof(sa->todcmp));
+- ptr = nt_init(ptr, NT_S390_TODPREG, &sa->todpreg, sizeof(sa->todpreg));
+- ptr = nt_init(ptr, NT_S390_CTRS, &sa->ctrs, sizeof(sa->ctrs));
+- ptr = nt_init(ptr, NT_S390_PREFIX, &sa->prefix, sizeof(sa->prefix));
++ ptr = nt_init(ptr, PRSTATUS, nt_prstatus);
++ ptr = nt_init(ptr, PRFPREG, nt_fpregset);
++ ptr = nt_init(ptr, S390_TIMER, sa->timer);
++ ptr = nt_init(ptr, S390_TODCMP, sa->todcmp);
++ ptr = nt_init(ptr, S390_TODPREG, sa->todpreg);
++ ptr = nt_init(ptr, S390_CTRS, sa->ctrs);
++ ptr = nt_init(ptr, S390_PREFIX, sa->prefix);
+ if (cpu_has_vx()) {
+- ptr = nt_init(ptr, NT_S390_VXRS_HIGH,
+- &sa->vxrs_high, sizeof(sa->vxrs_high));
+- ptr = nt_init(ptr, NT_S390_VXRS_LOW,
+- &sa->vxrs_low, sizeof(sa->vxrs_low));
++ ptr = nt_init(ptr, S390_VXRS_HIGH, sa->vxrs_high);
++ ptr = nt_init(ptr, S390_VXRS_LOW, sa->vxrs_low);
+ }
+ return ptr;
+ }
+@@ -346,16 +330,16 @@ static size_t get_cpu_elf_notes_size(void)
+ struct save_area *sa = NULL;
+ size_t size;
+
+- size = nt_size(NT_PRSTATUS, sizeof(struct elf_prstatus));
+- size += nt_size(NT_PRFPREG, sizeof(elf_fpregset_t));
+- size += nt_size(NT_S390_TIMER, sizeof(sa->timer));
+- size += nt_size(NT_S390_TODCMP, sizeof(sa->todcmp));
+- size += nt_size(NT_S390_TODPREG, sizeof(sa->todpreg));
+- size += nt_size(NT_S390_CTRS, sizeof(sa->ctrs));
+- size += nt_size(NT_S390_PREFIX, sizeof(sa->prefix));
++ size = nt_size(PRSTATUS, struct elf_prstatus);
++ size += nt_size(PRFPREG, elf_fpregset_t);
++ size += nt_size(S390_TIMER, sa->timer);
++ size += nt_size(S390_TODCMP, sa->todcmp);
++ size += nt_size(S390_TODPREG, sa->todpreg);
++ size += nt_size(S390_CTRS, sa->ctrs);
++ size += nt_size(S390_PREFIX, sa->prefix);
+ if (cpu_has_vx()) {
+- size += nt_size(NT_S390_VXRS_HIGH, sizeof(sa->vxrs_high));
+- size += nt_size(NT_S390_VXRS_LOW, sizeof(sa->vxrs_low));
++ size += nt_size(S390_VXRS_HIGH, sa->vxrs_high);
++ size += nt_size(S390_VXRS_LOW, sa->vxrs_low);
+ }
+
+ return size;
+@@ -371,7 +355,7 @@ static void *nt_prpsinfo(void *ptr)
+ memset(&prpsinfo, 0, sizeof(prpsinfo));
+ prpsinfo.pr_sname = 'R';
+ strcpy(prpsinfo.pr_fname, "vmlinux");
+- return nt_init(ptr, NT_PRPSINFO, &prpsinfo, sizeof(prpsinfo));
++ return nt_init(ptr, PRPSINFO, prpsinfo);
+ }
+
+ /*
+@@ -610,7 +594,7 @@ static size_t get_elfcorehdr_size(int phdr_count)
+ /* PT_NOTES */
+ size += sizeof(Elf64_Phdr);
+ /* nt_prpsinfo */
+- size += nt_size(NT_PRPSINFO, sizeof(struct elf_prpsinfo));
++ size += nt_size(PRPSINFO, struct elf_prpsinfo);
+ /* regsets */
+ size += get_cpu_cnt() * get_cpu_elf_notes_size();
+ /* nt_vmcoreinfo */
+--
+2.39.5
+
--- /dev/null
+From 6a1a4501ddab653b5244471ad692dfcaa653a77e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 10 Mar 2025 12:42:59 +0100
+Subject: s390/tlb: Use mm_has_pgste() instead of mm_alloc_pgste()
+
+From: Heiko Carstens <hca@linux.ibm.com>
+
+[ Upstream commit 9291ea091b29bb3e37c4b3416c7c1e49e472c7d5 ]
+
+An mm has pgstes only after s390_enable_sie() has been called, while
+mm_alloc_pgste() may be always true (e.g. via sysctl setting).
+
+Limit the calls to gmap_unlink() in pte_free_tlb() to those cases
+where there might be something to unlink.
+
+Reviewed-by: Alexander Gordeev <agordeev@linux.ibm.com>
+Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
+Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/s390/include/asm/tlb.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/arch/s390/include/asm/tlb.h b/arch/s390/include/asm/tlb.h
+index 72655fd2d867c..f20601995bb0e 100644
+--- a/arch/s390/include/asm/tlb.h
++++ b/arch/s390/include/asm/tlb.h
+@@ -84,7 +84,7 @@ static inline void pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
+ tlb->mm->context.flush_mm = 1;
+ tlb->freed_tables = 1;
+ tlb->cleared_pmds = 1;
+- if (mm_alloc_pgste(tlb->mm))
++ if (mm_has_pgste(tlb->mm))
+ gmap_unlink(tlb->mm, (unsigned long *)pte, address);
+ tlb_remove_ptdesc(tlb, virt_to_ptdesc(pte));
+ }
+--
+2.39.5
+
--- /dev/null
+From 216a6bda4ef0108cd928704691075d5c0dea6807 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Mar 2025 06:32:57 -0400
+Subject: s390/vfio-ap: Fix no AP queue sharing allowed message written to
+ kernel log
+
+From: Anthony Krowiak <akrowiak@linux.ibm.com>
+
+[ Upstream commit d33d729afcc8ad2148d99f9bc499b33fd0c0d73b ]
+
+An erroneous message is written to the kernel log when either of the
+following actions are taken by a user:
+
+1. Assign an adapter or domain to a vfio_ap mediated device via its sysfs
+ assign_adapter or assign_domain attributes that would result in one or
+ more AP queues being assigned that are already assigned to a different
+ mediated device. Sharing of queues between mdevs is not allowed.
+
+2. Reserve an adapter or domain for the host device driver via the AP bus
+ driver's sysfs apmask or aqmask attribute that would result in providing
+ host access to an AP queue that is in use by a vfio_ap mediated device.
+ Reserving a queue for a host driver that is in use by an mdev is not
+ allowed.
+
+In both cases, the assignment will return an error; however, a message like
+the following is written to the kernel log:
+
+vfio_ap_mdev e1839397-51a0-4e3c-91e0-c3b9c3d3047d: Userspace may not
+re-assign queue 00.0028 already assigned to \
+e1839397-51a0-4e3c-91e0-c3b9c3d3047d
+
+Notice the mdev reporting the error is the same as the mdev identified
+in the message as the one to which the queue is being assigned.
+It is perfectly okay to assign a queue to an mdev to which it is
+already assigned; the assignment is simply ignored by the vfio_ap device
+driver.
+
+This patch logs more descriptive and accurate messages for both 1 and 2
+above to the kernel log:
+
+Example for 1:
+vfio_ap_mdev 0fe903a0-a323-44db-9daf-134c68627d61: Userspace may not assign
+queue 00.0033 to mdev: already assigned to \
+62177883-f1bb-47f0-914d-32a22e3a8804
+
+Example for 2:
+vfio_ap_mdev 62177883-f1bb-47f0-914d-32a22e3a8804: Can not reserve queue
+00.0033 for host driver: in use by mdev
+
+Signed-off-by: Anthony Krowiak <akrowiak@linux.ibm.com>
+Link: https://lore.kernel.org/r/20250311103304.1539188-1-akrowiak@linux.ibm.com
+Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
+Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/s390/crypto/vfio_ap_ops.c | 72 ++++++++++++++++++++-----------
+ 1 file changed, 46 insertions(+), 26 deletions(-)
+
+diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c
+index a52c2690933fd..a6a0628979555 100644
+--- a/drivers/s390/crypto/vfio_ap_ops.c
++++ b/drivers/s390/crypto/vfio_ap_ops.c
+@@ -863,48 +863,66 @@ static void vfio_ap_mdev_remove(struct mdev_device *mdev)
+ vfio_put_device(&matrix_mdev->vdev);
+ }
+
+-#define MDEV_SHARING_ERR "Userspace may not re-assign queue %02lx.%04lx " \
+- "already assigned to %s"
++#define MDEV_SHARING_ERR "Userspace may not assign queue %02lx.%04lx to mdev: already assigned to %s"
+
+-static void vfio_ap_mdev_log_sharing_err(struct ap_matrix_mdev *matrix_mdev,
+- unsigned long *apm,
+- unsigned long *aqm)
++#define MDEV_IN_USE_ERR "Can not reserve queue %02lx.%04lx for host driver: in use by mdev"
++
++static void vfio_ap_mdev_log_sharing_err(struct ap_matrix_mdev *assignee,
++ struct ap_matrix_mdev *assigned_to,
++ unsigned long *apm, unsigned long *aqm)
+ {
+ unsigned long apid, apqi;
+- const struct device *dev = mdev_dev(matrix_mdev->mdev);
+- const char *mdev_name = dev_name(dev);
+
+- for_each_set_bit_inv(apid, apm, AP_DEVICES)
++ for_each_set_bit_inv(apid, apm, AP_DEVICES) {
++ for_each_set_bit_inv(apqi, aqm, AP_DOMAINS) {
++ dev_warn(mdev_dev(assignee->mdev), MDEV_SHARING_ERR,
++ apid, apqi, dev_name(mdev_dev(assigned_to->mdev)));
++ }
++ }
++}
++
++static void vfio_ap_mdev_log_in_use_err(struct ap_matrix_mdev *assignee,
++ unsigned long *apm, unsigned long *aqm)
++{
++ unsigned long apid, apqi;
++
++ for_each_set_bit_inv(apid, apm, AP_DEVICES) {
+ for_each_set_bit_inv(apqi, aqm, AP_DOMAINS)
+- dev_warn(dev, MDEV_SHARING_ERR, apid, apqi, mdev_name);
++ dev_warn(mdev_dev(assignee->mdev), MDEV_IN_USE_ERR, apid, apqi);
++ }
+ }
+
+ /**
+ * vfio_ap_mdev_verify_no_sharing - verify APQNs are not shared by matrix mdevs
+ *
++ * @assignee: the matrix mdev to which @mdev_apm and @mdev_aqm are being
++ * assigned; or, NULL if this function was called by the AP bus
++ * driver in_use callback to verify none of the APQNs being reserved
++ * for the host device driver are in use by a vfio_ap mediated device
+ * @mdev_apm: mask indicating the APIDs of the APQNs to be verified
+ * @mdev_aqm: mask indicating the APQIs of the APQNs to be verified
+ *
+- * Verifies that each APQN derived from the Cartesian product of a bitmap of
+- * AP adapter IDs and AP queue indexes is not configured for any matrix
+- * mediated device. AP queue sharing is not allowed.
++ * Verifies that each APQN derived from the Cartesian product of APIDs
++ * represented by the bits set in @mdev_apm and the APQIs of the bits set in
++ * @mdev_aqm is not assigned to a mediated device other than the mdev to which
++ * the APQN is being assigned (@assignee). AP queue sharing is not allowed.
+ *
+ * Return: 0 if the APQNs are not shared; otherwise return -EADDRINUSE.
+ */
+-static int vfio_ap_mdev_verify_no_sharing(unsigned long *mdev_apm,
++static int vfio_ap_mdev_verify_no_sharing(struct ap_matrix_mdev *assignee,
++ unsigned long *mdev_apm,
+ unsigned long *mdev_aqm)
+ {
+- struct ap_matrix_mdev *matrix_mdev;
++ struct ap_matrix_mdev *assigned_to;
+ DECLARE_BITMAP(apm, AP_DEVICES);
+ DECLARE_BITMAP(aqm, AP_DOMAINS);
+
+- list_for_each_entry(matrix_mdev, &matrix_dev->mdev_list, node) {
++ list_for_each_entry(assigned_to, &matrix_dev->mdev_list, node) {
+ /*
+- * If the input apm and aqm are fields of the matrix_mdev
+- * object, then move on to the next matrix_mdev.
++ * If the mdev to which the mdev_apm and mdev_aqm is being
++ * assigned is the same as the mdev being verified
+ */
+- if (mdev_apm == matrix_mdev->matrix.apm &&
+- mdev_aqm == matrix_mdev->matrix.aqm)
++ if (assignee == assigned_to)
+ continue;
+
+ memset(apm, 0, sizeof(apm));
+@@ -914,15 +932,16 @@ static int vfio_ap_mdev_verify_no_sharing(unsigned long *mdev_apm,
+ * We work on full longs, as we can only exclude the leftover
+ * bits in non-inverse order. The leftover is all zeros.
+ */
+- if (!bitmap_and(apm, mdev_apm, matrix_mdev->matrix.apm,
+- AP_DEVICES))
++ if (!bitmap_and(apm, mdev_apm, assigned_to->matrix.apm, AP_DEVICES))
+ continue;
+
+- if (!bitmap_and(aqm, mdev_aqm, matrix_mdev->matrix.aqm,
+- AP_DOMAINS))
++ if (!bitmap_and(aqm, mdev_aqm, assigned_to->matrix.aqm, AP_DOMAINS))
+ continue;
+
+- vfio_ap_mdev_log_sharing_err(matrix_mdev, apm, aqm);
++ if (assignee)
++ vfio_ap_mdev_log_sharing_err(assignee, assigned_to, apm, aqm);
++ else
++ vfio_ap_mdev_log_in_use_err(assigned_to, apm, aqm);
+
+ return -EADDRINUSE;
+ }
+@@ -951,7 +970,8 @@ static int vfio_ap_mdev_validate_masks(struct ap_matrix_mdev *matrix_mdev)
+ matrix_mdev->matrix.aqm))
+ return -EADDRNOTAVAIL;
+
+- return vfio_ap_mdev_verify_no_sharing(matrix_mdev->matrix.apm,
++ return vfio_ap_mdev_verify_no_sharing(matrix_mdev,
++ matrix_mdev->matrix.apm,
+ matrix_mdev->matrix.aqm);
+ }
+
+@@ -2458,7 +2478,7 @@ int vfio_ap_mdev_resource_in_use(unsigned long *apm, unsigned long *aqm)
+
+ mutex_lock(&matrix_dev->guests_lock);
+ mutex_lock(&matrix_dev->mdevs_lock);
+- ret = vfio_ap_mdev_verify_no_sharing(apm, aqm);
++ ret = vfio_ap_mdev_verify_no_sharing(NULL, apm, aqm);
+ mutex_unlock(&matrix_dev->mdevs_lock);
+ mutex_unlock(&matrix_dev->guests_lock);
+
+--
+2.39.5
+
--- /dev/null
+From 2491dbed04d3b86d6d1058feb5a9361798da4a99 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 25 Apr 2025 17:50:42 +0800
+Subject: samples/bpf: Fix compilation failure for samples/bpf on LoongArch
+ Fedora
+
+From: Haoran Jiang <jianghaoran@kylinos.cn>
+
+[ Upstream commit 548762f05d19c5542db7590bcdfb9be1fb928376 ]
+
+When building the latest samples/bpf on LoongArch Fedora
+
+ make M=samples/bpf
+
+There are compilation errors as follows:
+
+In file included from ./linux/samples/bpf/sockex2_kern.c:2:
+In file included from ./include/uapi/linux/in.h:25:
+In file included from ./include/linux/socket.h:8:
+In file included from ./include/linux/uio.h:9:
+In file included from ./include/linux/thread_info.h:60:
+In file included from ./arch/loongarch/include/asm/thread_info.h:15:
+In file included from ./arch/loongarch/include/asm/processor.h:13:
+In file included from ./arch/loongarch/include/asm/cpu-info.h:11:
+./arch/loongarch/include/asm/loongarch.h:13:10: fatal error: 'larchintrin.h' file not found
+ ^~~~~~~~~~~~~~~
+1 error generated.
+
+larchintrin.h is included in /usr/lib64/clang/14.0.6/include,
+and the header file location is specified at compile time.
+
+Test on LoongArch Fedora:
+https://github.com/fedora-remix-loongarch/releases-info
+
+Signed-off-by: Haoran Jiang <jianghaoran@kylinos.cn>
+Signed-off-by: zhangxi <zhangxi@kylinos.cn>
+Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
+Link: https://lore.kernel.org/bpf/20250425095042.838824-1-jianghaoran@kylinos.cn
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ samples/bpf/Makefile | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
+index 5b632635e00dd..95a4fa1f1e447 100644
+--- a/samples/bpf/Makefile
++++ b/samples/bpf/Makefile
+@@ -376,7 +376,7 @@ $(obj)/%.o: $(src)/%.c
+ @echo " CLANG-bpf " $@
+ $(Q)$(CLANG) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) $(BPF_EXTRA_CFLAGS) \
+ -I$(obj) -I$(srctree)/tools/testing/selftests/bpf/ \
+- -I$(LIBBPF_INCLUDE) \
++ -I$(LIBBPF_INCLUDE) $(CLANG_SYS_INCLUDES) \
+ -D__KERNEL__ -D__BPF_TRACING__ -Wno-unused-value -Wno-pointer-sign \
+ -D__TARGET_ARCH_$(SRCARCH) -Wno-compare-distinct-pointer-types \
+ -Wno-gnu-variable-sized-type-not-at-end \
+--
+2.39.5
+
--- /dev/null
+From 5ae1a1e66028187aab4714efafe78ab24acb2fcb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 8 Feb 2025 15:53:23 +0800
+Subject: sched: Reduce the default slice to avoid tasks getting an extra tick
+
+From: zihan zhou <15645113830zzh@gmail.com>
+
+[ Upstream commit 2ae891b826958b60919ea21c727f77bcd6ffcc2c ]
+
+The old default value for slice is 0.75 msec * (1 + ilog(ncpus)) which
+means that we have a default slice of:
+
+ 0.75 for 1 cpu
+ 1.50 up to 3 cpus
+ 2.25 up to 7 cpus
+ 3.00 for 8 cpus and above.
+
+For HZ=250 and HZ=100, because of the tick accuracy, the runtime of
+tasks is far higher than their slice.
+
+For HZ=1000 with 8 cpus or more, the accuracy of tick is already
+satisfactory, but there is still an issue that tasks will get an extra
+tick because the tick often arrives a little faster than expected. In
+this case, the task can only wait until the next tick to consider that it
+has reached its deadline, and will run 1ms longer.
+
+vruntime + sysctl_sched_base_slice = deadline
+ |-----------|-----------|-----------|-----------|
+ 1ms 1ms 1ms 1ms
+ ^ ^ ^ ^
+ tick1 tick2 tick3 tick4(nearly 4ms)
+
+There are two reasons for tick error: clockevent precision and the
+CONFIG_IRQ_TIME_ACCOUNTING/CONFIG_PARAVIRT_TIME_ACCOUNTING. with
+CONFIG_IRQ_TIME_ACCOUNTING every tick will be less than 1ms, but even
+without it, because of clockevent precision, tick still often less than
+1ms.
+
+In order to make scheduling more precise, we changed 0.75 to 0.70,
+Using 0.70 instead of 0.75 should not change much for other configs
+and would fix this issue:
+
+ 0.70 for 1 cpu
+ 1.40 up to 3 cpus
+ 2.10 up to 7 cpus
+ 2.8 for 8 cpus and above.
+
+This does not guarantee that tasks can run the slice time accurately
+every time, but occasionally running an extra tick has little impact.
+
+Signed-off-by: zihan zhou <15645113830zzh@gmail.com>
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Reviewed-by: Vincent Guittot <vincent.guittot@linaro.org>
+Link: https://lkml.kernel.org/r/20250208075322.13139-1-15645113830zzh@gmail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/sched/fair.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
+index 3d9b68a347b76..eb11650160f7e 100644
+--- a/kernel/sched/fair.c
++++ b/kernel/sched/fair.c
+@@ -74,10 +74,10 @@ unsigned int sysctl_sched_tunable_scaling = SCHED_TUNABLESCALING_LOG;
+ /*
+ * Minimal preemption granularity for CPU-bound tasks:
+ *
+- * (default: 0.75 msec * (1 + ilog(ncpus)), units: nanoseconds)
++ * (default: 0.70 msec * (1 + ilog(ncpus)), units: nanoseconds)
+ */
+-unsigned int sysctl_sched_base_slice = 750000ULL;
+-static unsigned int normalized_sysctl_sched_base_slice = 750000ULL;
++unsigned int sysctl_sched_base_slice = 700000ULL;
++static unsigned int normalized_sysctl_sched_base_slice = 700000ULL;
+
+ const_debug unsigned int sysctl_sched_migration_cost = 500000UL;
+
+--
+2.39.5
+
--- /dev/null
+From 6a10f607c820e875f42f27508980d00da533e5b2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 24 Feb 2025 10:58:19 +0100
+Subject: scsi: logging: Fix scsi_logging_level bounds
+
+From: Nicolas Bouchinet <nicolas.bouchinet@ssi.gouv.fr>
+
+[ Upstream commit 2cef5b4472c602e6c5a119aca869d9d4050586f3 ]
+
+Bound scsi_logging_level sysctl writings between SYSCTL_ZERO and
+SYSCTL_INT_MAX.
+
+The proc_handler has thus been updated to proc_dointvec_minmax.
+
+Signed-off-by: Nicolas Bouchinet <nicolas.bouchinet@ssi.gouv.fr>
+Link: https://lore.kernel.org/r/20250224095826.16458-5-nicolas.bouchinet@clip-os.org
+Reviewed-by: Joel Granados <joel.granados@kernel.org>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/scsi_sysctl.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/scsi/scsi_sysctl.c b/drivers/scsi/scsi_sysctl.c
+index be4aef0f4f996..055a03a83ad68 100644
+--- a/drivers/scsi/scsi_sysctl.c
++++ b/drivers/scsi/scsi_sysctl.c
+@@ -17,7 +17,9 @@ static const struct ctl_table scsi_table[] = {
+ .data = &scsi_logging_level,
+ .maxlen = sizeof(scsi_logging_level),
+ .mode = 0644,
+- .proc_handler = proc_dointvec },
++ .proc_handler = proc_dointvec_minmax,
++ .extra1 = SYSCTL_ZERO,
++ .extra2 = SYSCTL_INT_MAX },
+ };
+
+ static struct ctl_table_header *scsi_table_header;
+--
+2.39.5
+
--- /dev/null
+From 67f7fcd9a8b70dfc4fd496133ac03411b5a33776 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jan 2025 16:05:20 -0800
+Subject: scsi: lpfc: Free phba irq in lpfc_sli4_enable_msi() when
+ pci_irq_vector() fails
+
+From: Justin Tee <justin.tee@broadcom.com>
+
+[ Upstream commit f0842902b383982d1f72c490996aa8fc29a7aa0d ]
+
+Fix smatch warning regarding missed calls to free_irq(). Free the phba IRQ
+in the failed pci_irq_vector cases.
+
+lpfc_init.c: lpfc_sli4_enable_msi() warn: 'phba->pcidev->irq' from
+ request_irq() not released.
+
+Signed-off-by: Justin Tee <justin.tee@broadcom.com>
+Link: https://lore.kernel.org/r/20250131000524.163662-3-justintee8345@gmail.com
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/lpfc/lpfc_init.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
+index bcadf11414c8a..411a6b927c5b0 100644
+--- a/drivers/scsi/lpfc/lpfc_init.c
++++ b/drivers/scsi/lpfc/lpfc_init.c
+@@ -13170,6 +13170,7 @@ lpfc_sli4_enable_msi(struct lpfc_hba *phba)
+ eqhdl = lpfc_get_eq_hdl(0);
+ rc = pci_irq_vector(phba->pcidev, 0);
+ if (rc < 0) {
++ free_irq(phba->pcidev->irq, phba);
+ pci_free_irq_vectors(phba->pcidev);
+ lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+ "0496 MSI pci_irq_vec failed (%d)\n", rc);
+@@ -13250,6 +13251,7 @@ lpfc_sli4_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode)
+ eqhdl = lpfc_get_eq_hdl(0);
+ retval = pci_irq_vector(phba->pcidev, 0);
+ if (retval < 0) {
++ free_irq(phba->pcidev->irq, phba);
+ lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+ "0502 INTR pci_irq_vec failed (%d)\n",
+ retval);
+--
+2.39.5
+
--- /dev/null
+From 2bcd181d84cafa22b641905255f78dc209074903 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jan 2025 16:05:22 -0800
+Subject: scsi: lpfc: Handle duplicate D_IDs in ndlp search-by D_ID routine
+
+From: Justin Tee <justin.tee@broadcom.com>
+
+[ Upstream commit 56c3d809b7b450379162d0b8a70bbe71ab8db706 ]
+
+After a port swap between separate fabrics, there may be multiple nodes in
+the vport's fc_nodes list with the same fabric well known address.
+Duplication is temporary and eventually resolves itself after dev_loss_tmo
+expires, but nameserver queries may still occur before dev_loss_tmo. This
+possibly results in returning stale fabric ndlp objects. Fix by adding an
+nlp_state check to ensure the ndlp search routine returns the correct newer
+allocated ndlp fabric object.
+
+Signed-off-by: Justin Tee <justin.tee@broadcom.com>
+Link: https://lore.kernel.org/r/20250131000524.163662-5-justintee8345@gmail.com
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/lpfc/lpfc_hbadisc.c | 17 ++++++++++++-----
+ 1 file changed, 12 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
+index 36e66df36a18c..45d268d49060e 100644
+--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
++++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
+@@ -5564,6 +5564,7 @@ static struct lpfc_nodelist *
+ __lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did)
+ {
+ struct lpfc_nodelist *ndlp;
++ struct lpfc_nodelist *np = NULL;
+ uint32_t data1;
+
+ list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
+@@ -5578,14 +5579,20 @@ __lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did)
+ ndlp, ndlp->nlp_DID,
+ ndlp->nlp_flag, data1, ndlp->nlp_rpi,
+ ndlp->active_rrqs_xri_bitmap);
+- return ndlp;
++
++ /* Check for new or potentially stale node */
++ if (ndlp->nlp_state != NLP_STE_UNUSED_NODE)
++ return ndlp;
++ np = ndlp;
+ }
+ }
+
+- /* FIND node did <did> NOT FOUND */
+- lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
+- "0932 FIND node did x%x NOT FOUND.\n", did);
+- return NULL;
++ if (!np)
++ /* FIND node did <did> NOT FOUND */
++ lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
++ "0932 FIND node did x%x NOT FOUND.\n", did);
++
++ return np;
+ }
+
+ struct lpfc_nodelist *
+--
+2.39.5
+
--- /dev/null
+From 2549fb59f3fa1a96ae2c0538cf0c427ab6212e46 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jan 2025 16:05:21 -0800
+Subject: scsi: lpfc: Ignore ndlp rport mismatch in dev_loss_tmo callbk
+
+From: Justin Tee <justin.tee@broadcom.com>
+
+[ Upstream commit 23ed62897746f49f195d819ce6edeb1db27d1b72 ]
+
+With repeated port swaps between separate fabrics, there can be multiple
+registrations for fabric well known address 0xfffffe. This can cause ndlp
+reference confusion due to the usage of a single ndlp ptr that stores the
+rport object in fc_rport struct private storage during transport
+registration. Subsequent registrations update the ndlp->rport field with
+the newer rport, so when transport layer triggers dev_loss_tmo for the
+earlier registered rport the ndlp->rport private storage is referencing the
+newer rport instead of the older rport in dev_loss_tmo callbk.
+
+Because the older ndlp->rport object is already cleaned up elsewhere in
+driver code during the time of fabric swap, check that the rport provided
+in dev_loss_tmo callbk actually matches the rport stored in the LLDD's
+ndlp->rport field. Otherwise, skip dev_loss_tmo work on a stale rport.
+
+Signed-off-by: Justin Tee <justin.tee@broadcom.com>
+Link: https://lore.kernel.org/r/20250131000524.163662-4-justintee8345@gmail.com
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/lpfc/lpfc_hbadisc.c | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
+index 45d268d49060e..07cd611f34bd5 100644
+--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
++++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
+@@ -228,10 +228,16 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
+ if (ndlp->nlp_state == NLP_STE_MAPPED_NODE)
+ return;
+
+- /* check for recovered fabric node */
+- if (ndlp->nlp_state == NLP_STE_UNMAPPED_NODE &&
+- ndlp->nlp_DID == Fabric_DID)
++ /* Ignore callback for a mismatched (stale) rport */
++ if (ndlp->rport != rport) {
++ lpfc_vlog_msg(vport, KERN_WARNING, LOG_NODE,
++ "6788 fc rport mismatch: d_id x%06x ndlp x%px "
++ "fc rport x%px node rport x%px state x%x "
++ "refcnt %u\n",
++ ndlp->nlp_DID, ndlp, rport, ndlp->rport,
++ ndlp->nlp_state, kref_read(&ndlp->kref));
+ return;
++ }
+
+ if (rport->port_name != wwn_to_u64(ndlp->nlp_portname.u.wwn))
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
+--
+2.39.5
+
--- /dev/null
+From 2fbd2345b6beeb6341af27e44c9c16facb03665b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jan 2025 16:05:19 -0800
+Subject: scsi: lpfc: Reduce log message generation during ELS ring clean up
+
+From: Justin Tee <justin.tee@broadcom.com>
+
+[ Upstream commit 8eccc58d71eafbd2635077916b68fda15791d270 ]
+
+A clean up log message is output from lpfc_els_flush_cmd() for each
+outstanding ELS I/O and repeated for every NPIV instance. The log message
+should only be generated for active I/Os matching the NPIV vport. Thus,
+move the vport check to before logging the message.
+
+Signed-off-by: Justin Tee <justin.tee@broadcom.com>
+Link: https://lore.kernel.org/r/20250131000524.163662-2-justintee8345@gmail.com
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/lpfc/lpfc_els.c | 10 ++++------
+ 1 file changed, 4 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
+index 1d7db49a8fe45..318dc83e9a2ac 100644
+--- a/drivers/scsi/lpfc/lpfc_els.c
++++ b/drivers/scsi/lpfc/lpfc_els.c
+@@ -9569,18 +9569,16 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport)
+ mbx_tmo_err = test_bit(MBX_TMO_ERR, &phba->bit_flags);
+ /* First we need to issue aborts to outstanding cmds on txcmpl */
+ list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
++ if (piocb->vport != vport)
++ continue;
++
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "2243 iotag = 0x%x cmd_flag = 0x%x "
+- "ulp_command = 0x%x this_vport %x "
+- "sli_flag = 0x%x\n",
++ "ulp_command = 0x%x sli_flag = 0x%x\n",
+ piocb->iotag, piocb->cmd_flag,
+ get_job_cmnd(phba, piocb),
+- (piocb->vport == vport),
+ phba->sli.sli_flag);
+
+- if (piocb->vport != vport)
+- continue;
+-
+ if ((phba->sli.sli_flag & LPFC_SLI_ACTIVE) && !mbx_tmo_err) {
+ if (piocb->cmd_flag & LPFC_IO_LIBDFC)
+ continue;
+--
+2.39.5
+
--- /dev/null
+From 5ae8c0d6ebe01766916d09d55af7a2d32fd2a7a3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 15 Apr 2025 15:45:46 +0530
+Subject: scsi: mpi3mr: Add level check to control event logging
+
+From: Ranjan Kumar <ranjan.kumar@broadcom.com>
+
+[ Upstream commit b0b7ee3b574a72283399b9232f6190be07f220c0 ]
+
+Ensure event logs are only generated when the debug logging level
+MPI3_DEBUG_EVENT is enabled. This prevents unnecessary logging.
+
+Signed-off-by: Ranjan Kumar <ranjan.kumar@broadcom.com>
+Link: https://lore.kernel.org/r/20250415101546.204018-1-ranjan.kumar@broadcom.com
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/mpi3mr/mpi3mr_fw.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
+index c0a372868e1d7..f6d3db3fd0d8e 100644
+--- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
++++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
+@@ -174,6 +174,9 @@ static void mpi3mr_print_event_data(struct mpi3mr_ioc *mrioc,
+ char *desc = NULL;
+ u16 event;
+
++ if (!(mrioc->logging_level & MPI3_DEBUG_EVENT))
++ return;
++
+ event = event_reply->event;
+
+ switch (event) {
+--
+2.39.5
+
--- /dev/null
+From b8e2cf1cb565e0fbf937e451afe72f80cdb9bffd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 20 Feb 2025 19:55:26 +0530
+Subject: scsi: mpi3mr: Update timestamp only for supervisor IOCs
+
+From: Ranjan Kumar <ranjan.kumar@broadcom.com>
+
+[ Upstream commit 83a9d30d29f275571f6e8f879f04b2379be7eb6c ]
+
+The driver issues the time stamp update command periodically. Even if the
+command fails with supervisor only IOC Status.
+
+Instead check the Non-Supervisor capability bit reported by IOC as part of
+IOC Facts.
+
+Co-developed-by: Sumit Saxena <sumit.saxena@broadcom.com>
+Signed-off-by: Sumit Saxena <sumit.saxena@broadcom.com>
+Signed-off-by: Ranjan Kumar <ranjan.kumar@broadcom.com>
+Link: https://lore.kernel.org/r/20250220142528.20837-3-ranjan.kumar@broadcom.com
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/mpi3mr/mpi3mr_fw.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
+index f6d3db3fd0d8e..604f37e5c0c35 100644
+--- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
++++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
+@@ -2747,7 +2747,10 @@ static void mpi3mr_watchdog_work(struct work_struct *work)
+ return;
+ }
+
+- if (mrioc->ts_update_counter++ >= mrioc->ts_update_interval) {
++ if (!(mrioc->facts.ioc_capabilities &
++ MPI3_IOCFACTS_CAPABILITY_NON_SUPERVISOR_IOC) &&
++ (mrioc->ts_update_counter++ >= mrioc->ts_update_interval)) {
++
+ mrioc->ts_update_counter = 0;
+ mpi3mr_sync_timestamp(mrioc);
+ }
+--
+2.39.5
+
--- /dev/null
+From c89f00af24aebf4184eebc1d71310dead3ad35cc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 12 Feb 2025 17:26:55 -0800
+Subject: scsi: mpt3sas: Send a diag reset if target reset fails
+
+From: Shivasharan S <shivasharan.srikanteshwara@broadcom.com>
+
+[ Upstream commit 5612d6d51ed2634a033c95de2edec7449409cbb9 ]
+
+When an IOCTL times out and driver issues a target reset, if firmware
+fails the task management elevate the recovery by issuing a diag reset to
+controller.
+
+Signed-off-by: Shivasharan S <shivasharan.srikanteshwara@broadcom.com>
+Link: https://lore.kernel.org/r/1739410016-27503-5-git-send-email-shivasharan.srikanteshwara@broadcom.com
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/mpt3sas/mpt3sas_ctl.c | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c
+index 87784c96249a7..47faa27bc3559 100644
+--- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c
++++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c
+@@ -679,6 +679,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
+ size_t data_in_sz = 0;
+ long ret;
+ u16 device_handle = MPT3SAS_INVALID_DEVICE_HANDLE;
++ int tm_ret;
+
+ issue_reset = 0;
+
+@@ -1120,18 +1121,25 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
+ if (pcie_device && (!ioc->tm_custom_handling) &&
+ (!(mpt3sas_scsih_is_pcie_scsi_device(
+ pcie_device->device_info))))
+- mpt3sas_scsih_issue_locked_tm(ioc,
++ tm_ret = mpt3sas_scsih_issue_locked_tm(ioc,
+ le16_to_cpu(mpi_request->FunctionDependent1),
+ 0, 0, 0,
+ MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0,
+ 0, pcie_device->reset_timeout,
+ MPI26_SCSITASKMGMT_MSGFLAGS_PROTOCOL_LVL_RST_PCIE);
+ else
+- mpt3sas_scsih_issue_locked_tm(ioc,
++ tm_ret = mpt3sas_scsih_issue_locked_tm(ioc,
+ le16_to_cpu(mpi_request->FunctionDependent1),
+ 0, 0, 0,
+ MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0,
+ 0, 30, MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET);
++
++ if (tm_ret != SUCCESS) {
++ ioc_info(ioc,
++ "target reset failed, issue hard reset: handle (0x%04x)\n",
++ le16_to_cpu(mpi_request->FunctionDependent1));
++ mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
++ }
+ } else
+ mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
+ }
+--
+2.39.5
+
--- /dev/null
+From 792bfc8af9675067316f5d4e6562c1774e577f0f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 13 Feb 2025 11:26:30 +0200
+Subject: scsi: scsi_debug: First fixes for tapes
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Kai Mäkisara <Kai.Makisara@kolumbus.fi>
+
+[ Upstream commit f69da85d5d5cc5b7dfb963a6c6c1ac0dd9002341 ]
+
+Patch includes the following:
+
+ - Enable MODE SENSE/SELECT without actual page (to read/write only the
+ Block Descriptor)
+
+ - Store the density code and block size in the Block Descriptor (only
+ short version for tapes)
+
+ - Fix REWIND not to use the wrong page filling function
+
+Signed-off-by: Kai Mäkisara <Kai.Makisara@kolumbus.fi>
+Link: https://lore.kernel.org/r/20250213092636.2510-2-Kai.Makisara@kolumbus.fi
+Reviewed-by: John Meneghini <jmeneghi@redhat.com>
+Tested-by: John Meneghini <jmeneghi@redhat.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/scsi_debug.c | 55 ++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 49 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
+index 5ceaa4665e5df..4da0c259390b5 100644
+--- a/drivers/scsi/scsi_debug.c
++++ b/drivers/scsi/scsi_debug.c
+@@ -173,6 +173,10 @@ static const char *sdebug_version_date = "20210520";
+ #define DEF_ZBC_MAX_OPEN_ZONES 8
+ #define DEF_ZBC_NR_CONV_ZONES 1
+
++/* Default parameters for tape drives */
++#define TAPE_DEF_DENSITY 0x0
++#define TAPE_DEF_BLKSIZE 0
++
+ #define SDEBUG_LUN_0_VAL 0
+
+ /* bit mask values for sdebug_opts */
+@@ -363,6 +367,10 @@ struct sdebug_dev_info {
+ ktime_t create_ts; /* time since bootup that this device was created */
+ struct sdeb_zone_state *zstate;
+
++ /* For tapes */
++ unsigned int tape_blksize;
++ unsigned int tape_density;
++
+ struct dentry *debugfs_entry;
+ struct spinlock list_lock;
+ struct list_head inject_err_list;
+@@ -773,7 +781,7 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = {
+ /* 20 */
+ {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
+ {6, 0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+- {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
++ {0, 0x1, 0, 0, NULL, NULL, /* REWIND ?? */
+ {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+@@ -2742,7 +2750,7 @@ static int resp_mode_sense(struct scsi_cmnd *scp,
+ unsigned char *ap;
+ unsigned char *arr __free(kfree);
+ unsigned char *cmd = scp->cmnd;
+- bool dbd, llbaa, msense_6, is_disk, is_zbc;
++ bool dbd, llbaa, msense_6, is_disk, is_zbc, is_tape;
+
+ arr = kzalloc(SDEBUG_MAX_MSENSE_SZ, GFP_ATOMIC);
+ if (!arr)
+@@ -2755,7 +2763,8 @@ static int resp_mode_sense(struct scsi_cmnd *scp,
+ llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
+ is_disk = (sdebug_ptype == TYPE_DISK);
+ is_zbc = devip->zoned;
+- if ((is_disk || is_zbc) && !dbd)
++ is_tape = (sdebug_ptype == TYPE_TAPE);
++ if ((is_disk || is_zbc || is_tape) && !dbd)
+ bd_len = llbaa ? 16 : 8;
+ else
+ bd_len = 0;
+@@ -2793,15 +2802,25 @@ static int resp_mode_sense(struct scsi_cmnd *scp,
+ put_unaligned_be32(0xffffffff, ap + 0);
+ else
+ put_unaligned_be32(sdebug_capacity, ap + 0);
+- put_unaligned_be16(sdebug_sector_size, ap + 6);
++ if (is_tape) {
++ ap[0] = devip->tape_density;
++ put_unaligned_be16(devip->tape_blksize, ap + 6);
++ } else
++ put_unaligned_be16(sdebug_sector_size, ap + 6);
+ offset += bd_len;
+ ap = arr + offset;
+ } else if (16 == bd_len) {
++ if (is_tape) {
++ mk_sense_invalid_fld(scp, SDEB_IN_DATA, 1, 4);
++ return check_condition_result;
++ }
+ put_unaligned_be64((u64)sdebug_capacity, ap + 0);
+ put_unaligned_be32(sdebug_sector_size, ap + 12);
+ offset += bd_len;
+ ap = arr + offset;
+ }
++ if (cmd[2] == 0)
++ goto only_bd; /* Only block descriptor requested */
+
+ /*
+ * N.B. If len>0 before resp_*_pg() call, then form of that call should be:
+@@ -2902,6 +2921,7 @@ static int resp_mode_sense(struct scsi_cmnd *scp,
+ default:
+ goto bad_pcode;
+ }
++only_bd:
+ if (msense_6)
+ arr[0] = offset - 1;
+ else
+@@ -2945,8 +2965,27 @@ static int resp_mode_select(struct scsi_cmnd *scp,
+ __func__, param_len, res);
+ md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
+ bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
+- off = bd_len + (mselect6 ? 4 : 8);
+- if (md_len > 2 || off >= res) {
++ off = (mselect6 ? 4 : 8);
++ if (sdebug_ptype == TYPE_TAPE) {
++ int blksize;
++
++ if (bd_len != 8) {
++ mk_sense_invalid_fld(scp, SDEB_IN_DATA,
++ mselect6 ? 3 : 6, -1);
++ return check_condition_result;
++ }
++ blksize = get_unaligned_be16(arr + off + 6);
++ if ((blksize % 4) != 0) {
++ mk_sense_invalid_fld(scp, SDEB_IN_DATA, off + 6, -1);
++ return check_condition_result;
++ }
++ devip->tape_density = arr[off];
++ devip->tape_blksize = blksize;
++ }
++ off += bd_len;
++ if (off >= res)
++ return 0; /* No page written, just descriptors */
++ if (md_len > 2) {
+ mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
+ return check_condition_result;
+ }
+@@ -5835,6 +5874,10 @@ static struct sdebug_dev_info *sdebug_device_create(
+ } else {
+ devip->zoned = false;
+ }
++ if (sdebug_ptype == TYPE_TAPE) {
++ devip->tape_density = TAPE_DEF_DENSITY;
++ devip->tape_blksize = TAPE_DEF_BLKSIZE;
++ }
+ devip->create_ts = ktime_get_boottime();
+ atomic_set(&devip->stopped, (sdeb_tur_ms_to_ready > 0 ? 2 : 0));
+ spin_lock_init(&devip->list_lock);
+--
+2.39.5
+
--- /dev/null
+From 9e2bf56c01ffcf4aea4a9e620ee9b0e59625ff52 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Mar 2025 13:25:15 +0200
+Subject: scsi: st: ERASE does not change tape location
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Kai Mäkisara <Kai.Makisara@kolumbus.fi>
+
+[ Upstream commit ad77cebf97bd42c93ab4e3bffd09f2b905c1959a ]
+
+The SCSI ERASE command erases from the current position onwards. Don't
+clear the position variables.
+
+Signed-off-by: Kai Mäkisara <Kai.Makisara@kolumbus.fi>
+Link: https://lore.kernel.org/r/20250311112516.5548-3-Kai.Makisara@kolumbus.fi
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/st.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
+index 2a18ba51427ac..4add423f2f415 100644
+--- a/drivers/scsi/st.c
++++ b/drivers/scsi/st.c
+@@ -2897,7 +2897,6 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
+ timeout = STp->long_timeout * 8;
+
+ DEBC_printk(STp, "Erasing tape.\n");
+- fileno = blkno = at_sm = 0;
+ break;
+ case MTSETBLK: /* Set block length */
+ case MTSETDENSITY: /* Set tape density */
+--
+2.39.5
+
--- /dev/null
+From afa12d7a9be5c878ad8b1f5c381d1296977f0e20 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 20 Jan 2025 21:49:22 +0200
+Subject: scsi: st: Restore some drive settings after reset
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Kai Mäkisara <Kai.Makisara@kolumbus.fi>
+
+[ Upstream commit 7081dc75df79696d8322d01821c28e53416c932c ]
+
+Some of the allowed operations put the tape into a known position to
+continue operation assuming only the tape position has changed. But reset
+sets partition, density and block size to drive default values. These
+should be restored to the values before reset.
+
+Normally the current block size and density are stored by the drive. If
+the settings have been changed, the changed values have to be saved by the
+driver across reset.
+
+Signed-off-by: Kai Mäkisara <Kai.Makisara@kolumbus.fi>
+Link: https://lore.kernel.org/r/20250120194925.44432-2-Kai.Makisara@kolumbus.fi
+Reviewed-by: John Meneghini <jmeneghi@redhat.com>
+Tested-by: John Meneghini <jmeneghi@redhat.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/st.c | 24 +++++++++++++++++++++---
+ drivers/scsi/st.h | 2 ++
+ 2 files changed, 23 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
+index 4add423f2f415..7dec7958344ea 100644
+--- a/drivers/scsi/st.c
++++ b/drivers/scsi/st.c
+@@ -952,7 +952,6 @@ static void reset_state(struct scsi_tape *STp)
+ STp->partition = find_partition(STp);
+ if (STp->partition < 0)
+ STp->partition = 0;
+- STp->new_partition = STp->partition;
+ }
+ }
+ \f
+@@ -2929,14 +2928,17 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
+ if (cmd_in == MTSETDENSITY) {
+ (STp->buffer)->b_data[4] = arg;
+ STp->density_changed = 1; /* At least we tried ;-) */
++ STp->changed_density = arg;
+ } else if (cmd_in == SET_DENS_AND_BLK)
+ (STp->buffer)->b_data[4] = arg >> 24;
+ else
+ (STp->buffer)->b_data[4] = STp->density;
+ if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) {
+ ltmp = arg & MT_ST_BLKSIZE_MASK;
+- if (cmd_in == MTSETBLK)
++ if (cmd_in == MTSETBLK) {
+ STp->blksize_changed = 1; /* At least we tried ;-) */
++ STp->changed_blksize = arg;
++ }
+ } else
+ ltmp = STp->block_size;
+ (STp->buffer)->b_data[9] = (ltmp >> 16);
+@@ -3637,9 +3639,25 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
+ retval = (-EIO);
+ goto out;
+ }
+- reset_state(STp);
++ reset_state(STp); /* Clears pos_unknown */
+ /* remove this when the midlevel properly clears was_reset */
+ STp->device->was_reset = 0;
++
++ /* Fix the device settings after reset, ignore errors */
++ if (mtc.mt_op == MTREW || mtc.mt_op == MTSEEK ||
++ mtc.mt_op == MTEOM) {
++ if (STp->can_partitions) {
++ /* STp->new_partition contains the
++ * latest partition set
++ */
++ STp->partition = 0;
++ switch_partition(STp);
++ }
++ if (STp->density_changed)
++ st_int_ioctl(STp, MTSETDENSITY, STp->changed_density);
++ if (STp->blksize_changed)
++ st_int_ioctl(STp, MTSETBLK, STp->changed_blksize);
++ }
+ }
+
+ if (mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK &&
+diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h
+index 1aaaf5369a40f..6d31b894ee84c 100644
+--- a/drivers/scsi/st.h
++++ b/drivers/scsi/st.h
+@@ -165,6 +165,7 @@ struct scsi_tape {
+ unsigned char compression_changed;
+ unsigned char drv_buffer;
+ unsigned char density;
++ unsigned char changed_density;
+ unsigned char door_locked;
+ unsigned char autorew_dev; /* auto-rewind device */
+ unsigned char rew_at_close; /* rewind necessary at close */
+@@ -172,6 +173,7 @@ struct scsi_tape {
+ unsigned char cleaning_req; /* cleaning requested? */
+ unsigned char first_tur; /* first TEST UNIT READY */
+ int block_size;
++ int changed_blksize;
+ int min_block;
+ int max_block;
+ int recover_count; /* From tape opening */
+--
+2.39.5
+
--- /dev/null
+From f9cb5b2d9b2cc32d88e24f2fcf6e3c7a383bf2c1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Mar 2025 13:25:16 +0200
+Subject: scsi: st: Tighten the page format heuristics with MODE SELECT
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Kai Mäkisara <Kai.Makisara@kolumbus.fi>
+
+[ Upstream commit 8db816c6f176321e42254badd5c1a8df8bfcfdb4 ]
+
+In the days when SCSI-2 was emerging, some drives did claim SCSI-2 but did
+not correctly implement it. The st driver first tries MODE SELECT with the
+page format bit set to set the block descriptor. If not successful, the
+non-page format is tried.
+
+The test only tests the sense code and this triggers also from illegal
+parameter in the parameter list. The test is limited to "old" devices and
+made more strict to remove false alarms.
+
+Signed-off-by: Kai Mäkisara <Kai.Makisara@kolumbus.fi>
+Link: https://lore.kernel.org/r/20250311112516.5548-4-Kai.Makisara@kolumbus.fi
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/st.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
+index 344e4da336bb5..2a18ba51427ac 100644
+--- a/drivers/scsi/st.c
++++ b/drivers/scsi/st.c
+@@ -3084,7 +3084,9 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
+ cmd_in == MTSETDRVBUFFER ||
+ cmd_in == SET_DENS_AND_BLK) {
+ if (cmdstatp->sense_hdr.sense_key == ILLEGAL_REQUEST &&
+- !(STp->use_pf & PF_TESTED)) {
++ cmdstatp->sense_hdr.asc == 0x24 &&
++ (STp->device)->scsi_level <= SCSI_2 &&
++ !(STp->use_pf & PF_TESTED)) {
+ /* Try the other possible state of Page Format if not
+ already tried */
+ STp->use_pf = (STp->use_pf ^ USE_PF) | PF_TESTED;
+--
+2.39.5
+
--- /dev/null
+From 09752586d5163ed29291e775c06725c464775578 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Dec 2024 13:17:57 +0300
+Subject: scsi: target: iscsi: Fix timeout on deleted connection
+
+From: Dmitry Bogdanov <d.bogdanov@yadro.com>
+
+[ Upstream commit 7f533cc5ee4c4436cee51dc58e81dfd9c3384418 ]
+
+NOPIN response timer may expire on a deleted connection and crash with
+such logs:
+
+Did not receive response to NOPIN on CID: 0, failing connection for I_T Nexus (null),i,0x00023d000125,iqn.2017-01.com.iscsi.target,t,0x3d
+
+BUG: Kernel NULL pointer dereference on read at 0x00000000
+NIP strlcpy+0x8/0xb0
+LR iscsit_fill_cxn_timeout_err_stats+0x5c/0xc0 [iscsi_target_mod]
+Call Trace:
+ iscsit_handle_nopin_response_timeout+0xfc/0x120 [iscsi_target_mod]
+ call_timer_fn+0x58/0x1f0
+ run_timer_softirq+0x740/0x860
+ __do_softirq+0x16c/0x420
+ irq_exit+0x188/0x1c0
+ timer_interrupt+0x184/0x410
+
+That is because nopin response timer may be re-started on nopin timer
+expiration.
+
+Stop nopin timer before stopping the nopin response timer to be sure
+that no one of them will be re-started.
+
+Signed-off-by: Dmitry Bogdanov <d.bogdanov@yadro.com>
+Link: https://lore.kernel.org/r/20241224101757.32300-1-d.bogdanov@yadro.com
+Reviewed-by: Maurizio Lombardi <mlombard@redhat.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/target/iscsi/iscsi_target.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
+index 1244ef3aa86c1..620ba6e0ab075 100644
+--- a/drivers/target/iscsi/iscsi_target.c
++++ b/drivers/target/iscsi/iscsi_target.c
+@@ -4263,8 +4263,8 @@ int iscsit_close_connection(
+ spin_unlock(&iscsit_global->ts_bitmap_lock);
+
+ iscsit_stop_timers_for_cmds(conn);
+- iscsit_stop_nopin_response_timer(conn);
+ iscsit_stop_nopin_timer(conn);
++ iscsit_stop_nopin_response_timer(conn);
+
+ if (conn->conn_transport->iscsit_wait_conn)
+ conn->conn_transport->iscsit_wait_conn(conn);
+--
+2.39.5
+
--- /dev/null
+From 5a51a10eebb01733ae72da730437befe806910f0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 24 Jan 2025 16:55:42 +0800
+Subject: scsi: target: spc: Fix loop traversal in spc_rsoc_get_descr()
+
+From: Chaohai Chen <wdhh66@163.com>
+
+[ Upstream commit 04ad06e41d1c74cc323b20a7bd023c47bd0e0c38 ]
+
+Stop traversing after finding the appropriate descriptor.
+
+Signed-off-by: Chaohai Chen <wdhh66@163.com>
+Link: https://lore.kernel.org/r/20250124085542.109088-1-wdhh66@163.com
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/target/target_core_spc.c | 14 ++++++++++----
+ 1 file changed, 10 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c
+index 785a97536212b..0a02492bef701 100644
+--- a/drivers/target/target_core_spc.c
++++ b/drivers/target/target_core_spc.c
+@@ -2151,8 +2151,10 @@ spc_rsoc_get_descr(struct se_cmd *cmd, struct target_opcode_descriptor **opcode)
+ if (descr->serv_action_valid)
+ return TCM_INVALID_CDB_FIELD;
+
+- if (!descr->enabled || descr->enabled(descr, cmd))
++ if (!descr->enabled || descr->enabled(descr, cmd)) {
+ *opcode = descr;
++ return TCM_NO_SENSE;
++ }
+ break;
+ case 0x2:
+ /*
+@@ -2166,8 +2168,10 @@ spc_rsoc_get_descr(struct se_cmd *cmd, struct target_opcode_descriptor **opcode)
+ if (descr->serv_action_valid &&
+ descr->service_action == requested_sa) {
+ if (!descr->enabled || descr->enabled(descr,
+- cmd))
++ cmd)) {
+ *opcode = descr;
++ return TCM_NO_SENSE;
++ }
+ } else if (!descr->serv_action_valid)
+ return TCM_INVALID_CDB_FIELD;
+ break;
+@@ -2180,13 +2184,15 @@ spc_rsoc_get_descr(struct se_cmd *cmd, struct target_opcode_descriptor **opcode)
+ */
+ if (descr->service_action == requested_sa)
+ if (!descr->enabled || descr->enabled(descr,
+- cmd))
++ cmd)) {
+ *opcode = descr;
++ return TCM_NO_SENSE;
++ }
+ break;
+ }
+ }
+
+- return 0;
++ return TCM_NO_SENSE;
+ }
+
+ static sense_reason_t
+--
+2.39.5
+
--- /dev/null
+From 41dc5afed7cce0c7edefd76200794dbec5314f1d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 11 Apr 2025 17:46:30 +0530
+Subject: scsi: ufs: Introduce quirk to extend PA_HIBERN8TIME for UFS devices
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Manish Pandey <quic_mapa@quicinc.com>
+
+[ Upstream commit 569330a34a31a52c904239439984a59972c11d28 ]
+
+Samsung UFS devices require additional time in hibern8 mode before
+exiting, beyond the negotiated handshaking phase between the host and
+device. Introduce a quirk to increase the PA_HIBERN8TIME parameter by
+100 µs, a value derived from experiments, to ensure a proper hibernation
+process.
+
+Signed-off-by: Manish Pandey <quic_mapa@quicinc.com>
+Link: https://lore.kernel.org/r/20250411121630.21330-3-quic_mapa@quicinc.com
+Reviewed-by: Bean Huo <beanhuo@micron.com>
+Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/ufs/core/ufshcd.c | 29 +++++++++++++++++++++++++++++
+ include/ufs/ufs_quirks.h | 6 ++++++
+ 2 files changed, 35 insertions(+)
+
+diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
+index 99e7e4a570f0e..47ec4e4e4a2a0 100644
+--- a/drivers/ufs/core/ufshcd.c
++++ b/drivers/ufs/core/ufshcd.c
+@@ -278,6 +278,7 @@ static const struct ufs_dev_quirk ufs_fixups[] = {
+ .model = UFS_ANY_MODEL,
+ .quirk = UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM |
+ UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE |
++ UFS_DEVICE_QUIRK_PA_HIBER8TIME |
+ UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS },
+ { .wmanufacturerid = UFS_VENDOR_SKHYNIX,
+ .model = UFS_ANY_MODEL,
+@@ -8384,6 +8385,31 @@ static int ufshcd_quirk_tune_host_pa_tactivate(struct ufs_hba *hba)
+ return ret;
+ }
+
++/**
++ * ufshcd_quirk_override_pa_h8time - Ensures proper adjustment of PA_HIBERN8TIME.
++ * @hba: per-adapter instance
++ *
++ * Some UFS devices require specific adjustments to the PA_HIBERN8TIME parameter
++ * to ensure proper hibernation timing. This function retrieves the current
++ * PA_HIBERN8TIME value and increments it by 100us.
++ */
++static void ufshcd_quirk_override_pa_h8time(struct ufs_hba *hba)
++{
++ u32 pa_h8time;
++ int ret;
++
++ ret = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_HIBERN8TIME), &pa_h8time);
++ if (ret) {
++ dev_err(hba->dev, "Failed to get PA_HIBERN8TIME: %d\n", ret);
++ return;
++ }
++
++ /* Increment by 1 to increase hibernation time by 100 µs */
++ ret = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_HIBERN8TIME), pa_h8time + 1);
++ if (ret)
++ dev_err(hba->dev, "Failed updating PA_HIBERN8TIME: %d\n", ret);
++}
++
+ static void ufshcd_tune_unipro_params(struct ufs_hba *hba)
+ {
+ ufshcd_vops_apply_dev_quirks(hba);
+@@ -8394,6 +8420,9 @@ static void ufshcd_tune_unipro_params(struct ufs_hba *hba)
+
+ if (hba->dev_quirks & UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE)
+ ufshcd_quirk_tune_host_pa_tactivate(hba);
++
++ if (hba->dev_quirks & UFS_DEVICE_QUIRK_PA_HIBER8TIME)
++ ufshcd_quirk_override_pa_h8time(hba);
+ }
+
+ static void ufshcd_clear_dbg_ufs_stats(struct ufs_hba *hba)
+diff --git a/include/ufs/ufs_quirks.h b/include/ufs/ufs_quirks.h
+index 41ff44dfa1db3..f52de5ed1b3b6 100644
+--- a/include/ufs/ufs_quirks.h
++++ b/include/ufs/ufs_quirks.h
+@@ -107,4 +107,10 @@ struct ufs_dev_quirk {
+ */
+ #define UFS_DEVICE_QUIRK_DELAY_AFTER_LPM (1 << 11)
+
++/*
++ * Some ufs devices may need more time to be in hibern8 before exiting.
++ * Enable this quirk to give it an additional 100us.
++ */
++#define UFS_DEVICE_QUIRK_PA_HIBER8TIME (1 << 12)
++
+ #endif /* UFS_QUIRKS_H_ */
+--
+2.39.5
+
--- /dev/null
+From 788e11ad62a36f5e6245d3813b187bceaa43b613 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 10 Feb 2025 12:50:09 -0800
+Subject: scsi: usb: Rename the RESERVE and RELEASE constants
+
+From: Bart Van Assche <bvanassche@acm.org>
+
+[ Upstream commit 0ea163a18b17f9e0f8350bb348ae69c4a376be66 ]
+
+The names RESERVE and RELEASE are not only used in <scsi/scsi_proto.h> but
+also elsewhere in the kernel:
+
+$ git grep -nHE 'define[[:blank:]]*(RESERVE|RELEASE)[[:blank:]]'
+drivers/input/joystick/walkera0701.c:13:#define RESERVE 20000
+drivers/s390/char/tape_std.h:56:#define RELEASE 0xD4 /* 3420 NOP, 3480 REJECT */
+drivers/s390/char/tape_std.h:58:#define RESERVE 0xF4 /* 3420 NOP, 3480 REJECT */
+
+Additionally, while the names of the symbolic constants RESERVE_10 and
+RELEASE_10 include the command length, the command length is not included
+in the RESERVE and RELEASE names. Address both issues by renaming the
+RESERVE and RELEASE constants into RESERVE_6 and RELEASE_6 respectively.
+
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Bart Van Assche <bvanassche@acm.org>
+Link: https://lore.kernel.org/r/20250210205031.2970833-1-bvanassche@acm.org
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/message/fusion/mptscsih.c | 4 ++--
+ drivers/scsi/aacraid/aachba.c | 4 ++--
+ drivers/scsi/arm/acornscsi.c | 2 +-
+ drivers/scsi/ips.c | 8 ++++----
+ drivers/scsi/megaraid.c | 10 +++++-----
+ drivers/scsi/megaraid/megaraid_mbox.c | 10 +++++-----
+ drivers/target/target_core_device.c | 8 ++++----
+ drivers/target/target_core_pr.c | 6 +++---
+ drivers/target/target_core_spc.c | 20 ++++++++++----------
+ drivers/usb/gadget/function/f_mass_storage.c | 4 ++--
+ drivers/usb/storage/debug.c | 4 ++--
+ include/scsi/scsi_proto.h | 4 ++--
+ include/trace/events/scsi.h | 4 ++--
+ include/trace/events/target.h | 4 ++--
+ 14 files changed, 46 insertions(+), 46 deletions(-)
+
+diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
+index a9604ba3c8058..f0746db92ca61 100644
+--- a/drivers/message/fusion/mptscsih.c
++++ b/drivers/message/fusion/mptscsih.c
+@@ -2915,14 +2915,14 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
+ timeout = 10;
+ break;
+
+- case RESERVE:
++ case RESERVE_6:
+ cmdLen = 6;
+ dir = MPI_SCSIIO_CONTROL_READ;
+ CDB[0] = cmd;
+ timeout = 10;
+ break;
+
+- case RELEASE:
++ case RELEASE_6:
+ cmdLen = 6;
+ dir = MPI_SCSIIO_CONTROL_READ;
+ CDB[0] = cmd;
+diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
+index abf6a82b74af3..0be719f383770 100644
+--- a/drivers/scsi/aacraid/aachba.c
++++ b/drivers/scsi/aacraid/aachba.c
+@@ -3221,8 +3221,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
+ break;
+ }
+ fallthrough;
+- case RESERVE:
+- case RELEASE:
++ case RESERVE_6:
++ case RELEASE_6:
+ case REZERO_UNIT:
+ case REASSIGN_BLOCKS:
+ case SEEK_10:
+diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c
+index e50a3dbf9de3e..ef21b85cf0146 100644
+--- a/drivers/scsi/arm/acornscsi.c
++++ b/drivers/scsi/arm/acornscsi.c
+@@ -591,7 +591,7 @@ datadir_t acornscsi_datadirection(int command)
+ case CHANGE_DEFINITION: case COMPARE: case COPY:
+ case COPY_VERIFY: case LOG_SELECT: case MODE_SELECT:
+ case MODE_SELECT_10: case SEND_DIAGNOSTIC: case WRITE_BUFFER:
+- case FORMAT_UNIT: case REASSIGN_BLOCKS: case RESERVE:
++ case FORMAT_UNIT: case REASSIGN_BLOCKS: case RESERVE_6:
+ case SEARCH_EQUAL: case SEARCH_HIGH: case SEARCH_LOW:
+ case WRITE_6: case WRITE_10: case WRITE_VERIFY:
+ case UPDATE_BLOCK: case WRITE_LONG: case WRITE_SAME:
+diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
+index cce6c6b409ad5..94adb6ac02a4e 100644
+--- a/drivers/scsi/ips.c
++++ b/drivers/scsi/ips.c
+@@ -3631,8 +3631,8 @@ ips_send_cmd(ips_ha_t * ha, ips_scb_t * scb)
+
+ break;
+
+- case RESERVE:
+- case RELEASE:
++ case RESERVE_6:
++ case RELEASE_6:
+ scb->scsi_cmd->result = DID_OK << 16;
+ break;
+
+@@ -3899,8 +3899,8 @@ ips_chkstatus(ips_ha_t * ha, IPS_STATUS * pstatus)
+ case WRITE_6:
+ case READ_10:
+ case WRITE_10:
+- case RESERVE:
+- case RELEASE:
++ case RESERVE_6:
++ case RELEASE_6:
+ break;
+
+ case MODE_SENSE:
+diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
+index adab151663dd8..2006094af4189 100644
+--- a/drivers/scsi/megaraid.c
++++ b/drivers/scsi/megaraid.c
+@@ -855,8 +855,8 @@ mega_build_cmd(adapter_t *adapter, struct scsi_cmnd *cmd, int *busy)
+ return scb;
+
+ #if MEGA_HAVE_CLUSTERING
+- case RESERVE:
+- case RELEASE:
++ case RESERVE_6:
++ case RELEASE_6:
+
+ /*
+ * Do we support clustering and is the support enabled
+@@ -875,7 +875,7 @@ mega_build_cmd(adapter_t *adapter, struct scsi_cmnd *cmd, int *busy)
+ }
+
+ scb->raw_mbox[0] = MEGA_CLUSTER_CMD;
+- scb->raw_mbox[2] = ( *cmd->cmnd == RESERVE ) ?
++ scb->raw_mbox[2] = *cmd->cmnd == RESERVE_6 ?
+ MEGA_RESERVE_LD : MEGA_RELEASE_LD;
+
+ scb->raw_mbox[3] = ldrv_num;
+@@ -1618,8 +1618,8 @@ mega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status)
+ * failed or the input parameter is invalid
+ */
+ if( status == 1 &&
+- (cmd->cmnd[0] == RESERVE ||
+- cmd->cmnd[0] == RELEASE) ) {
++ (cmd->cmnd[0] == RESERVE_6 ||
++ cmd->cmnd[0] == RELEASE_6) ) {
+
+ cmd->result |= (DID_ERROR << 16) |
+ SAM_STAT_RESERVATION_CONFLICT;
+diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c
+index 60cc3372991fd..3ba837b3093f8 100644
+--- a/drivers/scsi/megaraid/megaraid_mbox.c
++++ b/drivers/scsi/megaraid/megaraid_mbox.c
+@@ -1725,8 +1725,8 @@ megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy)
+
+ return scb;
+
+- case RESERVE:
+- case RELEASE:
++ case RESERVE_6:
++ case RELEASE_6:
+ /*
+ * Do we support clustering and is the support enabled
+ */
+@@ -1748,7 +1748,7 @@ megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy)
+ scb->dev_channel = 0xFF;
+ scb->dev_target = target;
+ ccb->raw_mbox[0] = CLUSTER_CMD;
+- ccb->raw_mbox[2] = (scp->cmnd[0] == RESERVE) ?
++ ccb->raw_mbox[2] = scp->cmnd[0] == RESERVE_6 ?
+ RESERVE_LD : RELEASE_LD;
+
+ ccb->raw_mbox[3] = target;
+@@ -2334,8 +2334,8 @@ megaraid_mbox_dpc(unsigned long devp)
+ * Error code returned is 1 if Reserve or Release
+ * failed or the input parameter is invalid
+ */
+- if (status == 1 && (scp->cmnd[0] == RESERVE ||
+- scp->cmnd[0] == RELEASE)) {
++ if (status == 1 && (scp->cmnd[0] == RESERVE_6 ||
++ scp->cmnd[0] == RELEASE_6)) {
+
+ scp->result = DID_ERROR << 16 |
+ SAM_STAT_RESERVATION_CONFLICT;
+diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
+index d1ae3df069a4f..cc2da086f96e2 100644
+--- a/drivers/target/target_core_device.c
++++ b/drivers/target/target_core_device.c
+@@ -1078,8 +1078,8 @@ passthrough_parse_cdb(struct se_cmd *cmd,
+ if (!dev->dev_attrib.emulate_pr &&
+ ((cdb[0] == PERSISTENT_RESERVE_IN) ||
+ (cdb[0] == PERSISTENT_RESERVE_OUT) ||
+- (cdb[0] == RELEASE || cdb[0] == RELEASE_10) ||
+- (cdb[0] == RESERVE || cdb[0] == RESERVE_10))) {
++ (cdb[0] == RELEASE_6 || cdb[0] == RELEASE_10) ||
++ (cdb[0] == RESERVE_6 || cdb[0] == RESERVE_10))) {
+ return TCM_UNSUPPORTED_SCSI_OPCODE;
+ }
+
+@@ -1101,7 +1101,7 @@ passthrough_parse_cdb(struct se_cmd *cmd,
+ return target_cmd_size_check(cmd, size);
+ }
+
+- if (cdb[0] == RELEASE || cdb[0] == RELEASE_10) {
++ if (cdb[0] == RELEASE_6 || cdb[0] == RELEASE_10) {
+ cmd->execute_cmd = target_scsi2_reservation_release;
+ if (cdb[0] == RELEASE_10)
+ size = get_unaligned_be16(&cdb[7]);
+@@ -1109,7 +1109,7 @@ passthrough_parse_cdb(struct se_cmd *cmd,
+ size = cmd->data_length;
+ return target_cmd_size_check(cmd, size);
+ }
+- if (cdb[0] == RESERVE || cdb[0] == RESERVE_10) {
++ if (cdb[0] == RESERVE_6 || cdb[0] == RESERVE_10) {
+ cmd->execute_cmd = target_scsi2_reservation_reserve;
+ if (cdb[0] == RESERVE_10)
+ size = get_unaligned_be16(&cdb[7]);
+diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
+index 4f4ad6af416c8..34cf2c399b399 100644
+--- a/drivers/target/target_core_pr.c
++++ b/drivers/target/target_core_pr.c
+@@ -91,7 +91,7 @@ target_scsi2_reservation_check(struct se_cmd *cmd)
+
+ switch (cmd->t_task_cdb[0]) {
+ case INQUIRY:
+- case RELEASE:
++ case RELEASE_6:
+ case RELEASE_10:
+ return 0;
+ default:
+@@ -418,12 +418,12 @@ static int core_scsi3_pr_seq_non_holder(struct se_cmd *cmd, u32 pr_reg_type,
+ return -EINVAL;
+ }
+ break;
+- case RELEASE:
++ case RELEASE_6:
+ case RELEASE_10:
+ /* Handled by CRH=1 in target_scsi2_reservation_release() */
+ ret = 0;
+ break;
+- case RESERVE:
++ case RESERVE_6:
+ case RESERVE_10:
+ /* Handled by CRH=1 in target_scsi2_reservation_reserve() */
+ ret = 0;
+diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c
+index 61c065702350e..785a97536212b 100644
+--- a/drivers/target/target_core_spc.c
++++ b/drivers/target/target_core_spc.c
+@@ -1674,9 +1674,9 @@ static bool tcm_is_pr_enabled(struct target_opcode_descriptor *descr,
+ return true;
+
+ switch (descr->opcode) {
+- case RESERVE:
++ case RESERVE_6:
+ case RESERVE_10:
+- case RELEASE:
++ case RELEASE_6:
+ case RELEASE_10:
+ /*
+ * The pr_ops which are used by the backend modules don't
+@@ -1828,9 +1828,9 @@ static struct target_opcode_descriptor tcm_opcode_pro_register_move = {
+
+ static struct target_opcode_descriptor tcm_opcode_release = {
+ .support = SCSI_SUPPORT_FULL,
+- .opcode = RELEASE,
++ .opcode = RELEASE_6,
+ .cdb_size = 6,
+- .usage_bits = {RELEASE, 0x00, 0x00, 0x00,
++ .usage_bits = {RELEASE_6, 0x00, 0x00, 0x00,
+ 0x00, SCSI_CONTROL_MASK},
+ .enabled = tcm_is_pr_enabled,
+ };
+@@ -1847,9 +1847,9 @@ static struct target_opcode_descriptor tcm_opcode_release10 = {
+
+ static struct target_opcode_descriptor tcm_opcode_reserve = {
+ .support = SCSI_SUPPORT_FULL,
+- .opcode = RESERVE,
++ .opcode = RESERVE_6,
+ .cdb_size = 6,
+- .usage_bits = {RESERVE, 0x00, 0x00, 0x00,
++ .usage_bits = {RESERVE_6, 0x00, 0x00, 0x00,
+ 0x00, SCSI_CONTROL_MASK},
+ .enabled = tcm_is_pr_enabled,
+ };
+@@ -2267,9 +2267,9 @@ spc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
+ unsigned char *cdb = cmd->t_task_cdb;
+
+ switch (cdb[0]) {
+- case RESERVE:
++ case RESERVE_6:
+ case RESERVE_10:
+- case RELEASE:
++ case RELEASE_6:
+ case RELEASE_10:
+ if (!dev->dev_attrib.emulate_pr)
+ return TCM_UNSUPPORTED_SCSI_OPCODE;
+@@ -2313,7 +2313,7 @@ spc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
+ *size = get_unaligned_be32(&cdb[5]);
+ cmd->execute_cmd = target_scsi3_emulate_pr_out;
+ break;
+- case RELEASE:
++ case RELEASE_6:
+ case RELEASE_10:
+ if (cdb[0] == RELEASE_10)
+ *size = get_unaligned_be16(&cdb[7]);
+@@ -2322,7 +2322,7 @@ spc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
+
+ cmd->execute_cmd = target_scsi2_reservation_release;
+ break;
+- case RESERVE:
++ case RESERVE_6:
+ case RESERVE_10:
+ /*
+ * The SPC-2 RESERVE does not contain a size in the SCSI CDB.
+diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c
+index 2eae8fc2e0db7..94d478b6bcd3d 100644
+--- a/drivers/usb/gadget/function/f_mass_storage.c
++++ b/drivers/usb/gadget/function/f_mass_storage.c
+@@ -2142,8 +2142,8 @@ static int do_scsi_command(struct fsg_common *common)
+ * of Posix locks.
+ */
+ case FORMAT_UNIT:
+- case RELEASE:
+- case RESERVE:
++ case RELEASE_6:
++ case RESERVE_6:
+ case SEND_DIAGNOSTIC:
+
+ default:
+diff --git a/drivers/usb/storage/debug.c b/drivers/usb/storage/debug.c
+index 576be66ad9627..dda610f689b73 100644
+--- a/drivers/usb/storage/debug.c
++++ b/drivers/usb/storage/debug.c
+@@ -58,8 +58,8 @@ void usb_stor_show_command(const struct us_data *us, struct scsi_cmnd *srb)
+ case INQUIRY: what = "INQUIRY"; break;
+ case RECOVER_BUFFERED_DATA: what = "RECOVER_BUFFERED_DATA"; break;
+ case MODE_SELECT: what = "MODE_SELECT"; break;
+- case RESERVE: what = "RESERVE"; break;
+- case RELEASE: what = "RELEASE"; break;
++ case RESERVE_6: what = "RESERVE"; break;
++ case RELEASE_6: what = "RELEASE"; break;
+ case COPY: what = "COPY"; break;
+ case ERASE: what = "ERASE"; break;
+ case MODE_SENSE: what = "MODE_SENSE"; break;
+diff --git a/include/scsi/scsi_proto.h b/include/scsi/scsi_proto.h
+index 70e1262b2e202..aeca37816506d 100644
+--- a/include/scsi/scsi_proto.h
++++ b/include/scsi/scsi_proto.h
+@@ -33,8 +33,8 @@
+ #define INQUIRY 0x12
+ #define RECOVER_BUFFERED_DATA 0x14
+ #define MODE_SELECT 0x15
+-#define RESERVE 0x16
+-#define RELEASE 0x17
++#define RESERVE_6 0x16
++#define RELEASE_6 0x17
+ #define COPY 0x18
+ #define ERASE 0x19
+ #define MODE_SENSE 0x1a
+diff --git a/include/trace/events/scsi.h b/include/trace/events/scsi.h
+index 05f1945ed204e..bf6cc98d91228 100644
+--- a/include/trace/events/scsi.h
++++ b/include/trace/events/scsi.h
+@@ -29,8 +29,8 @@
+ scsi_opcode_name(INQUIRY), \
+ scsi_opcode_name(RECOVER_BUFFERED_DATA), \
+ scsi_opcode_name(MODE_SELECT), \
+- scsi_opcode_name(RESERVE), \
+- scsi_opcode_name(RELEASE), \
++ scsi_opcode_name(RESERVE_6), \
++ scsi_opcode_name(RELEASE_6), \
+ scsi_opcode_name(COPY), \
+ scsi_opcode_name(ERASE), \
+ scsi_opcode_name(MODE_SENSE), \
+diff --git a/include/trace/events/target.h b/include/trace/events/target.h
+index a13cbf2b34050..7e2e20ba26f1c 100644
+--- a/include/trace/events/target.h
++++ b/include/trace/events/target.h
+@@ -31,8 +31,8 @@
+ scsi_opcode_name(INQUIRY), \
+ scsi_opcode_name(RECOVER_BUFFERED_DATA), \
+ scsi_opcode_name(MODE_SELECT), \
+- scsi_opcode_name(RESERVE), \
+- scsi_opcode_name(RELEASE), \
++ scsi_opcode_name(RESERVE_6), \
++ scsi_opcode_name(RELEASE_6), \
+ scsi_opcode_name(COPY), \
+ scsi_opcode_name(ERASE), \
+ scsi_opcode_name(MODE_SENSE), \
+--
+2.39.5
+
--- /dev/null
+From 539912a96c595eb83a70956aac495523f5a26ccd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 16 Apr 2025 10:02:46 -0700
+Subject: selftests/bpf: Mitigate sockmap_ktls disconnect_after_delete failure
+
+From: Ihor Solodrai <ihor.solodrai@linux.dev>
+
+[ Upstream commit f2858f308131a09e33afb766cd70119b5b900569 ]
+
+"sockmap_ktls disconnect_after_delete" test has been failing on BPF CI
+after recent merges from netdev:
+* https://github.com/kernel-patches/bpf/actions/runs/14458537639
+* https://github.com/kernel-patches/bpf/actions/runs/14457178732
+
+It happens because disconnect has been disabled for TLS [1], and it
+renders the test case invalid.
+
+Removing all the test code creates a conflict between bpf and
+bpf-next, so for now only remove the offending assert [2].
+
+The test will be removed later on bpf-next.
+
+[1] https://lore.kernel.org/netdev/20250404180334.3224206-1-kuba@kernel.org/
+[2] https://lore.kernel.org/bpf/cfc371285323e1a3f3b006bfcf74e6cf7ad65258@linux.dev/
+
+Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
+Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
+Reviewed-by: Jiayuan Chen <jiayuan.chen@linux.dev>
+Link: https://lore.kernel.org/bpf/20250416170246.2438524-1-ihor.solodrai@linux.dev
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/testing/selftests/bpf/prog_tests/sockmap_ktls.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_ktls.c b/tools/testing/selftests/bpf/prog_tests/sockmap_ktls.c
+index 2d0796314862a..0a99fd404f6dc 100644
+--- a/tools/testing/selftests/bpf/prog_tests/sockmap_ktls.c
++++ b/tools/testing/selftests/bpf/prog_tests/sockmap_ktls.c
+@@ -68,7 +68,6 @@ static void test_sockmap_ktls_disconnect_after_delete(int family, int map)
+ goto close_cli;
+
+ err = disconnect(cli);
+- ASSERT_OK(err, "disconnect");
+
+ close_cli:
+ close(cli);
+--
+2.39.5
+
--- /dev/null
+From aff23d470addbd4fb70cc7b534d79a78d4074e0b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Feb 2025 11:27:23 -0800
+Subject: selftests/net: have `gro.sh -t` return a correct exit code
+
+From: Kevin Krakauer <krakauer@google.com>
+
+[ Upstream commit 784e6abd99f24024a8998b5916795f0bec9d2fd9 ]
+
+Modify gro.sh to return a useful exit code when the -t flag is used. It
+formerly returned 0 no matter what.
+
+Tested: Ran `gro.sh -t large` and verified that test failures return 1.
+Signed-off-by: Kevin Krakauer <krakauer@google.com>
+Reviewed-by: Willem de Bruijn <willemb@google.com>
+Link: https://patch.msgid.link/20250226192725.621969-2-krakauer@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/testing/selftests/net/gro.sh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/tools/testing/selftests/net/gro.sh b/tools/testing/selftests/net/gro.sh
+index 02c21ff4ca81f..aabd6e5480b8e 100755
+--- a/tools/testing/selftests/net/gro.sh
++++ b/tools/testing/selftests/net/gro.sh
+@@ -100,5 +100,6 @@ trap cleanup EXIT
+ if [[ "${test}" == "all" ]]; then
+ run_all_tests
+ else
+- run_test "${proto}" "${test}"
++ exit_code=$(run_test "${proto}" "${test}")
++ exit $exit_code
+ fi;
+--
+2.39.5
+
--- /dev/null
+From 2c2e2fd5dec9940a0740ccf38424636432451767 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 23 Jan 2025 13:01:49 +0100
+Subject: selftests: pci_endpoint: Skip disabled BARs
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Niklas Cassel <cassel@kernel.org>
+
+[ Upstream commit af1451b6738ec7cf91f2914f53845424959ec4ee ]
+
+Currently BARs that have been disabled by the endpoint controller driver
+will result in a test FAIL.
+
+Returning FAIL for a BAR that is disabled seems overly pessimistic.
+
+There are EPC that disables one or more BARs intentionally.
+
+One reason for this is that there are certain EPCs that are hardwired to
+expose internal PCIe controller registers over a certain BAR, so the EPC
+driver disables such a BAR, such that the host will not overwrite random
+registers during testing.
+
+Such a BAR will be disabled by the EPC driver's init function, and the
+BAR will be marked as BAR_RESERVED, such that it will be unavailable to
+endpoint function drivers.
+
+Let's return FAIL only for BARs that are actually enabled and failed the
+test, and let's return skip for BARs that are not even enabled.
+
+Signed-off-by: Niklas Cassel <cassel@kernel.org>
+Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+Link: https://lore.kernel.org/r/20250123120147.3603409-4-cassel@kernel.org
+Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+Signed-off-by: Krzysztof Wilczyński <kwilczynski@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/testing/selftests/pci_endpoint/pci_endpoint_test.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/tools/testing/selftests/pci_endpoint/pci_endpoint_test.c b/tools/testing/selftests/pci_endpoint/pci_endpoint_test.c
+index c267b822c1081..576c590b277b1 100644
+--- a/tools/testing/selftests/pci_endpoint/pci_endpoint_test.c
++++ b/tools/testing/selftests/pci_endpoint/pci_endpoint_test.c
+@@ -65,6 +65,8 @@ TEST_F(pci_ep_bar, BAR_TEST)
+ int ret;
+
+ pci_ep_ioctl(PCITEST_BAR, variant->barno);
++ if (ret == -ENODATA)
++ SKIP(return, "BAR is disabled");
+ EXPECT_FALSE(ret) TH_LOG("Test failed for BAR%d", variant->barno);
+ }
+
+--
+2.39.5
+
--- /dev/null
+From 35f3d93ba01a301382b33705f3bb4c6b8c51e28a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 17 Feb 2025 07:21:53 +0100
+Subject: serial: mctrl_gpio: split disable_ms into sync and no_sync APIs
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Alexis Lothoré <alexis.lothore@bootlin.com>
+
+[ Upstream commit 1bd2aad57da95f7f2d2bb52f7ad15c0f4993a685 ]
+
+The following splat has been observed on a SAMA5D27 platform using
+atmel_serial:
+
+BUG: sleeping function called from invalid context at kernel/irq/manage.c:738
+in_atomic(): 1, irqs_disabled(): 128, non_block: 0, pid: 27, name: kworker/u5:0
+preempt_count: 1, expected: 0
+INFO: lockdep is turned off.
+irq event stamp: 0
+hardirqs last enabled at (0): [<00000000>] 0x0
+hardirqs last disabled at (0): [<c01588f0>] copy_process+0x1c4c/0x7bec
+softirqs last enabled at (0): [<c0158944>] copy_process+0x1ca0/0x7bec
+softirqs last disabled at (0): [<00000000>] 0x0
+CPU: 0 UID: 0 PID: 27 Comm: kworker/u5:0 Not tainted 6.13.0-rc7+ #74
+Hardware name: Atmel SAMA5
+Workqueue: hci0 hci_power_on [bluetooth]
+Call trace:
+ unwind_backtrace from show_stack+0x18/0x1c
+ show_stack from dump_stack_lvl+0x44/0x70
+ dump_stack_lvl from __might_resched+0x38c/0x598
+ __might_resched from disable_irq+0x1c/0x48
+ disable_irq from mctrl_gpio_disable_ms+0x74/0xc0
+ mctrl_gpio_disable_ms from atmel_disable_ms.part.0+0x80/0x1f4
+ atmel_disable_ms.part.0 from atmel_set_termios+0x764/0x11e8
+ atmel_set_termios from uart_change_line_settings+0x15c/0x994
+ uart_change_line_settings from uart_set_termios+0x2b0/0x668
+ uart_set_termios from tty_set_termios+0x600/0x8ec
+ tty_set_termios from ttyport_set_flow_control+0x188/0x1e0
+ ttyport_set_flow_control from wilc_setup+0xd0/0x524 [hci_wilc]
+ wilc_setup [hci_wilc] from hci_dev_open_sync+0x330/0x203c [bluetooth]
+ hci_dev_open_sync [bluetooth] from hci_dev_do_open+0x40/0xb0 [bluetooth]
+ hci_dev_do_open [bluetooth] from hci_power_on+0x12c/0x664 [bluetooth]
+ hci_power_on [bluetooth] from process_one_work+0x998/0x1a38
+ process_one_work from worker_thread+0x6e0/0xfb4
+ worker_thread from kthread+0x3d4/0x484
+ kthread from ret_from_fork+0x14/0x28
+
+This warning is emitted when trying to toggle, at the highest level,
+some flow control (with serdev_device_set_flow_control) in a device
+driver. At the lowest level, the atmel_serial driver is using
+serial_mctrl_gpio lib to enable/disable the corresponding IRQs
+accordingly. The warning emitted by CONFIG_DEBUG_ATOMIC_SLEEP is due to
+disable_irq (called in mctrl_gpio_disable_ms) being possibly called in
+some atomic context (some tty drivers perform modem lines configuration
+in regions protected by port lock).
+
+Split mctrl_gpio_disable_ms into two differents APIs, a non-blocking one
+and a blocking one. Replace mctrl_gpio_disable_ms calls with the
+relevant version depending on whether the call is protected by some port
+lock.
+
+Suggested-by: Jiri Slaby <jirislaby@kernel.org>
+Signed-off-by: Alexis Lothoré <alexis.lothore@bootlin.com>
+Acked-by: Richard Genoud <richard.genoud@bootlin.com>
+Link: https://lore.kernel.org/r/20250217-atomic_sleep_mctrl_serial_gpio-v3-1-59324b313eef@bootlin.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ Documentation/driver-api/serial/driver.rst | 2 +-
+ drivers/tty/serial/8250/8250_port.c | 2 +-
+ drivers/tty/serial/atmel_serial.c | 2 +-
+ drivers/tty/serial/imx.c | 2 +-
+ drivers/tty/serial/serial_mctrl_gpio.c | 34 +++++++++++++++++-----
+ drivers/tty/serial/serial_mctrl_gpio.h | 17 +++++++++--
+ drivers/tty/serial/sh-sci.c | 2 +-
+ drivers/tty/serial/stm32-usart.c | 2 +-
+ 8 files changed, 47 insertions(+), 16 deletions(-)
+
+diff --git a/Documentation/driver-api/serial/driver.rst b/Documentation/driver-api/serial/driver.rst
+index 84b43061c11be..60434f2b02863 100644
+--- a/Documentation/driver-api/serial/driver.rst
++++ b/Documentation/driver-api/serial/driver.rst
+@@ -103,4 +103,4 @@ Some helpers are provided in order to set/get modem control lines via GPIO.
+ .. kernel-doc:: drivers/tty/serial/serial_mctrl_gpio.c
+ :identifiers: mctrl_gpio_init mctrl_gpio_free mctrl_gpio_to_gpiod
+ mctrl_gpio_set mctrl_gpio_get mctrl_gpio_enable_ms
+- mctrl_gpio_disable_ms
++ mctrl_gpio_disable_ms_sync mctrl_gpio_disable_ms_no_sync
+diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
+index 442967a6cd52d..886e40f680d45 100644
+--- a/drivers/tty/serial/8250/8250_port.c
++++ b/drivers/tty/serial/8250/8250_port.c
+@@ -1680,7 +1680,7 @@ static void serial8250_disable_ms(struct uart_port *port)
+ if (up->bugs & UART_BUG_NOMSR)
+ return;
+
+- mctrl_gpio_disable_ms(up->gpios);
++ mctrl_gpio_disable_ms_no_sync(up->gpios);
+
+ up->ier &= ~UART_IER_MSI;
+ serial_port_out(port, UART_IER, up->ier);
+diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
+index f44f9d20a9744..8918fbd4bddd5 100644
+--- a/drivers/tty/serial/atmel_serial.c
++++ b/drivers/tty/serial/atmel_serial.c
+@@ -700,7 +700,7 @@ static void atmel_disable_ms(struct uart_port *port)
+
+ atmel_port->ms_irq_enabled = false;
+
+- mctrl_gpio_disable_ms(atmel_port->gpios);
++ mctrl_gpio_disable_ms_no_sync(atmel_port->gpios);
+
+ if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS))
+ idr |= ATMEL_US_CTSIC;
+diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
+index 9c59ec128bb4f..cfeb3f8cf45ea 100644
+--- a/drivers/tty/serial/imx.c
++++ b/drivers/tty/serial/imx.c
+@@ -1608,7 +1608,7 @@ static void imx_uart_shutdown(struct uart_port *port)
+ imx_uart_dma_exit(sport);
+ }
+
+- mctrl_gpio_disable_ms(sport->gpios);
++ mctrl_gpio_disable_ms_sync(sport->gpios);
+
+ uart_port_lock_irqsave(&sport->port, &flags);
+ ucr2 = imx_uart_readl(sport, UCR2);
+diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c
+index 8855688a5b6c0..ca55bcc0b6111 100644
+--- a/drivers/tty/serial/serial_mctrl_gpio.c
++++ b/drivers/tty/serial/serial_mctrl_gpio.c
+@@ -322,11 +322,7 @@ void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios)
+ }
+ EXPORT_SYMBOL_GPL(mctrl_gpio_enable_ms);
+
+-/**
+- * mctrl_gpio_disable_ms - disable irqs and handling of changes to the ms lines
+- * @gpios: gpios to disable
+- */
+-void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
++static void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios, bool sync)
+ {
+ enum mctrl_gpio_idx i;
+
+@@ -342,10 +338,34 @@ void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
+ if (!gpios->irq[i])
+ continue;
+
+- disable_irq(gpios->irq[i]);
++ if (sync)
++ disable_irq(gpios->irq[i]);
++ else
++ disable_irq_nosync(gpios->irq[i]);
+ }
+ }
+-EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms);
++
++/**
++ * mctrl_gpio_disable_ms_sync - disable irqs and handling of changes to the ms
++ * lines, and wait for any pending IRQ to be processed
++ * @gpios: gpios to disable
++ */
++void mctrl_gpio_disable_ms_sync(struct mctrl_gpios *gpios)
++{
++ mctrl_gpio_disable_ms(gpios, true);
++}
++EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms_sync);
++
++/**
++ * mctrl_gpio_disable_ms_no_sync - disable irqs and handling of changes to the
++ * ms lines, and return immediately
++ * @gpios: gpios to disable
++ */
++void mctrl_gpio_disable_ms_no_sync(struct mctrl_gpios *gpios)
++{
++ mctrl_gpio_disable_ms(gpios, false);
++}
++EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms_no_sync);
+
+ void mctrl_gpio_enable_irq_wake(struct mctrl_gpios *gpios)
+ {
+diff --git a/drivers/tty/serial/serial_mctrl_gpio.h b/drivers/tty/serial/serial_mctrl_gpio.h
+index fc76910fb105a..79e97838ebe56 100644
+--- a/drivers/tty/serial/serial_mctrl_gpio.h
++++ b/drivers/tty/serial/serial_mctrl_gpio.h
+@@ -87,9 +87,16 @@ void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios);
+ void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios);
+
+ /*
+- * Disable gpio interrupts to report status line changes.
++ * Disable gpio interrupts to report status line changes, and block until
++ * any corresponding IRQ is processed
+ */
+-void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios);
++void mctrl_gpio_disable_ms_sync(struct mctrl_gpios *gpios);
++
++/*
++ * Disable gpio interrupts to report status line changes, and return
++ * immediately
++ */
++void mctrl_gpio_disable_ms_no_sync(struct mctrl_gpios *gpios);
+
+ /*
+ * Enable gpio wakeup interrupts to enable wake up source.
+@@ -148,7 +155,11 @@ static inline void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios)
+ {
+ }
+
+-static inline void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
++static inline void mctrl_gpio_disable_ms_sync(struct mctrl_gpios *gpios)
++{
++}
++
++static inline void mctrl_gpio_disable_ms_no_sync(struct mctrl_gpios *gpios)
+ {
+ }
+
+diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
+index b1ea48f38248e..41f987632bce8 100644
+--- a/drivers/tty/serial/sh-sci.c
++++ b/drivers/tty/serial/sh-sci.c
+@@ -2298,7 +2298,7 @@ static void sci_shutdown(struct uart_port *port)
+ dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
+
+ s->autorts = false;
+- mctrl_gpio_disable_ms(to_sci_port(port)->gpios);
++ mctrl_gpio_disable_ms_sync(to_sci_port(port)->gpios);
+
+ uart_port_lock_irqsave(port, &flags);
+ sci_stop_rx(port);
+diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
+index 0854ad8c90cd2..ad06b760cfca7 100644
+--- a/drivers/tty/serial/stm32-usart.c
++++ b/drivers/tty/serial/stm32-usart.c
+@@ -944,7 +944,7 @@ static void stm32_usart_enable_ms(struct uart_port *port)
+
+ static void stm32_usart_disable_ms(struct uart_port *port)
+ {
+- mctrl_gpio_disable_ms(to_stm32_port(port)->gpios);
++ mctrl_gpio_disable_ms_sync(to_stm32_port(port)->gpios);
+ }
+
+ /* Transmit stop */
+--
+2.39.5
+
--- /dev/null
+From 196e0ef38957a44142a4bf71f2ceac9690b64d57 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Mar 2025 20:06:11 +0100
+Subject: serial: sh-sci: Save and restore more registers
+
+From: Geert Uytterhoeven <geert+renesas@glider.be>
+
+[ Upstream commit 81100b9a7b0515132996d62a7a676a77676cb6e3 ]
+
+On (H)SCIF with a Baud Rate Generator for External Clock (BRG), there
+are multiple ways to configure the requested serial speed. If firmware
+uses a different method than Linux, and if any debug info is printed
+after the Bit Rate Register (SCBRR) is restored, but before termios is
+reconfigured (which configures the alternative method), the system may
+lock-up during resume.
+
+Fix this by saving and restoring the contents of the BRG Frequency
+Division (SCDL) and Clock Select (SCCKS) registers as well.
+
+Also save and restore the HSCIF's Sampling Rate Register (HSSRR), which
+configures the sampling point, and the SCIFA/SCIFB's Serial Port Control
+and Data Registers (SCPCR/SCPDR), which configure the optional control
+flow signals.
+
+After this, all registers that are not saved/restored are either:
+ - read-only,
+ - write-only,
+ - status registers containing flags with clear-after-set semantics,
+ - FIFO Data Count Trigger registers, which do not matter much for
+ the serial console.
+
+Fixes: 22a6984c5b5df8ea ("serial: sh-sci: Update the suspend/resume support")
+Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
+Tested-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
+Reviewed-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
+Link: https://lore.kernel.org/r/11c2eab45d48211e75d8b8202cce60400880fe55.1741114989.git.geert+renesas@glider.be
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/serial/sh-sci.c | 25 +++++++++++++++++++++++++
+ 1 file changed, 25 insertions(+)
+
+diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
+index e0ead0147bfe0..0219135caafa4 100644
+--- a/drivers/tty/serial/sh-sci.c
++++ b/drivers/tty/serial/sh-sci.c
+@@ -105,10 +105,15 @@ struct plat_sci_reg {
+ };
+
+ struct sci_suspend_regs {
++ u16 scdl;
++ u16 sccks;
+ u16 scsmr;
+ u16 scscr;
+ u16 scfcr;
+ u16 scsptr;
++ u16 hssrr;
++ u16 scpcr;
++ u16 scpdr;
+ u8 scbrr;
+ u8 semr;
+ };
+@@ -3564,6 +3569,10 @@ static void sci_console_save(struct sci_port *s)
+ struct sci_suspend_regs *regs = &s->suspend_regs;
+ struct uart_port *port = &s->port;
+
++ if (sci_getreg(port, SCDL)->size)
++ regs->scdl = sci_serial_in(port, SCDL);
++ if (sci_getreg(port, SCCKS)->size)
++ regs->sccks = sci_serial_in(port, SCCKS);
+ if (sci_getreg(port, SCSMR)->size)
+ regs->scsmr = sci_serial_in(port, SCSMR);
+ if (sci_getreg(port, SCSCR)->size)
+@@ -3574,6 +3583,12 @@ static void sci_console_save(struct sci_port *s)
+ regs->scsptr = sci_serial_in(port, SCSPTR);
+ if (sci_getreg(port, SCBRR)->size)
+ regs->scbrr = sci_serial_in(port, SCBRR);
++ if (sci_getreg(port, HSSRR)->size)
++ regs->hssrr = sci_serial_in(port, HSSRR);
++ if (sci_getreg(port, SCPCR)->size)
++ regs->scpcr = sci_serial_in(port, SCPCR);
++ if (sci_getreg(port, SCPDR)->size)
++ regs->scpdr = sci_serial_in(port, SCPDR);
+ if (sci_getreg(port, SEMR)->size)
+ regs->semr = sci_serial_in(port, SEMR);
+ }
+@@ -3583,6 +3598,10 @@ static void sci_console_restore(struct sci_port *s)
+ struct sci_suspend_regs *regs = &s->suspend_regs;
+ struct uart_port *port = &s->port;
+
++ if (sci_getreg(port, SCDL)->size)
++ sci_serial_out(port, SCDL, regs->scdl);
++ if (sci_getreg(port, SCCKS)->size)
++ sci_serial_out(port, SCCKS, regs->sccks);
+ if (sci_getreg(port, SCSMR)->size)
+ sci_serial_out(port, SCSMR, regs->scsmr);
+ if (sci_getreg(port, SCSCR)->size)
+@@ -3593,6 +3612,12 @@ static void sci_console_restore(struct sci_port *s)
+ sci_serial_out(port, SCSPTR, regs->scsptr);
+ if (sci_getreg(port, SCBRR)->size)
+ sci_serial_out(port, SCBRR, regs->scbrr);
++ if (sci_getreg(port, HSSRR)->size)
++ sci_serial_out(port, HSSRR, regs->hssrr);
++ if (sci_getreg(port, SCPCR)->size)
++ sci_serial_out(port, SCPCR, regs->scpcr);
++ if (sci_getreg(port, SCPDR)->size)
++ sci_serial_out(port, SCPDR, regs->scpdr);
+ if (sci_getreg(port, SEMR)->size)
+ sci_serial_out(port, SEMR, regs->semr);
+ }
+--
+2.39.5
+
--- /dev/null
+From 8cbb933ccd8aba342e267b224429a02e19608db7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 7 Feb 2025 13:33:13 +0200
+Subject: serial: sh-sci: Update the suspend/resume support
+
+From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
+
+[ Upstream commit 22a6984c5b5df8eab864d7f3e8b94d5a554d31ab ]
+
+The Renesas RZ/G3S supports a power saving mode where power to most of the
+SoC components is turned off. When returning from this power saving mode,
+SoC components need to be re-configured.
+
+The SCIFs on the Renesas RZ/G3S need to be re-configured as well when
+returning from this power saving mode. The sh-sci code already configures
+the SCIF clocks, power domain and registers by calling uart_resume_port()
+in sci_resume(). On suspend path the SCIF UART ports are suspended
+accordingly (by calling uart_suspend_port() in sci_suspend()). The only
+missing setting is the reset signal. For this assert/de-assert the reset
+signal on driver suspend/resume.
+
+In case the no_console_suspend is specified by the user, the registers need
+to be saved on suspend path and restore on resume path. To do this the
+sci_console_save()/sci_console_restore() functions were added. There is no
+need to cache/restore the status or FIFO registers. Only the control
+registers. The registers that will be saved/restored on suspend/resume are
+specified by the struct sci_suspend_regs data structure.
+
+Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
+Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
+Link: https://lore.kernel.org/r/20250207113313.545432-1-claudiu.beznea.uj@bp.renesas.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/serial/sh-sci.c | 71 +++++++++++++++++++++++++++++++++++--
+ 1 file changed, 69 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
+index 41f987632bce8..e0ead0147bfe0 100644
+--- a/drivers/tty/serial/sh-sci.c
++++ b/drivers/tty/serial/sh-sci.c
+@@ -104,6 +104,15 @@ struct plat_sci_reg {
+ u8 offset, size;
+ };
+
++struct sci_suspend_regs {
++ u16 scsmr;
++ u16 scscr;
++ u16 scfcr;
++ u16 scsptr;
++ u8 scbrr;
++ u8 semr;
++};
++
+ struct sci_port_params {
+ const struct plat_sci_reg regs[SCIx_NR_REGS];
+ unsigned int fifosize;
+@@ -134,6 +143,8 @@ struct sci_port {
+ struct dma_chan *chan_tx;
+ struct dma_chan *chan_rx;
+
++ struct reset_control *rstc;
++
+ #ifdef CONFIG_SERIAL_SH_SCI_DMA
+ struct dma_chan *chan_tx_saved;
+ struct dma_chan *chan_rx_saved;
+@@ -153,6 +164,7 @@ struct sci_port {
+ int rx_trigger;
+ struct timer_list rx_fifo_timer;
+ int rx_fifo_timeout;
++ struct sci_suspend_regs suspend_regs;
+ u16 hscif_tot;
+
+ bool has_rtscts;
+@@ -3374,6 +3386,7 @@ static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev,
+ }
+
+ sp = &sci_ports[id];
++ sp->rstc = rstc;
+ *dev_id = id;
+
+ p->type = SCI_OF_TYPE(data);
+@@ -3546,13 +3559,57 @@ static int sci_probe(struct platform_device *dev)
+ return 0;
+ }
+
++static void sci_console_save(struct sci_port *s)
++{
++ struct sci_suspend_regs *regs = &s->suspend_regs;
++ struct uart_port *port = &s->port;
++
++ if (sci_getreg(port, SCSMR)->size)
++ regs->scsmr = sci_serial_in(port, SCSMR);
++ if (sci_getreg(port, SCSCR)->size)
++ regs->scscr = sci_serial_in(port, SCSCR);
++ if (sci_getreg(port, SCFCR)->size)
++ regs->scfcr = sci_serial_in(port, SCFCR);
++ if (sci_getreg(port, SCSPTR)->size)
++ regs->scsptr = sci_serial_in(port, SCSPTR);
++ if (sci_getreg(port, SCBRR)->size)
++ regs->scbrr = sci_serial_in(port, SCBRR);
++ if (sci_getreg(port, SEMR)->size)
++ regs->semr = sci_serial_in(port, SEMR);
++}
++
++static void sci_console_restore(struct sci_port *s)
++{
++ struct sci_suspend_regs *regs = &s->suspend_regs;
++ struct uart_port *port = &s->port;
++
++ if (sci_getreg(port, SCSMR)->size)
++ sci_serial_out(port, SCSMR, regs->scsmr);
++ if (sci_getreg(port, SCSCR)->size)
++ sci_serial_out(port, SCSCR, regs->scscr);
++ if (sci_getreg(port, SCFCR)->size)
++ sci_serial_out(port, SCFCR, regs->scfcr);
++ if (sci_getreg(port, SCSPTR)->size)
++ sci_serial_out(port, SCSPTR, regs->scsptr);
++ if (sci_getreg(port, SCBRR)->size)
++ sci_serial_out(port, SCBRR, regs->scbrr);
++ if (sci_getreg(port, SEMR)->size)
++ sci_serial_out(port, SEMR, regs->semr);
++}
++
+ static __maybe_unused int sci_suspend(struct device *dev)
+ {
+ struct sci_port *sport = dev_get_drvdata(dev);
+
+- if (sport)
++ if (sport) {
+ uart_suspend_port(&sci_uart_driver, &sport->port);
+
++ if (!console_suspend_enabled && uart_console(&sport->port))
++ sci_console_save(sport);
++ else
++ return reset_control_assert(sport->rstc);
++ }
++
+ return 0;
+ }
+
+@@ -3560,8 +3617,18 @@ static __maybe_unused int sci_resume(struct device *dev)
+ {
+ struct sci_port *sport = dev_get_drvdata(dev);
+
+- if (sport)
++ if (sport) {
++ if (!console_suspend_enabled && uart_console(&sport->port)) {
++ sci_console_restore(sport);
++ } else {
++ int ret = reset_control_deassert(sport->rstc);
++
++ if (ret)
++ return ret;
++ }
++
+ uart_resume_port(&sci_uart_driver, &sport->port);
++ }
+
+ return 0;
+ }
+--
+2.39.5
+
--- /dev/null
+drm-amd-display-do-not-enable-replay-when-vtotal-upd.patch
+drm-amd-display-correct-timing_adjust_pending-flag-s.patch
+drm-amd-display-defer-bw-optimization-blocked-drr-ad.patch
+phy-renesas-rcar-gen3-usb2-move-irq-request-in-probe.patch
+phy-renesas-rcar-gen3-usb2-lock-around-hardware-regi.patch
+phy-renesas-rcar-gen3-usb2-assert-pll-reset-on-phy-p.patch
+nvmet-pci-epf-keep-completion-queues-mapped.patch
+nvmet-pci-epf-clear-completion-queue-irq-flag-on-del.patch
+cpufreq-add-sm8650-to-cpufreq-dt-platdev-blocklist.patch
+nvmem-rockchip-otp-move-read-offset-into-variant-dat.patch
+nvmem-rockchip-otp-add-rk3576-variant-data.patch
+nvmem-core-fix-bit-offsets-of-more-than-one-byte.patch
+nvmem-core-verify-cell-s-raw_len.patch
+nvmem-core-update-raw_len-if-the-bit-reading-is-requ.patch
+nvmem-qfprom-switch-to-4-byte-aligned-reads.patch
+scsi-target-iscsi-fix-timeout-on-deleted-connection.patch
+scsi-ufs-introduce-quirk-to-extend-pa_hibern8time-fo.patch
+virtio_ring-fix-data-race-by-tagging-event_triggered.patch
+dma-mapping.c-dev_dbg-support-for-dma_addressing_lim.patch
+intel_th-avoid-using-deprecated-page-mapping-index-f.patch
+mei-vsc-use-struct-vsc_tp_packet-as-vsc-tp-tx_buf-an.patch
+dma-mapping-avoid-potential-unused-data-compilation-.patch
+btrfs-tree-checker-adjust-error-code-for-header-leve.patch
+cgroup-fix-compilation-issue-due-to-cgroup_mutex-not.patch
+vhost_task-fix-vhost_task_create-documentation.patch
+vhost-scsi-protect-vq-log_used-with-vq-mutex.patch
+scsi-mpi3mr-add-level-check-to-control-event-logging.patch
+dma-mapping-fix-warning-reported-for-missing-prototy.patch
+ima-process_measurement-needlessly-takes-inode_lock-.patch
+fs-buffer-split-locking-for-pagecache-lookups.patch
+fs-buffer-introduce-sleeping-flavors-for-pagecache-l.patch
+fs-buffer-use-sleeping-version-of-__find_get_block.patch
+fs-ocfs2-use-sleeping-version-of-__find_get_block.patch
+fs-jbd2-use-sleeping-version-of-__find_get_block.patch
+fs-ext4-use-sleeping-version-of-sb_find_get_block.patch
+drm-amd-display-enable-urgent-latency-adjustment-on-.patch
+drm-amdgpu-allow-p2p-access-through-xgmi.patch
+selftests-bpf-mitigate-sockmap_ktls-disconnect_after.patch
+block-fix-race-between-set_blocksize-and-read-paths.patch
+block-hoist-block-size-validation-code-to-a-separate.patch
+io_uring-don-t-duplicate-flushing-in-io_req_post_cqe.patch
+bpf-fix-possible-endless-loop-in-bpf-map-iteration.patch
+samples-bpf-fix-compilation-failure-for-samples-bpf-.patch
+kconfig-merge_config-use-an-empty-file-as-initfile.patch
+x86-fred-fix-system-hang-during-s4-resume-with-fred-.patch
+s390-vfio-ap-fix-no-ap-queue-sharing-allowed-message.patch
+cifs-add-fallback-for-smb2-create-without-file_read_.patch
+cifs-fix-querying-and-creating-mf-symlinks-over-smb1.patch
+cifs-fix-access_flags_to_smbopen_mode.patch
+cifs-fix-negotiate-retry-functionality.patch
+smb-client-store-original-io-parameters-and-prevent-.patch
+fuse-return-eperm-rather-than-enosys-from-link.patch
+exfat-call-bh_read-in-get_block-only-when-necessary.patch
+io_uring-msg-initialise-msg-request-opcode.patch
+nfsv4-check-for-delegation-validity-in-nfs_start_del.patch
+nfs-don-t-allow-waiting-for-exiting-tasks.patch
+sunrpc-don-t-allow-waiting-for-exiting-tasks.patch
+arm64-add-support-for-hip09-spectre-bhb-mitigation.patch
+iommufd-extend-iommu_get_hw_info-to-report-pasid-cap.patch
+ring-buffer-use-kaslr-address-instead-of-text-delta.patch
+tracing-mark-binary-printing-functions-with-__printf.patch
+acpi-pnp-add-intel-oc-watchdog-ids-to-non-pnp-device.patch
+tpm-convert-warn-to-dbg-in-tpm2_start_auth_session.patch
+mailbox-pcc-use-acpi_os_ioremap-instead-of-ioremap.patch
+mailbox-use-error-ret-code-of-of_parse_phandle_with_.patch
+riscv-allow-nommu-kernels-to-access-all-of-ram.patch
+fbdev-fsl-diu-fb-add-missing-device_remove_file.patch
+fbcon-use-correct-erase-colour-for-clearing-in-fbcon.patch
+fbdev-core-tileblit-implement-missing-margin-clearin.patch
+cifs-set-default-netbios-rfc1001-server-name-to-host.patch
+cifs-add-validation-check-for-the-fields-in-smb_aces.patch
+cifs-fix-establishing-netbios-session-for-smb2-conne.patch
+cifs-fix-getting-dacl-only-xattr-system.cifs_acl-and.patch
+cifs-check-if-server-supports-reparse-points-before-.patch
+nfsv4-treat-enetunreach-errors-as-fatal-for-state-re.patch
+sunrpc-rpc_clnt_set_transport-must-not-change-the-au.patch
+sunrpc-rpcbind-should-never-reset-the-port-to-the-va.patch
+spi-rockchip-fix-register-out-of-bounds-access.patch
+asoc-codecs-wsa884x-correct-vi-sense-channel-mask.patch
+asoc-codecs-wsa883x-correct-vi-sense-channel-mask.patch
+mctp-fix-incorrect-tx-flow-invalidation-condition-in.patch
+net-tn40xx-add-pci-id-of-the-aqr105-based-tehuti-tn4.patch
+net-tn40xx-create-swnode-for-mdio-and-aqr105-phy-and.patch
+thermal-drivers-mediatek-lvts-start-sensor-interrupt.patch
+thermal-drivers-qoriq-power-down-tmu-on-system-suspe.patch
+bluetooth-btmtksdio-prevent-enabling-interrupts-afte.patch
+bluetooth-disable-sco-support-if-read_voice_setting-.patch
+exit-fix-the-usage-of-delay_group_leader-exit_code-i.patch
+risc-v-add-vector-extension-validation-checks.patch
+dql-fix-dql-limit-value-when-reset.patch
+lockdep-fix-wait-context-check-on-softirq-for-preemp.patch
+objtool-properly-disable-uaccess-validation.patch
+net-mlx5e-use-right-api-to-free-bitmap-memory.patch
+pci-dwc-ep-ensure-proper-iteration-over-outbound-map.patch
+r8169-disable-rtl8126-zrx-dc-timeout.patch
+tools-build-don-t-pass-test-log-files-to-linker.patch
+pci-xilinx-cpm-add-cpm_csr-register-mapping-for-cpm5.patch
+i2c-qcom-geni-update-i2c-frequency-table-to-match-ha.patch
+pnfs-flexfiles-report-enetdown-as-a-connection-error.patch
+drm-amdgpu-discovery-check-ip_discovery-fw-file-avai.patch
+drm-amdgpu-rework-how-the-cleaner-shader-is-emitted-.patch
+drm-amdgpu-rework-how-isolation-is-enforced-v2.patch
+drm-amdgpu-use-gfp_nowait-for-memory-allocations.patch
+drm-amdkfd-set-precise-mem-ops-caps-to-disabled-for-.patch
+pci-vmd-disable-msi-remapping-bypass-under-xen.patch
+xen-pci-do-not-register-devices-with-segments-0x1000.patch
+ext4-on-a-remount-only-log-the-ro-or-r-w-state-when-.patch
+libnvdimm-labels-fix-divide-error-in-nd_label_data_i.patch
+pidfs-improve-multi-threaded-exec-and-premature-thre.patch
+staging-vchiq_arm-create-keep-alive-thread-during-pr.patch
+mmc-host-wait-for-vdd-to-settle-on-card-power-off.patch
+drm-amdgpu-skip-pcie_replay_count-sysfs-creation-for.patch
+cgroup-rstat-avoid-disabling-irqs-for-o-num_cpu.patch
+wifi-mt76-check-link_conf-pointer-in-mt76_connac_mcu.patch
+wifi-mt76-scan-fix-setting-tx_info-fields.patch
+wifi-mt76-mt7996-implement-driver-specific-get_txpow.patch
+wifi-mt76-only-mark-tx-status-failed-frames-as-acked.patch
+wifi-mt76-mt7996-use-the-correct-vif-link-for-scanni.patch
+wifi-mt76-scan-set-vif-offchannel-link-for-scanning-.patch
+wifi-mt76-mt7996-fix-ser-reset-trigger-on-wed-reset.patch
+wifi-mt76-mt7996-revise-txs-size.patch
+wifi-mt76-mt7925-load-the-appropriate-clc-data-based.patch
+wifi-mt76-mt7925-simplify-hif-suspend-handling-to-av.patch
+wifi-mt76-mt7925-fix-fails-to-enter-low-power-mode-i.patch
+x86-headers-replace-__assembly__-with-__assembler__-.patch
+x86-headers-replace-__assembly__-with-__assembler__-.patch-7903
+x86-stackprotector-64-only-export-__ref_stack_chk_gu.patch
+x86-smpboot-fix-init-delay-assignment-for-extended-i.patch
+x86-microcode-update-the-intel-processor-flag-scan-c.patch
+x86-amd_node-add-smn-offsets-to-exclusive-region-acc.patch
+x86-mm-check-return-value-from-memblock_phys_alloc_r.patch
+i2c-qup-vote-for-interconnect-bandwidth-to-dram.patch
+i2c-amd-asf-set-cmd-variable-when-encountering-an-er.patch
+i2c-pxa-fix-call-balance-of-i2c-clk-handling-routine.patch
+btrfs-make-btrfs_discard_workfn-block_group-ref-expl.patch
+btrfs-avoid-linker-error-in-btrfs_find_create_tree_b.patch
+btrfs-run-btrfs_error_commit_super-early.patch
+btrfs-fix-non-empty-delayed-iputs-list-on-unmount-du.patch
+btrfs-properly-limit-inline-data-extent-according-to.patch
+btrfs-allow-buffered-write-to-avoid-full-page-read-i.patch
+btrfs-prevent-inline-data-extents-read-from-touching.patch
+btrfs-get-zone-unusable-bytes-while-holding-lock-at-.patch
+btrfs-send-return-enametoolong-when-attempting-a-pat.patch
+btrfs-zoned-exit-btrfs_can_activate_zone-if-btrfs_fs.patch
+blk-cgroup-improve-policy-registration-error-handlin.patch
+drm-amdgpu-release-xcp_mgr-on-exit.patch
+drm-amd-display-guard-against-setting-dispclk-low-fo.patch
+drm-amdgpu-don-t-free-conflicting-apertures-for-non-.patch
+drm-amdgpu-adjust-drm_firmware_drivers_only-handling.patch
+i3c-master-svc-fix-missing-stop-for-master-request.patch
+s390-tlb-use-mm_has_pgste-instead-of-mm_alloc_pgste.patch
+dlm-make-tcp-still-work-in-multi-link-env.patch
+loop-move-vfs_fsync-out-of-loop_update_dio.patch
+clocksource-drivers-timer-riscv-stop-stimecmp-when-c.patch
+um-store-full-csgsfs-and-ss-register-from-mcontext.patch
+um-update-min_low_pfn-to-match-changes-in-uml_reserv.patch
+net-mlx5-preserve-rate-settings-when-creating-a-rate.patch
+wifi-mwifiex-fix-ht40-bandwidth-issue.patch
+bnxt_en-query-fw-parameters-when-the-caps_change-bit.patch
+ixgbe-add-support-for-thermal-sensor-event-reception.patch
+riscv-call-secondary-mmu-notifier-when-flushing-the-.patch
+ext4-reorder-capability-check-last.patch
+hypfs_create_cpu_files-add-missing-check-for-hypfs_m.patch
+scsi-st-tighten-the-page-format-heuristics-with-mode.patch
+scsi-st-erase-does-not-change-tape-location.patch
+vfio-pci-handle-intx-irq_notconnected.patch
+bpftool-using-the-right-format-specifiers.patch
+libbpf-pass-bpf-token-from-find_prog_btf_id-to-bpf_b.patch
+bpf-return-prog-btf_id-without-capable-check.patch
+pci-dwc-use-resource-start-as-ioremap-input-in-dw_pc.patch
+jbd2-do-not-try-to-recover-wiped-journal.patch
+tcp-reorganize-tcp_in_ack_event-and-tcp_count_delive.patch
+rtc-rv3032-fix-eerd-location.patch
+objtool-fix-error-handling-inconsistencies-in-check.patch
+thunderbolt-do-not-add-non-active-nvm-if-nvm-upgrade.patch
+erofs-initialize-decompression-early.patch
+spi-spi-mux-fix-coverity-issue-unchecked-return-valu.patch
+asoc-sma1307-add-null-check-in-sma1307_setting_loade.patch
+asoc-pcm6240-drop-bogus-code-handling-irq-as-gpio.patch
+asoc-mediatek-mt6359-add-stub-for-mt6359_accdet_enab.patch
+kunit-tool-fix-bug-in-parsing-test-plan.patch
+bpf-allow-pre-ordering-for-bpf-cgroup-progs.patch
+kbuild-fix-argument-parsing-in-scripts-config.patch
+kconfig-do-not-clear-symbol_valid-when-reading-inclu.patch
+crypto-octeontx2-suppress-auth-failure-screaming-due.patch
+dm-restrict-dm-device-size-to-2-63-512-bytes.patch
+net-smc-use-the-correct-ndev-to-find-pnetid-by-pneti.patch
+xen-add-support-for-xenserver-6.1-platform-device.patch
+pinctrl-tegra-restore-sfsel-bit-when-freeing-pins.patch
+mfd-syscon-add-check-for-invalid-resource-size.patch
+mfd-tps65219-remove-tps65219_reg_ti_dev_id-check.patch
+drm-amdgpu-gfx12-don-t-read-registers-in-mqd-init.patch
+drm-amdgpu-gfx11-don-t-read-registers-in-mqd-init.patch
+drm-amdgpu-update-sriov-video-codec-caps.patch
+asoc-sun4i-codec-support-hp-det-gpios-property.patch
+asoc-sun4i-codec-correct-dapm-widgets-and-controls-f.patch
+clk-qcom-lpassaudiocc-sc7280-add-support-for-lpass-r.patch
+f2fs-defer-readonly-check-vs-norecovery.patch
+leds-kconfig-leds-st1202-add-select-for-required-led.patch
+leds-leds-st1202-initialize-hardware-before-dt-node-.patch
+ext4-reject-the-data_err-abort-option-in-nojournal-m.patch
+ext4-do-not-convert-the-unwritten-extents-if-data-wr.patch
+rdma-uverbs-propagate-errors-from-rdma_lookup_get_uo.patch
+posix-timers-add-cond_resched-to-posix_timer_add-sea.patch
+posix-timers-ensure-that-timer-initialization-is-ful.patch
+net-stmmac-dwmac-rk-validate-grf-and-peripheral-grf-.patch
+net-hsr-fix-prp-duplicate-detection.patch
+timer_list-don-t-use-pk-through-printk.patch
+wifi-rtw89-coex-fix-coexistence-report-not-show-as-e.patch
+wifi-rtw89-set-force-he-tb-mode-when-connecting-to-1.patch
+netfilter-conntrack-bound-nf_conntrack-sysctl-writes.patch
+pnp-expand-length-of-fixup-id-string.patch
+phy-rockchip-usbdp-only-verify-link-rates-lanes-volt.patch
+arm64-mm-check-pmd_table-in-pmd_trans_huge.patch
+arm64-mm-check-pud_type_table-in-pud_bad.patch
+mmc-dw_mmc-add-exynos7870-dw-mmc-support.patch
+mmc-sdhci-disable-sd-card-clock-before-changing-para.patch
+usb-xhci-don-t-change-the-status-of-stalled-tds-on-f.patch
+wifi-iwlwifi-mvm-fix-setting-the-tk-when-associated.patch
+hwmon-dell-smm-increment-the-number-of-fans.patch
+iommu-keep-dev-iommu-state-consistent.patch
+printk-check-con_suspend-when-unblanking-a-console.patch
+wifi-iwlwifi-don-t-warn-when-if-there-is-a-fw-error.patch
+wifi-iwlwifi-w-a-fw-smps-mode-selection.patch
+wifi-iwlwifi-fix-debug-actions-order.patch
+wifi-iwlwifi-mark-br-device-not-integrated.patch
+wifi-iwlwifi-fix-the-eckv-uefi-variable-name.patch
+wifi-mac80211-don-t-include-mle-in-ml-reconf-per-sta.patch
+wifi-cfg80211-update-the-link-address-when-a-link-is.patch
+wifi-mac80211-fix-warning-on-disconnect-during-faile.patch
+wifi-mac80211_hwsim-fix-mld-address-translation.patch
+wifi-mac80211-fix-u-apsd-check-in-ml-reconfiguration.patch
+wifi-cfg80211-allow-ir-in-20-mhz-configurations.patch
+r8169-increase-max-jumbo-packet-size-on-rtl8125-rtl8.patch
+ipv6-save-dontfrag-in-cork.patch
+drm-amd-display-remove-minimum-dispclk-and-apply-oem.patch
+drm-amd-display-calculate-the-remain-segments-for-al.patch
+drm-amd-display-not-abort-link-train-when-bw-is-low.patch
+drm-amd-display-fix-incorrect-dpcd-configs-while-rep.patch
+gfs2-check-for-empty-queue-in-run_queue.patch
+auxdisplay-charlcd-partially-revert-move-hwidth-and-.patch
+asoc-qcom-sm8250-explicitly-set-format-in-sm8250_be_.patch
+badblocks-fix-a-nonsense-warn_on-which-checks-whethe.patch
+block-acquire-q-limits_lock-while-reading-sysfs-attr.patch
+coresight-etb10-change-etb_drvdata-spinlock-s-type-t.patch
+coresight-change-coresight_trace_id_map-s-lock-type-.patch
+iommu-vt-d-move-scalable-mode-ats-enablement-to-prob.patch
+iommu-vt-d-check-if-sva-is-supported-when-attaching-.patch
+iommu-amd-pgtbl_v2-improve-error-handling.patch
+fs-pipe-limit-the-slots-in-pipe_resize_ring.patch
+cpufreq-tegra186-share-policy-per-cluster.patch
+watchdog-s3c2410_wdt-fix-pmu-register-bits-for-exyno.patch
+watchdog-aspeed-update-bootstatus-handling.patch
+pci-endpoint-pci-epf-test-fix-double-free-that-cause.patch
+misc-pci_endpoint_test-give-disabled-bars-a-distinct.patch
+selftests-pci_endpoint-skip-disabled-bars.patch
+crypto-lzo-fix-compression-buffer-overrun.patch
+crypto-mxs-dcp-only-set-otp_key-bit-for-otp-key.patch
+drm-amdkfd-set-per-process-flags-only-once-for-gfx9-.patch
+drm-amdkfd-set-per-process-flags-only-once-cik-vi.patch
+drm-amdkfd-clear-f8_mode-for-gfx950.patch
+drm-amdgpu-increase-ras-bad-page-threshold.patch
+drm-amdgpu-fix-missing-drain-retry-fault-the-last-en.patch
+arm64-tegra-p2597-fix-gpio-for-vdd-1v8-dis-regulator.patch
+arm64-tegra-resize-aperture-for-the-igx-pcie-c5-slot.patch
+powerpc-prom_init-fixup-missing-size-cells-on-powerb.patch
+alsa-seq-improve-data-consistency-at-polling.patch
+tcp-bring-back-numa-dispersion-in-inet_ehash_locks_a.patch
+rseq-fix-segfault-on-registration-when-rseq_cs-is-no.patch
+rtc-ds1307-stop-disabling-alarms-on-probe.patch
+ieee802154-ca8210-use-proper-setters-and-getters-for.patch
+drm-xe-nuke-vm-s-mapping-upon-close.patch
+drm-xe-retry-bo-allocation.patch
+soc-samsung-include-linux-array_size.h-where-needed.patch
+arm-tegra-switch-dsi-b-clock-parent-to-plld-on-tegra.patch
+media-c8sectpfe-call-of_node_put-i2c_bus-only-once-i.patch
+media-cec-use-us_to_ktime-where-appropriate.patch
+usb-xhci-set-page-size-to-the-xhci-supported-size.patch
+dm-cache-prevent-bug_on-by-blocking-retries-on-faile.patch
+soc-mediatek-mtk-mutex-add-dpi1-sof-eof-to-mt8188-mu.patch
+orangefs-do-not-truncate-file-size.patch
+drm-gem-test-for-imported-gem-buffers-with-helper.patch
+net-phylink-use-pl-link_interface-in-phylink_expects.patch
+blk-throttle-don-t-take-carryover-for-prioritized-pr.patch
+remoteproc-qcom_wcnss-handle-platforms-with-only-sin.patch
+drm-xe-disambiguate-gmdid-based-ip-names.patch
+drm-amdgpu-do-not-program-agp-bar-regs-under-sriov-i.patch
+drm-amdgpu-reinit-fw-shared-flags-on-vcn-v5.0.1.patch
+drm-amdgpu-add-dce_v6_0_soft_reset-to-dce6.patch
+drm-amd-display-ensure-dmcub-idle-before-reset-on-dc.patch
+drm-amd-display-skip-checking-frl_mode-bit-for-pcon-.patch
+drm-amd-display-fix-dmub-reset-sequence-for-dcn401.patch
+drm-amd-display-fix-p-state-type-when-p-state-is-uns.patch
+drm-amd-display-request-hw-cursor-on-dcn3.2-with-sub.patch
+drm-amdgpu-avoid-hdp-flush-on-jpeg-v5.0.1.patch
+drm-amdgpu-add-offset-normalization-in-vcn-v5.0.1.patch
+perf-core-clean-up-perf_try_init_event.patch
+media-cx231xx-set-device_caps-for-417.patch
+pinctrl-bcm281xx-use-unsigned-int-instead-of-bare-un.patch
+rcu-fix-get_state_synchronize_rcu_full-gp-start-dete.patch
+drm-msm-dpu-set-possible-clones-for-all-encoders.patch
+net-ethernet-ti-cpsw_new-populate-netdev-of_node.patch
+eth-fbnic-prepend-tsene-fw-fields-with-fbnic_fw.patch
+net-phy-nxp-c45-tja11xx-add-match_phy_device-to-tja1.patch
+dpll-add-an-assertion-to-check-freq_supported_num.patch
+ublk-enforce-ublks_max-only-for-unprivileged-devices.patch
+iommufd-disallow-allocating-nested-parent-domain-wit.patch
+media-imx335-set-vblank-immediately.patch
+net-pktgen-fix-mpls-maximum-labels-list-parsing.patch
+perf-core-fix-perf_mmap-failure-path.patch
+perf-hw_breakpoint-return-eopnotsupp-for-unsupported.patch
+alsa-hda-realtek-enable-pc-beep-passthrough-for-hp-e.patch
+scsi-logging-fix-scsi_logging_level-bounds.patch
+ipv4-fib-move-fib_valid_key_len-to-rtm_to_fib_config.patch
+ipv4-fib-hold-rtnl_net_lock-in-ip_rt_ioctl.patch
+drm-rockchip-vop2-add-uv-swap-for-cluster-window.patch
+block-mark-bounce-buffering-as-incompatible-with-int.patch
+null_blk-generate-null_blk-configfs-features-string.patch
+ublk-complete-command-synchronously-on-error.patch
+media-uvcvideo-add-sanity-check-to-uvc_ioctl_xu_ctrl.patch
+media-uvcvideo-handle-uvc-menu-translation-inside-uv.patch
+clk-imx8mp-inform-ccf-of-maximum-frequency-of-clocks.patch
+pm-sleep-suppress-sleeping-parent-warning-in-special.patch
+x86-bugs-make-spectre-user-default-depend-on-mitigat.patch
+hwmon-acpi_power_meter-fix-the-fake-power-alarm-repo.patch
+hwmon-gpio-fan-add-missing-mutex-locks.patch
+arm-at91-pm-fix-at91_suspend_finish-for-zq-calibrati.patch
+drm-mediatek-mtk_dpi-add-checks-for-reg_h_fre_con-ex.patch
+fpga-altera-cvp-increase-credit-timeout.patch
+perf-arm_pmuv3-call-kvm_vcpu_pmu_resync_el0-before-e.patch
+soc-apple-rtkit-use-high-prio-work-queue.patch
+soc-apple-rtkit-implement-oslog-buffers-properly.patch
+wifi-ath12k-report-proper-tx-completion-status-to-ma.patch
+pci-brcmstb-expand-inbound-window-size-up-to-64gb.patch
+pci-brcmstb-add-a-softdep-to-mip-msi-x-driver.patch
+nvme-map-uring_cmd-data-even-if-address-is-0.patch
+firmware-arm_ffa-set-dma_mask-for-ffa-devices.patch
+drm-xe-vf-retry-sending-mmio-request-to-guc-on-timeo.patch
+drm-xe-pf-create-a-link-between-pf-and-vf-devices.patch
+net-mlx5-avoid-report-two-health-errors-on-same-synd.patch
+selftests-net-have-gro.sh-t-return-a-correct-exit-co.patch
+driver-core-faux-only-create-the-device-if-probe-suc.patch
+rust-faux-add-missing-parent-argument-to-registratio.patch
+pinctrl-sophgo-avoid-to-modify-untouched-bit-when-se.patch
+drm-amdkfd-kfd-release_work-possible-circular-lockin.patch
+drm-xe-xe_gen_wa_oob-replace-program_invocation_shor.patch
+leds-pwm-multicolor-add-check-for-fwnode_property_re.patch
+accel-amdxdna-check-interrupt-register-before-mailbo.patch
+net-ethernet-mtk_ppe_offload-allow-qinq-double-eth_p.patch
+net-xgene-v2-remove-incorrect-acpi_ptr-annotation.patch
+dmaengine-ti-k3-udma-glue-drop-skip_fdq-argument-fro.patch
+wifi-rtw89-parse-channel-from-ie-to-correct-invalid-.patch
+bonding-report-duplicate-mac-address-in-all-situatio.patch
+tcp-be-less-liberal-in-tsecr-received-while-in-syn_r.patch
+pinctrl-qcom-msm8917-add-msm8937-wsa_reset-pin.patch
+wifi-ath12k-improve-bss-discovery-with-hidden-ssid-i.patch
+soc-ti-k3-socinfo-do-not-use-syscon-helper-to-build-.patch
+x86-bugs-kvm-add-support-for-srso_msr_fix.patch
+bpf-search-and-add-kfuncs-in-struct_ops-prologue-and.patch
+octeontx2-af-rpm-register-driver-with-pci-subsys-ids.patch
+x86-build-fix-broken-copy-command-in-genimage.sh-whe.patch
+drm-amd-display-handle-max_downscale_src_width-fail-.patch
+drm-amd-display-fix-dcn4x-init-failed.patch
+drm-amd-display-fix-check-for-identity-ratio.patch
+drm-amd-display-fix-mismatch-type-comparison.patch
+drm-amd-display-add-opp-recout-adjustment.patch
+drm-amd-display-fix-mismatch-type-comparison-in-cust.patch
+asoc-mediatek-mt8188-treat-dmic_gainx_cur-as-non-vol.patch
+asoc-mediatek-mt8188-add-reference-for-dmic-clocks.patch
+x86-nmi-add-an-emergency-handler-in-nmi_desc-use-it-.patch
+vhost-scsi-return-queue-full-for-page-alloc-failures.patch
+vdpa-mlx5-fix-mlx5_vdpa_get_config-endianness-on-big.patch
+cpuidle-menu-avoid-discarding-useful-information.patch
+media-adv7180-disable-test-pattern-control-on-adv718.patch
+media-tc358746-improve-calculation-of-the-d-phy-timi.patch
+net-mlx5e-add-correct-match-to-check-ipsec-syndromes.patch
+scsi-mpi3mr-update-timestamp-only-for-supervisor-ioc.patch
+loop-check-in-lo_flags_direct_io-in-loop_default_blo.patch
+net-stmmac-correct-usage-of-maximum-queue-number-mac.patch
+libbpf-fix-out-of-bound-read.patch
+virtio-break-and-reset-virtio-devices-on-device_shut.patch
+dm-fix-unconditional-io-throttle-caused-by-req_prefl.patch
+fs-mpage-avoid-negative-shift-for-large-blocksize.patch
+gpiolib-sanitize-the-return-value-of-gpio_chip-set_c.patch
+scsi-scsi_debug-first-fixes-for-tapes.patch
+bpf-arm64-silence-ubsan-negation-overflow-warning.patch
+clk-sunxi-ng-h616-reparent-gpu-clock-during-frequenc.patch
+net-mlx5-change-pool_next_size-define-value-and-make.patch
+x86-kaslr-reduce-kaslr-entropy-on-most-x86-systems.patch
+crypto-ahash-set-default-reqsize-from-ahash_alg.patch
+crypto-skcipher-zap-type-in-crypto_alloc_sync_skciph.patch
+net-ipv6-init-tunnel-link-netns-before-registering-d.patch
+rtnetlink-lookup-device-in-target-netns-when-creatin.patch
+drm-xe-oa-ensure-that-polled-read-returns-latest-dat.patch
+mips-use-arch-specific-syscall-name-match-function.patch
+drm-amdgpu-remove-all-kfd-fences-from-the-bo-on-rele.patch
+x86-mm-make-mmu_gather_rcu_table_free-unconditional.patch
+x86-locking-use-alt_output_sp-for-percpu_-try_-cmpxc.patch
+genirq-msi-store-the-iommu-iova-directly-in-msi_desc.patch
+pps-generators-replace-copy-of-pps-gen-info-struct-w.patch
+mips-pm-cps-use-per-cpu-variables-as-per-cpu-not-per.patch
+clocksource-mips-gic-timer-enable-counter-when-cpus-.patch
+pci-epf-mhi-update-device-id-for-sa8775p.patch
+scsi-mpt3sas-send-a-diag-reset-if-target-reset-fails.patch
+wifi-rtw88-fix-rtw_init_vht_cap-for-rtl8814au.patch
+wifi-rtw88-fix-rtw_init_ht_cap-for-rtl8814au.patch
+wifi-rtw88-fix-rtw_desc_to_mcsrate-to-handle-mcs16-3.patch
+wifi-rtw88-fix-rtw_mac_power_switch-for-rtl8814au.patch
+wifi-rtw89-fw-propagate-error-code-from-rtw89_h2c_tx.patch
+wifi-rtw89-fw-get-sb_sel_ver-via-get_unaligned_le32.patch
+wifi-rtw89-fw-add-blacklist-to-avoid-obsolete-secure.patch
+wifi-rtw89-8922a-fix-incorrect-sta-id-in-eht-mu-ppdu.patch
+net-pktgen-fix-access-outside-of-user-given-buffer-i.patch
+power-supply-axp20x_battery-update-temp-sensor-for-a.patch
+edac-ie31200-work-around-false-positive-build-warnin.patch
+bpf-prevent-unsafe-access-to-the-sock-fields-in-the-.patch
+i3c-master-svc-flush-fifo-before-sending-dynamic-add.patch
+netdevsim-call-napi_schedule-from-a-timer-context.patch
+mfd-axp20x-axp717-add-axp717_ts_pin_cfg-to-writeable.patch
+eeprom-ee1004-check-chip-before-probing.patch
+irqchip-riscv-imsic-separate-next-and-previous-point.patch
+drm-xe-client-skip-show_run_ticks-if-unable-to-read-.patch
+pci-pwrctrl-move-pci_pwrctrl_unregister-to-pci_destr.patch
+drm-amd-pm-fetch-current-power-limit-from-pmfw.patch
+drm-amd-display-add-support-for-disconnected-edp-str.patch
+drm-amd-display-guard-against-setting-dispclk-low-wh.patch
+drm-amd-display-fix-bt2020-ycbcr-limited-full-range-.patch
+drm-amd-display-read-lttpr-alpm-caps-during-link-cap.patch
+revert-drm-amd-display-request-hw-cursor-on-dcn3.2-w.patch
+drm-amd-display-don-t-treat-wb-connector-as-physical.patch
+serial-mctrl_gpio-split-disable_ms-into-sync-and-no_.patch
+rdma-core-fix-best-page-size-finding-when-it-can-cro.patch
+pmdomain-imx-gpcv2-use-proper-helper-for-property-de.patch
+can-c_can-use-of_property_present-to-test-existence-.patch
+bpf-don-t-do-clean_live_states-when-state-loop_entry.patch
+bpf-copy_verifier_state-should-copy-loop_entry-field.patch
+eth-mlx4-don-t-try-to-complete-xdp-frames-in-netpoll.patch
+pci-fix-old_size-lower-bound-in-calculate_iosize-too.patch
+acpi-hed-always-initialize-before-evged.patch
+vxlan-join-leave-mc-group-after-remote-changes.patch
+x86-relocs-handle-r_x86_64_rex_gotpcrelx-relocations.patch
+x86-boot-disable-stack-protector-for-early-boot-code.patch
+posix-timers-invoke-cond_resched-during-exit_itimers.patch
+hrtimers-replace-hrtimer_clock_to_base_table-with-sw.patch
+irqchip-riscv-imsic-set-irq_set_affinity-for-imsic-b.patch
+media-test-drivers-vivid-don-t-call-schedule-in-loop.patch
+bpf-make-every-prog-keep-a-copy-of-ctx_arg_info.patch
+net-mlx5-modify-lsb-bitmask-in-temperature-event-to-.patch
+net-mlx5-apply-rate-limiting-to-high-temperature-war.patch
+firmware-arm_ffa-reject-higher-major-version-as-inco.patch
+firmware-arm_ffa-handle-the-presence-of-host-partiti.patch
+firmware-xilinx-dont-send-linux-address-to-get-fpga-.patch
+io_uring-use-io_req_link_flags-more.patch
+io_uring-sanitise-ring-params-earlier.patch
+asoc-ops-enforce-platform-maximum-on-initial-value.patch
+asoc-tas2764-add-reg-defaults-for-tas2764_int_clk_cf.patch
+asoc-tas2764-mark-sw_reset-as-volatile.patch
+asoc-tas2764-power-up-down-amp-on-mute-ops.patch
+asoc-soc-dai-check-return-value-at-snd_soc_dai_set_t.patch
+pinctrl-devicetree-do-not-goto-err-when-probing-hogs.patch
+smack-recognize-ipv4-cipso-w-o-categories.patch
+drm-xe-pf-release-all-vfs-configs-on-device-removal.patch
+smack-revert-smackfs-added-check-catlen.patch
+kunit-tool-use-qboot-on-qemu-x86_64.patch
+kernfs-don-t-re-lock-kernfs_root-kernfs_rwsem-in-ker.patch
+kernfs-acquire-kernfs_rwsem-in-kernfs_node_dentry.patch
+kernfs-acquire-kernfs_rwsem-in-kernfs_get_parent_den.patch
+kernfs-acquire-kernfs_rwsem-in-kernfs_notify_workfn.patch
+media-i2c-imx219-correct-the-minimum-vblanking-value.patch
+media-v4l-memset-argument-to-0-before-calling-get_mb.patch
+media-stm32-csi-use-array_size-to-search-d-phy-table.patch
+media-stm32-csi-add-missing-pm_runtime_put-on-error.patch
+media-i2c-ov2740-free-control-handler-on-error-path.patch
+libbpf-fix-ldx-stx-st-co-re-relocation-size-adjustme.patch
+bnxt_en-set-npar-1.2-support-when-registering-with-f.patch
+net-mlx4_core-avoid-impossible-mlx4_db_alloc-order-v.patch
+drm-xe-stop-ignoring-errors-from-xe_ttm_stolen_mgr_i.patch
+drm-xe-fix-xe_tile_init_noalloc-error-propagation.patch
+clk-qcom-ipq5018-allow-it-to-be-bulid-on-arm32.patch
+accel-amdxdna-refactor-hardware-context-destroy-rout.patch
+clk-qcom-clk-alpha-pll-do-not-use-random-stack-value.patch
+drm-xe-debugfs-fixed-the-return-value-of-wedged_mode.patch
+drm-xe-debugfs-add-missing-xe_pm_runtime_put-in-wedg.patch
+x86-ibt-handle-fineibt-in-handle_cfi_failure.patch
+x86-traps-cleanup-and-robustify-decode_bug.patch
+x86-boot-mark-start_secondary-with-__noendbr.patch
+sched-reduce-the-default-slice-to-avoid-tasks-gettin.patch
+serial-sh-sci-update-the-suspend-resume-support.patch
+pinctrl-renesas-rzg2l-add-suspend-resume-support-for.patch
+drm-xe-display-remove-hpd-cancel-work-sync-from-runt.patch
+phy-phy-rockchip-samsung-hdptx-swap-the-definitions-.patch
+phy-core-don-t-require-set_mode-callback-for-phy_get.patch
+phy-exynos5-usbdrd-fix-eds-distribution-tuning-gs101.patch
+soundwire-amd-change-the-soundwire-wake-enable-disab.patch
+soundwire-cadence_master-set-frame-shape-and-divider.patch
+jbd2-avoid-long-replay-times-due-to-high-number-or-r.patch
+net-stmmac-dwmac-loongson-set-correct-tx-rx-_fifo_si.patch
+scsi-usb-rename-the-reserve-and-release-constants.patch
+drm-amdgpu-mes11-fix-set_hw_resources_1-calculation.patch
+drm-amdkfd-fix-missing-l2-cache-info-in-topology.patch
+drm-amdgpu-set-snoop-bit-for-sdma-for-mi-series.patch
+drm-amd-display-pass-calculated-dram_speed_mts-to-dm.patch
+drm-amd-display-remove-tf-check-for-lls-policy.patch
+drm-amd-display-don-t-try-aux-transactions-on-discon.patch
+drm-amdgpu-reset-psp-cmd-to-null-after-releasing-the.patch
+drm-amd-pm-skip-p2s-load-for-smu-v13.0.12.patch
+drm-amd-display-support-multiple-options-during-psr-.patch
+revert-drm-amd-display-exit-idle-optimizations-befor.patch
+drm-amd-display-fixes-for-mcache-programming-in-dml2.patch
+drm-amd-display-ammend-dcpg-ip-control-sequences-to-.patch
+drm-amd-display-account-for-oto-prefetch-bandwidth-w.patch
+drm-amd-display-update-cr-aux-rd-interval-interpreta.patch
+drm-amd-display-initial-psr_version-with-correct-set.patch
+drm-amdgpu-gfx10-add-cleaner-shader-for-gfx10.1.10.patch
+drm-amdgpu-skip-err_count-sysfs-creation-on-vf-unsup.patch
+amdgpu-soc15-enable-asic-reset-for-dgpu-in-case-of-s.patch
+drm-amd-display-reverse-the-visual-confirm-recouts.patch
+drm-amd-display-increase-block_sequence-array-size.patch
+drm-amd-display-use-nominal-vblank-if-provided-inste.patch
+drm-amd-display-populate-register-address-for-dentis.patch
+drm-amdgpu-use-active-umc-info-from-discovery.patch
+drm-amdgpu-enlarge-the-vbios-binary-size-limit.patch
+drm-amdkfd-have-kfd-driver-use-same-pasid-values-fro.patch
+drm-amd-display-dm-drop-hw_support-check-in-amdgpu_d.patch
+scsi-target-spc-fix-loop-traversal-in-spc_rsoc_get_d.patch
+net-mlx5-xdp-enable-tx-side-xdp-multi-buffer-support.patch
+net-mlx5-extend-ethtool-loopback-selftest-to-support.patch
+net-mlx5e-set-the-tx_queue_len-for-pfifo_fast.patch
+net-mlx5e-reduce-rep-rxq-depth-to-256-for-ecpf.patch
+net-mlx5e-reduce-the-max-log-mpwrq-sz-for-ecpf-and-r.patch
+drm-v3d-add-clock-handling.patch
+xfrm-prevent-high-seq-input-in-non-esn-mode.patch
+iio-adc-ad7606-protect-register-access.patch
+wifi-ath12k-enable-mlo-setup-ready-and-teardown-comm.patch
+wifi-ath12k-use-arvif-instead-of-link_conf-in-ath12k.patch
+wifi-ath12k-fix-the-ampdu-id-fetch-in-the-hal_rx_mpd.patch
+wifi-ath12k-update-the-peer-id-in-ppdu-end-user-stat.patch
+mptcp-pm-userspace-flags-clearer-msg-if-no-remote-ad.patch
+wifi-iwlwifi-use-correct-imr-dump-variable.patch
+wifi-iwlwifi-don-t-warn-during-reprobe.patch
+wifi-mac80211-always-send-max-agg-subframe-num-in-st.patch
+wifi-mac80211-don-t-unconditionally-call-drv_mgd_com.patch
+wifi-mac80211-remove-misplaced-drv_mgd_complete_tx-c.patch
+wifi-mac80211-set-ieee80211_prep_tx_info-link_id-upo.patch
+wifi-mac80211-add-ht-and-vht-basic-set-verification.patch
+wifi-mac80211-drop-cooked-monitor-support.patch
+net-fec-refactor-mac-reset-to-function.patch
+powerpc-pseries-iommu-memory-notifier-incorrectly-ad.patch
+powerpc-pseries-iommu-create-ddw-for-devices-with-dm.patch
+arch-powerpc-perf-check-the-instruction-type-before-.patch
+ip-fib_rules-fetch-net-from-fib_rule-in-fib-46-_rule.patch
+r8152-add-vendor-device-id-pair-for-dell-alienware-a.patch
+s390-crash-use-note-name-macros.patch
+iio-adc-ad7944-don-t-use-storagebits-for-sizing.patch
+igc-avoid-unnecessary-link-down-event-in-xdp_setup_p.patch
+pstore-change-kmsg_bytes-storage-size-to-u32.patch
+leds-trigger-netdev-configure-led-blink-interval-for.patch
+net-ethtool-prevent-flow-steering-to-rss-contexts-wh.patch
+ext4-don-t-write-back-data-before-punch-hole-in-nojo.patch
+ext4-remove-writable-userspace-mappings-before-trunc.patch
+wifi-rtw88-fix-rtw_update_sta_info-for-rtl8814au.patch
+wifi-rtw88-extend-rtw_fw_send_ra_info-for-rtl8814au.patch
+wifi-rtw88-fix-download_firmware_validate-for-rtl881.patch
+wifi-rtw88-fix-__rtw_download_firmware-for-rtl8814au.patch
+wifi-rtw89-coex-assign-value-over-than-0-to-avoid-fi.patch
+wifi-rtw89-fw-validate-multi-firmware-header-before-.patch
+wifi-rtw89-fw-validate-multi-firmware-header-before-.patch-7297
+wifi-rtw89-call-power_on-ahead-before-selecting-firm.patch
+iio-dac-ad3552r-hs-use-instruction-mode-for-configur.patch
+iio-dac-adi-axi-dac-add-bus-mode-setup.patch
+clk-qcom-camcc-sm8250-use-clk_rcg2_shared_ops-for-so.patch
+netdevsim-allow-normal-queue-reset-while-down.patch
+net-page_pool-avoid-false-positive-warning-if-napi-w.patch
+tools-power-turbostat-clustered-uncore-mhz-counters-.patch
+hwmon-xgene-hwmon-use-appropriate-type-for-the-laten.patch
+drm-xe-fix-pvc-rpe-and-rpa-information.patch
+f2fs-introduce-f2fs_base_attr-for-global-sysfs-entri.patch
+media-qcom-camss-csid-only-add-tpg-v4l2-ctrl-if-tpg-.patch
+media-qcom-camss-add-default-case-in-vfe_src_pad_cod.patch
+drm-rockchip-vop2-improve-display-modes-handling-on-.patch
+eth-fbnic-set-iff_unicast_flt-to-avoid-enabling-prom.patch
+tools-ynl-gen-don-t-output-external-constants.patch
+net-mlx5e-avoid-warn_on-when-configuring-mqprio-with.patch
+cpufreq-amd-pstate-remove-unnecessary-driver_lock-in.patch
+vxlan-annotate-fdb-data-races.patch
+ipv4-ip_gre-fix-set-but-not-used-warning-in-ipgre_er.patch
+r8169-don-t-scan-phy-addresses-0.patch
+net-flush_backlog-small-changes.patch
+bridge-mdb-allow-replace-of-a-host-joined-group.patch
+ice-init-flow-director-before-rdma.patch
+ice-treat-dyn_allowed-only-as-suggestion.patch
+rcu-handle-quiescent-states-for-preempt_rcu-n-preemp.patch
+rcu-handle-unstable-rdp-in-rcu_read_unlock_strict.patch
+rcu-fix-header-guard-for-rcu_all_qs.patch
+perf-avoid-the-read-if-the-count-is-already-updated.patch
+ice-count-combined-queues-using-rx-tx-count.patch
+drm-xe-relay-don-t-use-gfp_kernel-for-new-transactio.patch
+net-mana-fix-warning-in-the-writer-of-client-oob.patch
+scsi-lpfc-handle-duplicate-d_ids-in-ndlp-search-by-d.patch
+scsi-lpfc-ignore-ndlp-rport-mismatch-in-dev_loss_tmo.patch
+scsi-lpfc-free-phba-irq-in-lpfc_sli4_enable_msi-when.patch
+scsi-lpfc-reduce-log-message-generation-during-els-r.patch
+scsi-st-restore-some-drive-settings-after-reset.patch
+wifi-ath12k-avoid-napi_sync-before-napi_enable.patch
+hid-usbkbd-fix-the-bit-shift-number-for-led_kana.patch
+arm64-zynqmp-add-clock-output-names-property-in-cloc.patch
+asoc-codecs-pcm3168a-allow-for-24-bit-in-provider-mo.patch
+asoc-rt722-sdca-add-some-missing-readable-registers.patch
+irqchip-riscv-aplic-add-support-for-hart-indexes.patch
+dm-vdo-vio-pool-allow-variable-sized-metadata-vios.patch
+dm-vdo-indexer-prevent-unterminated-string-warning.patch
+dm-vdo-use-a-short-static-string-for-thread-name-pre.patch
+drm-ast-find-vbios-mode-from-regular-display-size.patch
+bpf-use-kallsyms-to-find-the-function-name-of-a-stru.patch
+bpftool-fix-readlink-usage-in-get_fd_type.patch
+firmware-arm_scmi-relax-duplicate-name-constraint-ac.patch
+perf-amd-ibs-fix-perf_ibs_op.cnt_mask-for-curcnt.patch
+perf-amd-ibs-fix-config-to-sample-period-calculation.patch
+clk-renesas-rzg2l-cpg-refactor-runtime-pm-clock-vali.patch
+wifi-rtl8xxxu-retry-firmware-download-on-error.patch
+wifi-rtw88-don-t-use-static-local-variable-in-rtw882.patch
+wifi-rtw89-add-wiphy_lock-to-work-that-isn-t-held-wi.patch
+spi-zynqmp-gqspi-always-acknowledge-interrupts.patch
+regulator-ad5398-add-device-tree-support.patch
+wifi-ath12k-fix-ath12k_hal_tx_cmd_ext_desc_setup-inf.patch
+accel-qaic-mask-out-sr-iov-pci-resources.patch
+drm-xe-pf-reset-guc-vf-config-when-unprovisioning-cr.patch
+wifi-ath9k-return-by-of_get_mac_address.patch
+wifi-ath12k-fetch-regdb.bin-file-from-board-2.bin.patch
+drm-xe-pf-move-vfs-reprovisioning-to-worker.patch
+wifi-ath12k-fix-end-offset-bit-definition-in-monitor.patch
+wifi-ath12k-report-station-mode-receive-rate-for-iee.patch
+wifi-ath12k-report-station-mode-transmit-rate.patch
+drm-bridge-adv7511-fill-stream-capabilities.patch
+drm-nouveau-fix-the-broken-marco-gsp_msg_max_size.patch
+wifi-ath11k-use-dma_alloc_noncoherent-for-rx_tid-buf.patch
+drm-ast-hide-gens-1-to-3-tx-detection-in-branch.patch
+drm-xe-move-suballocator-init-to-after-display-init.patch
+drm-xe-do-not-attempt-to-bootstrap-vf-in-execlists-m.patch
+wifi-rtw89-coex-separated-wi-fi-connecting-event-fro.patch
+wifi-rtw89-coex-add-protect-to-avoid-a2dp-lag-while-.patch
+drm-xe-sa-always-call-drm_suballoc_manager_fini.patch
+drm-xe-vf-perform-early-gt-mmio-initialization-to-re.patch
+drm-xe-always-setup-gt-mmio-adjustment-data.patch
+drm-xe-guc-drop-error-messages-about-missing-guc-log.patch
+drm-xe-reject-bo-eviction-if-bo-is-bound-to-current-.patch
+drm-atomic-clarify-the-rules-around-drm_atomic_state.patch
+drm-buddy-fix-issue-that-force_merge-cannot-free-all.patch
+drm-xe-add-locks-in-gtidle-code.patch
+drm-panel-edp-add-starry-116khd024006.patch
+drm-add-valid-clones-check.patch
+i3c-master-svc-fix-implicit-fallthrough-in-svc_i3c_m.patch
+asoc-sma1307-fix-error-handling-in-sma1307_setting_l.patch
+pinctrl-tegra-fix-off-by-one-in-tegra_pinctrl_get_gr.patch
+watchdog-aspeed-fix-64-bit-division.patch
+drm-amdkfd-correct-f8_mode-for-gfx950.patch
+drm-gem-internally-test-import_attach-for-imported-o.patch
+virtgpu-don-t-reset-on-shutdown.patch
+x86-mm-init-handle-the-special-case-of-device-privat.patch
+bpf-abort-verification-if-env-cur_state-loop_entry-n.patch
+ipv6-remove-leftover-ip6-cookie-initializer.patch
+kernfs-use-rcu-to-access-kernfs_node-parent.patch
+kernfs-use-rcu-to-access-kernfs_node-name.patch
+kernfs-drop-kernfs_rwsem-while-invoking-lookup_posit.patch
+serial-sh-sci-save-and-restore-more-registers.patch
+drm-amd-display-exit-idle-optimizations-before-acces.patch
+drm-amdkfd-fix-error-handling-for-missing-pasid-in-k.patch
+drm-amdkfd-fix-pasid-value-leak.patch
+wifi-mac80211-add-counter-for-all-monitor-interfaces.patch
+hid-kconfig-add-leds_class_multicolor-dependency-to-.patch
+net-sysfs-restore-behavior-for-not-running-devices.patch
+asoc-imx-card-adjust-over-allocation-of-memory-in-im.patch
+book3s64-radix-fix-compile-errors-when-config_arch_w.patch
+pinctrl-meson-define-the-pull-up-down-resistor-value.patch
+smb-server-smb2pdu-check-return-value-of-xa_store.patch
+platform-x86-intel-hid-add-pantherlake-support.patch
+platform-x86-asus-wmi-disable-oobe-state-after-resum.patch
+platform-x86-ideapad-laptop-add-support-for-some-new.patch
+asoc-cs42l43-disable-headphone-clamps-during-type-de.patch
+asoc-intel-bytcr_rt5640-add-dmi-quirk-for-acer-aspir.patch
+alsa-hda-realtek-add-quirk-for-hp-spectre-x360-15-df.patch
+drm-ttm-fix-the-warning-for-hit_low-and-evict_low.patch
+nvme-pci-add-quirks-for-device-126f-1001.patch
+nvme-pci-add-quirks-for-wdc-blue-sn550-15b7-5009.patch
+alsa-usb-audio-fix-duplicated-name-in-midi-substream.patch
+nvmet-tcp-don-t-restore-null-sk_state_change.patch
+io_uring-fdinfo-annotate-racy-sq-cq-head-tail-reads.patch
+cifs-fix-and-improve-cifs_query_path_info-and-cifs_q.patch
+cifs-fix-changing-times-and-read-only-attr-over-smb1.patch
+asoc-intel-sdw_utils-add-volume-limit-to-cs42l43-spe.patch
+asoc-intel-sdw_utils-add-volume-limit-to-cs35l56-spe.patch
+iio-accel-fxls8962af-fix-wakeup-source-leaks-on-devi.patch
+iio-adc-qcom-spmi-iadc-fix-wakeup-source-leaks-on-de.patch
+iio-imu-st_lsm6dsx-fix-wakeup-source-leaks-on-device.patch
+btrfs-compression-adjust-cb-compressed_folios-alloca.patch
+btrfs-correct-the-order-of-prelim_ref-arguments-in-b.patch
+btrfs-handle-empty-eb-folios-in-num_extent_folios.patch
+btrfs-avoid-null-pointer-dereference-if-no-valid-csu.patch
+tools-ynl-gen-validate-0-len-strings-from-kernel.patch
+block-only-update-request-sector-if-needed.patch
+wifi-iwlwifi-add-support-for-killer-on-mtl.patch
+x86-kconfig-make-cfi_auto_default-depend-on-rust-or-.patch
+xenbus-allow-pvh-dom0-a-non-local-xenstore.patch
+drm-amd-display-call-fp-protect-before-mode-programm.patch
+__legitimize_mnt-check-for-mnt_sync_umount-should-be.patch
--- /dev/null
+From 58bcca60bee859857e868dc29ab80b343f64e609 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 17 Jan 2025 02:40:34 +0300
+Subject: smack: recognize ipv4 CIPSO w/o categories
+
+From: Konstantin Andreev <andreev@swemel.ru>
+
+[ Upstream commit a158a937d864d0034fea14913c1f09c6d5f574b8 ]
+
+If SMACK label has CIPSO representation w/o categories, e.g.:
+
+| # cat /smack/cipso2
+| foo 10
+| @ 250/2
+| ...
+
+then SMACK does not recognize such CIPSO in input ipv4 packets
+and substitues '*' label instead. Audit records may look like
+
+| lsm=SMACK fn=smack_socket_sock_rcv_skb action=denied
+| subject="*" object="_" requested=w pid=0 comm="swapper/1" ...
+
+This happens in two steps:
+
+1) security/smack/smackfs.c`smk_set_cipso
+ does not clear NETLBL_SECATTR_MLS_CAT
+ from (struct smack_known *)skp->smk_netlabel.flags
+ on assigning CIPSO w/o categories:
+
+| rcu_assign_pointer(skp->smk_netlabel.attr.mls.cat, ncats.attr.mls.cat);
+| skp->smk_netlabel.attr.mls.lvl = ncats.attr.mls.lvl;
+
+2) security/smack/smack_lsm.c`smack_from_secattr
+ can not match skp->smk_netlabel with input packet's
+ struct netlbl_lsm_secattr *sap
+ because sap->flags have not NETLBL_SECATTR_MLS_CAT (what is correct)
+ but skp->smk_netlabel.flags have (what is incorrect):
+
+| if ((sap->flags & NETLBL_SECATTR_MLS_CAT) == 0) {
+| if ((skp->smk_netlabel.flags &
+| NETLBL_SECATTR_MLS_CAT) == 0)
+| found = 1;
+| break;
+| }
+
+This commit sets/clears NETLBL_SECATTR_MLS_CAT in
+skp->smk_netlabel.flags according to the presense of CIPSO categories.
+The update of smk_netlabel is not atomic, so input packets processing
+still may be incorrect during short time while update proceeds.
+
+Signed-off-by: Konstantin Andreev <andreev@swemel.ru>
+Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ security/smack/smackfs.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
+index 357188f764ce1..d8f9922804974 100644
+--- a/security/smack/smackfs.c
++++ b/security/smack/smackfs.c
+@@ -915,6 +915,10 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf,
+ if (rc >= 0) {
+ old_cat = skp->smk_netlabel.attr.mls.cat;
+ rcu_assign_pointer(skp->smk_netlabel.attr.mls.cat, ncats.attr.mls.cat);
++ if (ncats.attr.mls.cat)
++ skp->smk_netlabel.flags |= NETLBL_SECATTR_MLS_CAT;
++ else
++ skp->smk_netlabel.flags &= ~(u32)NETLBL_SECATTR_MLS_CAT;
+ skp->smk_netlabel.attr.mls.lvl = ncats.attr.mls.lvl;
+ synchronize_rcu();
+ netlbl_catmap_free(old_cat);
+--
+2.39.5
+
--- /dev/null
+From 284ccaa27fe76bf1b326429b71014a6e8029361b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 17 Jan 2025 02:40:33 +0300
+Subject: smack: Revert "smackfs: Added check catlen"
+
+From: Konstantin Andreev <andreev@swemel.ru>
+
+[ Upstream commit c7fb50cecff9cad19fdac5b37337eae4e42b94c7 ]
+
+This reverts commit ccfd889acb06eab10b98deb4b5eef0ec74157ea0
+
+The indicated commit
+* does not describe the problem that change tries to solve
+* has programming issues
+* introduces a bug: forever clears NETLBL_SECATTR_MLS_CAT
+ in (struct smack_known *)skp->smk_netlabel.flags
+
+Reverting the commit to reapproach original problem
+
+Signed-off-by: Konstantin Andreev <andreev@swemel.ru>
+Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ security/smack/smackfs.c | 17 +++--------------
+ 1 file changed, 3 insertions(+), 14 deletions(-)
+
+diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
+index d8f9922804974..a7886cfc9dc3a 100644
+--- a/security/smack/smackfs.c
++++ b/security/smack/smackfs.c
+@@ -812,7 +812,7 @@ static int smk_open_cipso(struct inode *inode, struct file *file)
+ static ssize_t smk_set_cipso(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos, int format)
+ {
+- struct netlbl_lsm_catmap *old_cat, *new_cat = NULL;
++ struct netlbl_lsm_catmap *old_cat;
+ struct smack_known *skp;
+ struct netlbl_lsm_secattr ncats;
+ char mapcatset[SMK_CIPSOLEN];
+@@ -899,19 +899,8 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf,
+
+ smack_catset_bit(cat, mapcatset);
+ }
+- ncats.flags = 0;
+- if (catlen == 0) {
+- ncats.attr.mls.cat = NULL;
+- ncats.attr.mls.lvl = maplevel;
+- new_cat = netlbl_catmap_alloc(GFP_ATOMIC);
+- if (new_cat)
+- new_cat->next = ncats.attr.mls.cat;
+- ncats.attr.mls.cat = new_cat;
+- skp->smk_netlabel.flags &= ~(1U << 3);
+- rc = 0;
+- } else {
+- rc = smk_netlbl_mls(maplevel, mapcatset, &ncats, SMK_CIPSOLEN);
+- }
++
++ rc = smk_netlbl_mls(maplevel, mapcatset, &ncats, SMK_CIPSOLEN);
+ if (rc >= 0) {
+ old_cat = skp->smk_netlabel.attr.mls.cat;
+ rcu_assign_pointer(skp->smk_netlabel.attr.mls.cat, ncats.attr.mls.cat);
+--
+2.39.5
+
--- /dev/null
+From c7211a2fdb101bc160fe645622db54ba67bf2a52 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 31 Mar 2025 21:33:14 +0800
+Subject: smb: client: Store original IO parameters and prevent zero IO sizes
+
+From: Wang Zhaolong <wangzhaolong1@huawei.com>
+
+[ Upstream commit 287906b20035a04a234d1a3c64f760a5678387be ]
+
+During mount option processing and negotiation with the server, the
+original user-specified rsize/wsize values were being modified directly.
+This makes it impossible to recover these values after a connection
+reset, leading to potential degraded performance after reconnection.
+
+The other problem is that When negotiating read and write sizes, there are
+cases where the negotiated values might calculate to zero, especially
+during reconnection when server->max_read or server->max_write might be
+reset. In general, these values come from the negotiation response.
+According to MS-SMB2 specification, these values should be at least 65536
+bytes.
+
+This patch improves IO parameter handling:
+
+1. Adds vol_rsize and vol_wsize fields to store the original user-specified
+ values separately from the negotiated values
+2. Uses got_rsize/got_wsize flags to determine if values were
+ user-specified rather than checking for non-zero values, which is more
+ reliable
+3. Adds a prevent_zero_iosize() helper function to ensure IO sizes are
+ never negotiated down to zero, which could happen in edge cases like
+ when server->max_read/write is zero
+
+The changes make the CIFS client more resilient to unusual server
+responses and reconnection scenarios, preventing potential failures
+when IO sizes are calculated to be zero.
+
+Signed-off-by: Wang Zhaolong <wangzhaolong1@huawei.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/client/fs_context.c | 2 ++
+ fs/smb/client/fs_context.h | 3 +++
+ fs/smb/client/smb1ops.c | 6 +++---
+ fs/smb/client/smb2ops.c | 27 +++++++++++++++++++--------
+ fs/smb/common/smb2pdu.h | 3 +++
+ 5 files changed, 30 insertions(+), 11 deletions(-)
+
+diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c
+index e38521a713a6b..00af8dd5aa689 100644
+--- a/fs/smb/client/fs_context.c
++++ b/fs/smb/client/fs_context.c
+@@ -1327,6 +1327,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
+ case Opt_rsize:
+ ctx->rsize = result.uint_32;
+ ctx->got_rsize = true;
++ ctx->vol_rsize = ctx->rsize;
+ break;
+ case Opt_wsize:
+ ctx->wsize = result.uint_32;
+@@ -1342,6 +1343,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
+ ctx->wsize, PAGE_SIZE);
+ }
+ }
++ ctx->vol_wsize = ctx->wsize;
+ break;
+ case Opt_acregmax:
+ if (result.uint_32 > CIFS_MAX_ACTIMEO / HZ) {
+diff --git a/fs/smb/client/fs_context.h b/fs/smb/client/fs_context.h
+index 881bfc08667e7..7516ccdc69c71 100644
+--- a/fs/smb/client/fs_context.h
++++ b/fs/smb/client/fs_context.h
+@@ -279,6 +279,9 @@ struct smb3_fs_context {
+ bool use_client_guid:1;
+ /* reuse existing guid for multichannel */
+ u8 client_guid[SMB2_CLIENT_GUID_SIZE];
++ /* User-specified original r/wsize value */
++ unsigned int vol_rsize;
++ unsigned int vol_wsize;
+ unsigned int bsize;
+ unsigned int rasize;
+ unsigned int rsize;
+diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c
+index e28cdaca47e12..73a689b4ccdff 100644
+--- a/fs/smb/client/smb1ops.c
++++ b/fs/smb/client/smb1ops.c
+@@ -437,8 +437,8 @@ cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
+ unsigned int wsize;
+
+ /* start with specified wsize, or default */
+- if (ctx->wsize)
+- wsize = ctx->wsize;
++ if (ctx->got_wsize)
++ wsize = ctx->vol_wsize;
+ else if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_WRITE_CAP))
+ wsize = CIFS_DEFAULT_IOSIZE;
+ else
+@@ -490,7 +490,7 @@ cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
+ else
+ defsize = server->maxBuf - sizeof(READ_RSP);
+
+- rsize = ctx->rsize ? ctx->rsize : defsize;
++ rsize = ctx->got_rsize ? ctx->vol_rsize : defsize;
+
+ /*
+ * no CAP_LARGE_READ_X? Then MS-CIFS states that we must limit this to
+diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
+index 6f89e087629fe..6795970d4de6e 100644
+--- a/fs/smb/client/smb2ops.c
++++ b/fs/smb/client/smb2ops.c
+@@ -467,6 +467,17 @@ smb2_negotiate(const unsigned int xid,
+ return rc;
+ }
+
++static inline unsigned int
++prevent_zero_iosize(unsigned int size, const char *type)
++{
++ if (size == 0) {
++ cifs_dbg(VFS, "SMB: Zero %ssize calculated, using minimum value %u\n",
++ type, CIFS_MIN_DEFAULT_IOSIZE);
++ return CIFS_MIN_DEFAULT_IOSIZE;
++ }
++ return size;
++}
++
+ static unsigned int
+ smb2_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
+ {
+@@ -474,12 +485,12 @@ smb2_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
+ unsigned int wsize;
+
+ /* start with specified wsize, or default */
+- wsize = ctx->wsize ? ctx->wsize : CIFS_DEFAULT_IOSIZE;
++ wsize = ctx->got_wsize ? ctx->vol_wsize : CIFS_DEFAULT_IOSIZE;
+ wsize = min_t(unsigned int, wsize, server->max_write);
+ if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
+ wsize = min_t(unsigned int, wsize, SMB2_MAX_BUFFER_SIZE);
+
+- return wsize;
++ return prevent_zero_iosize(wsize, "w");
+ }
+
+ static unsigned int
+@@ -489,7 +500,7 @@ smb3_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
+ unsigned int wsize;
+
+ /* start with specified wsize, or default */
+- wsize = ctx->wsize ? ctx->wsize : SMB3_DEFAULT_IOSIZE;
++ wsize = ctx->got_wsize ? ctx->vol_wsize : SMB3_DEFAULT_IOSIZE;
+ wsize = min_t(unsigned int, wsize, server->max_write);
+ #ifdef CONFIG_CIFS_SMB_DIRECT
+ if (server->rdma) {
+@@ -511,7 +522,7 @@ smb3_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
+ if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
+ wsize = min_t(unsigned int, wsize, SMB2_MAX_BUFFER_SIZE);
+
+- return wsize;
++ return prevent_zero_iosize(wsize, "w");
+ }
+
+ static unsigned int
+@@ -521,13 +532,13 @@ smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
+ unsigned int rsize;
+
+ /* start with specified rsize, or default */
+- rsize = ctx->rsize ? ctx->rsize : CIFS_DEFAULT_IOSIZE;
++ rsize = ctx->got_rsize ? ctx->vol_rsize : CIFS_DEFAULT_IOSIZE;
+ rsize = min_t(unsigned int, rsize, server->max_read);
+
+ if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
+ rsize = min_t(unsigned int, rsize, SMB2_MAX_BUFFER_SIZE);
+
+- return rsize;
++ return prevent_zero_iosize(rsize, "r");
+ }
+
+ static unsigned int
+@@ -537,7 +548,7 @@ smb3_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
+ unsigned int rsize;
+
+ /* start with specified rsize, or default */
+- rsize = ctx->rsize ? ctx->rsize : SMB3_DEFAULT_IOSIZE;
++ rsize = ctx->got_rsize ? ctx->vol_rsize : SMB3_DEFAULT_IOSIZE;
+ rsize = min_t(unsigned int, rsize, server->max_read);
+ #ifdef CONFIG_CIFS_SMB_DIRECT
+ if (server->rdma) {
+@@ -560,7 +571,7 @@ smb3_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
+ if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
+ rsize = min_t(unsigned int, rsize, SMB2_MAX_BUFFER_SIZE);
+
+- return rsize;
++ return prevent_zero_iosize(rsize, "r");
+ }
+
+ /*
+diff --git a/fs/smb/common/smb2pdu.h b/fs/smb/common/smb2pdu.h
+index 12f0013334057..f79a5165a7cc6 100644
+--- a/fs/smb/common/smb2pdu.h
++++ b/fs/smb/common/smb2pdu.h
+@@ -95,6 +95,9 @@
+ */
+ #define SMB3_DEFAULT_IOSIZE (4 * 1024 * 1024)
+
++/* According to MS-SMB2 specification The minimum recommended value is 65536.*/
++#define CIFS_MIN_DEFAULT_IOSIZE (65536)
++
+ /*
+ * SMB2 Header Definition
+ *
+--
+2.39.5
+
--- /dev/null
+From ae258004247523f3ca610dda51f9843c2c707423 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 16 Apr 2025 20:26:25 +0100
+Subject: smb: server: smb2pdu: check return value of xa_store()
+
+From: Salah Triki <salah.triki@gmail.com>
+
+[ Upstream commit af5226abb40cae959f424f7ca614787a1c87ce48 ]
+
+xa_store() may fail so check its return value and return error code if
+error occurred.
+
+Signed-off-by: Salah Triki <salah.triki@gmail.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/smb2pdu.c | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
+index c2603c398a467..f2a2be8467c66 100644
+--- a/fs/smb/server/smb2pdu.c
++++ b/fs/smb/server/smb2pdu.c
+@@ -1450,7 +1450,7 @@ static int ntlm_authenticate(struct ksmbd_work *work,
+ {
+ struct ksmbd_conn *conn = work->conn;
+ struct ksmbd_session *sess = work->sess;
+- struct channel *chann = NULL;
++ struct channel *chann = NULL, *old;
+ struct ksmbd_user *user;
+ u64 prev_id;
+ int sz, rc;
+@@ -1562,7 +1562,12 @@ static int ntlm_authenticate(struct ksmbd_work *work,
+ return -ENOMEM;
+
+ chann->conn = conn;
+- xa_store(&sess->ksmbd_chann_list, (long)conn, chann, KSMBD_DEFAULT_GFP);
++ old = xa_store(&sess->ksmbd_chann_list, (long)conn, chann,
++ KSMBD_DEFAULT_GFP);
++ if (xa_is_err(old)) {
++ kfree(chann);
++ return xa_err(old);
++ }
+ }
+ }
+
+--
+2.39.5
+
--- /dev/null
+From fc1272c4bfbd85d8b8f503ff4856fd0e525bfe5a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Feb 2025 19:00:04 +0000
+Subject: soc: apple: rtkit: Implement OSLog buffers properly
+
+From: Hector Martin <marcan@marcan.st>
+
+[ Upstream commit a06398687065e0c334dc5fc4d2778b5b87292e43 ]
+
+Apparently nobody can figure out where the old logic came from, but it
+seems like it has never been actually used on any supported firmware to
+this day. OSLog buffers were apparently never requested.
+
+But starting with 13.3, we actually need this implemented properly for
+MTP (and later AOP) to work, so let's actually do that.
+
+Signed-off-by: Hector Martin <marcan@marcan.st>
+Reviewed-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
+Link: https://lore.kernel.org/r/20250226-apple-soc-misc-v2-2-c3ec37f9021b@svenpeter.dev
+Signed-off-by: Sven Peter <sven@svenpeter.dev>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/soc/apple/rtkit-internal.h | 1 +
+ drivers/soc/apple/rtkit.c | 56 ++++++++++++++++++------------
+ 2 files changed, 35 insertions(+), 22 deletions(-)
+
+diff --git a/drivers/soc/apple/rtkit-internal.h b/drivers/soc/apple/rtkit-internal.h
+index 27c9fa745fd52..b8d5244678f01 100644
+--- a/drivers/soc/apple/rtkit-internal.h
++++ b/drivers/soc/apple/rtkit-internal.h
+@@ -44,6 +44,7 @@ struct apple_rtkit {
+
+ struct apple_rtkit_shmem ioreport_buffer;
+ struct apple_rtkit_shmem crashlog_buffer;
++ struct apple_rtkit_shmem oslog_buffer;
+
+ struct apple_rtkit_shmem syslog_buffer;
+ char *syslog_msg_buffer;
+diff --git a/drivers/soc/apple/rtkit.c b/drivers/soc/apple/rtkit.c
+index 00d59a81db88b..45ccbe2cbcd63 100644
+--- a/drivers/soc/apple/rtkit.c
++++ b/drivers/soc/apple/rtkit.c
+@@ -66,8 +66,9 @@ enum {
+ #define APPLE_RTKIT_SYSLOG_MSG_SIZE GENMASK_ULL(31, 24)
+
+ #define APPLE_RTKIT_OSLOG_TYPE GENMASK_ULL(63, 56)
+-#define APPLE_RTKIT_OSLOG_INIT 1
+-#define APPLE_RTKIT_OSLOG_ACK 3
++#define APPLE_RTKIT_OSLOG_BUFFER_REQUEST 1
++#define APPLE_RTKIT_OSLOG_SIZE GENMASK_ULL(55, 36)
++#define APPLE_RTKIT_OSLOG_IOVA GENMASK_ULL(35, 0)
+
+ #define APPLE_RTKIT_MIN_SUPPORTED_VERSION 11
+ #define APPLE_RTKIT_MAX_SUPPORTED_VERSION 12
+@@ -251,15 +252,21 @@ static int apple_rtkit_common_rx_get_buffer(struct apple_rtkit *rtk,
+ struct apple_rtkit_shmem *buffer,
+ u8 ep, u64 msg)
+ {
+- size_t n_4kpages = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_SIZE, msg);
+ u64 reply;
+ int err;
+
++ /* The different size vs. IOVA shifts look odd but are indeed correct this way */
++ if (ep == APPLE_RTKIT_EP_OSLOG) {
++ buffer->size = FIELD_GET(APPLE_RTKIT_OSLOG_SIZE, msg);
++ buffer->iova = FIELD_GET(APPLE_RTKIT_OSLOG_IOVA, msg) << 12;
++ } else {
++ buffer->size = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_SIZE, msg) << 12;
++ buffer->iova = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_IOVA, msg);
++ }
++
+ buffer->buffer = NULL;
+ buffer->iomem = NULL;
+ buffer->is_mapped = false;
+- buffer->iova = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_IOVA, msg);
+- buffer->size = n_4kpages << 12;
+
+ dev_dbg(rtk->dev, "RTKit: buffer request for 0x%zx bytes at %pad\n",
+ buffer->size, &buffer->iova);
+@@ -284,11 +291,21 @@ static int apple_rtkit_common_rx_get_buffer(struct apple_rtkit *rtk,
+ }
+
+ if (!buffer->is_mapped) {
+- reply = FIELD_PREP(APPLE_RTKIT_SYSLOG_TYPE,
+- APPLE_RTKIT_BUFFER_REQUEST);
+- reply |= FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_SIZE, n_4kpages);
+- reply |= FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_IOVA,
+- buffer->iova);
++ /* oslog uses different fields and needs a shifted IOVA instead of size */
++ if (ep == APPLE_RTKIT_EP_OSLOG) {
++ reply = FIELD_PREP(APPLE_RTKIT_OSLOG_TYPE,
++ APPLE_RTKIT_OSLOG_BUFFER_REQUEST);
++ reply |= FIELD_PREP(APPLE_RTKIT_OSLOG_SIZE, buffer->size);
++ reply |= FIELD_PREP(APPLE_RTKIT_OSLOG_IOVA,
++ buffer->iova >> 12);
++ } else {
++ reply = FIELD_PREP(APPLE_RTKIT_SYSLOG_TYPE,
++ APPLE_RTKIT_BUFFER_REQUEST);
++ reply |= FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_SIZE,
++ buffer->size >> 12);
++ reply |= FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_IOVA,
++ buffer->iova);
++ }
+ apple_rtkit_send_message(rtk, ep, reply, NULL, false);
+ }
+
+@@ -482,25 +499,18 @@ static void apple_rtkit_syslog_rx(struct apple_rtkit *rtk, u64 msg)
+ }
+ }
+
+-static void apple_rtkit_oslog_rx_init(struct apple_rtkit *rtk, u64 msg)
+-{
+- u64 ack;
+-
+- dev_dbg(rtk->dev, "RTKit: oslog init: msg: 0x%llx\n", msg);
+- ack = FIELD_PREP(APPLE_RTKIT_OSLOG_TYPE, APPLE_RTKIT_OSLOG_ACK);
+- apple_rtkit_send_message(rtk, APPLE_RTKIT_EP_OSLOG, ack, NULL, false);
+-}
+-
+ static void apple_rtkit_oslog_rx(struct apple_rtkit *rtk, u64 msg)
+ {
+ u8 type = FIELD_GET(APPLE_RTKIT_OSLOG_TYPE, msg);
+
+ switch (type) {
+- case APPLE_RTKIT_OSLOG_INIT:
+- apple_rtkit_oslog_rx_init(rtk, msg);
++ case APPLE_RTKIT_OSLOG_BUFFER_REQUEST:
++ apple_rtkit_common_rx_get_buffer(rtk, &rtk->oslog_buffer,
++ APPLE_RTKIT_EP_OSLOG, msg);
+ break;
+ default:
+- dev_warn(rtk->dev, "RTKit: Unknown oslog message: %llx\n", msg);
++ dev_warn(rtk->dev, "RTKit: Unknown oslog message: %llx\n",
++ msg);
+ }
+ }
+
+@@ -710,6 +720,7 @@ int apple_rtkit_reinit(struct apple_rtkit *rtk)
+
+ apple_rtkit_free_buffer(rtk, &rtk->ioreport_buffer);
+ apple_rtkit_free_buffer(rtk, &rtk->crashlog_buffer);
++ apple_rtkit_free_buffer(rtk, &rtk->oslog_buffer);
+ apple_rtkit_free_buffer(rtk, &rtk->syslog_buffer);
+
+ kfree(rtk->syslog_msg_buffer);
+@@ -890,6 +901,7 @@ void apple_rtkit_free(struct apple_rtkit *rtk)
+
+ apple_rtkit_free_buffer(rtk, &rtk->ioreport_buffer);
+ apple_rtkit_free_buffer(rtk, &rtk->crashlog_buffer);
++ apple_rtkit_free_buffer(rtk, &rtk->oslog_buffer);
+ apple_rtkit_free_buffer(rtk, &rtk->syslog_buffer);
+
+ kfree(rtk->syslog_msg_buffer);
+--
+2.39.5
+
--- /dev/null
+From 34b8dd29a5a549d67d0ac42ce528e375a9a03624 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Feb 2025 19:00:05 +0000
+Subject: soc: apple: rtkit: Use high prio work queue
+
+From: Janne Grunau <j@jannau.net>
+
+[ Upstream commit 22af2fac88fa5dbc310bfe7d0b66d4de3ac47305 ]
+
+rtkit messages as communication with the DCP firmware for framebuffer
+swaps or input events are time critical so use WQ_HIGHPRI to prevent
+user space CPU load to increase latency.
+With kwin_wayland 6's explicit sync mode user space load was able to
+delay the IOMFB rtkit communication enough to miss vsync for surface
+swaps. Minimal test scenario is constantly resizing a glxgears
+Xwayland window.
+
+Signed-off-by: Janne Grunau <j@jannau.net>
+Reviewed-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
+Link: https://lore.kernel.org/r/20250226-apple-soc-misc-v2-3-c3ec37f9021b@svenpeter.dev
+Signed-off-by: Sven Peter <sven@svenpeter.dev>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/soc/apple/rtkit.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/soc/apple/rtkit.c b/drivers/soc/apple/rtkit.c
+index e6d940292c9fb..00d59a81db88b 100644
+--- a/drivers/soc/apple/rtkit.c
++++ b/drivers/soc/apple/rtkit.c
+@@ -667,7 +667,7 @@ struct apple_rtkit *apple_rtkit_init(struct device *dev, void *cookie,
+ rtk->mbox->rx = apple_rtkit_rx;
+ rtk->mbox->cookie = rtk;
+
+- rtk->wq = alloc_ordered_workqueue("rtkit-%s", WQ_MEM_RECLAIM,
++ rtk->wq = alloc_ordered_workqueue("rtkit-%s", WQ_HIGHPRI | WQ_MEM_RECLAIM,
+ dev_name(rtk->dev));
+ if (!rtk->wq) {
+ ret = -ENOMEM;
+--
+2.39.5
+
--- /dev/null
+From 5fe9cd124c1d33c31e4ac0f5f202049f6a9dff8d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 12 Feb 2025 11:00:05 +0100
+Subject: soc: mediatek: mtk-mutex: Add DPI1 SOF/EOF to MT8188 mutex tables
+
+From: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+
+[ Upstream commit 694e0b7c1747603243da874de9cbbf8cb806ca44 ]
+
+MT8188 uses DPI1 to output to the HDMI controller: add the
+Start of Frame and End of Frame configuration for the DPI1
+IP to the tables to unblock generation and sending of these
+signals to the GCE.
+
+Link: https://lore.kernel.org/r/20250212100012.33001-2-angelogioacchino.delregno@collabora.com
+Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/soc/mediatek/mtk-mutex.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/drivers/soc/mediatek/mtk-mutex.c b/drivers/soc/mediatek/mtk-mutex.c
+index 5250c1d702eb9..aaa965d4b050a 100644
+--- a/drivers/soc/mediatek/mtk-mutex.c
++++ b/drivers/soc/mediatek/mtk-mutex.c
+@@ -155,6 +155,7 @@
+ #define MT8188_MUTEX_MOD_DISP1_VPP_MERGE3 23
+ #define MT8188_MUTEX_MOD_DISP1_VPP_MERGE4 24
+ #define MT8188_MUTEX_MOD_DISP1_DISP_MIXER 30
++#define MT8188_MUTEX_MOD_DISP1_DPI1 38
+ #define MT8188_MUTEX_MOD_DISP1_DP_INTF1 39
+
+ #define MT8195_MUTEX_MOD_DISP_OVL0 0
+@@ -289,6 +290,7 @@
+ #define MT8188_MUTEX_SOF_DSI0 1
+ #define MT8188_MUTEX_SOF_DP_INTF0 3
+ #define MT8188_MUTEX_SOF_DP_INTF1 4
++#define MT8188_MUTEX_SOF_DPI1 5
+ #define MT8195_MUTEX_SOF_DSI0 1
+ #define MT8195_MUTEX_SOF_DSI1 2
+ #define MT8195_MUTEX_SOF_DP_INTF0 3
+@@ -301,6 +303,7 @@
+ #define MT8188_MUTEX_EOF_DSI0 (MT8188_MUTEX_SOF_DSI0 << 7)
+ #define MT8188_MUTEX_EOF_DP_INTF0 (MT8188_MUTEX_SOF_DP_INTF0 << 7)
+ #define MT8188_MUTEX_EOF_DP_INTF1 (MT8188_MUTEX_SOF_DP_INTF1 << 7)
++#define MT8188_MUTEX_EOF_DPI1 (MT8188_MUTEX_SOF_DPI1 << 7)
+ #define MT8195_MUTEX_EOF_DSI0 (MT8195_MUTEX_SOF_DSI0 << 7)
+ #define MT8195_MUTEX_EOF_DSI1 (MT8195_MUTEX_SOF_DSI1 << 7)
+ #define MT8195_MUTEX_EOF_DP_INTF0 (MT8195_MUTEX_SOF_DP_INTF0 << 7)
+@@ -472,6 +475,7 @@ static const u8 mt8188_mutex_mod[DDP_COMPONENT_ID_MAX] = {
+ [DDP_COMPONENT_PWM0] = MT8188_MUTEX_MOD2_DISP_PWM0,
+ [DDP_COMPONENT_DP_INTF0] = MT8188_MUTEX_MOD_DISP_DP_INTF0,
+ [DDP_COMPONENT_DP_INTF1] = MT8188_MUTEX_MOD_DISP1_DP_INTF1,
++ [DDP_COMPONENT_DPI1] = MT8188_MUTEX_MOD_DISP1_DPI1,
+ [DDP_COMPONENT_ETHDR_MIXER] = MT8188_MUTEX_MOD_DISP1_DISP_MIXER,
+ [DDP_COMPONENT_MDP_RDMA0] = MT8188_MUTEX_MOD_DISP1_MDP_RDMA0,
+ [DDP_COMPONENT_MDP_RDMA1] = MT8188_MUTEX_MOD_DISP1_MDP_RDMA1,
+@@ -686,6 +690,8 @@ static const u16 mt8188_mutex_sof[DDP_MUTEX_SOF_MAX] = {
+ [MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE,
+ [MUTEX_SOF_DSI0] =
+ MT8188_MUTEX_SOF_DSI0 | MT8188_MUTEX_EOF_DSI0,
++ [MUTEX_SOF_DPI1] =
++ MT8188_MUTEX_SOF_DPI1 | MT8188_MUTEX_EOF_DPI1,
+ [MUTEX_SOF_DP_INTF0] =
+ MT8188_MUTEX_SOF_DP_INTF0 | MT8188_MUTEX_EOF_DP_INTF0,
+ [MUTEX_SOF_DP_INTF1] =
+--
+2.39.5
+
--- /dev/null
+From f3f824d2c65f83635a233b62c44debef63dac507 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Mar 2025 22:14:02 +0100
+Subject: soc: samsung: include linux/array_size.h where needed
+
+From: Arnd Bergmann <arnd@arndb.de>
+
+[ Upstream commit 4c57930f68d90e0d52c396d058cfa9ed8447a6c4 ]
+
+This does not necessarily get included through asm/io.h:
+
+drivers/soc/samsung/exynos3250-pmu.c:120:18: error: use of undeclared identifier 'ARRAY_SIZE'
+ 120 | for (i = 0; i < ARRAY_SIZE(exynos3250_list_feed); i++) {
+ | ^
+drivers/soc/samsung/exynos5250-pmu.c:162:18: error: use of undeclared identifier 'ARRAY_SIZE'
+ 162 | for (i = 0; i < ARRAY_SIZE(exynos5_list_both_cnt_feed); i++) {
+ | ^
+
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Link: https://lore.kernel.org/r/20250305211446.43772-1-arnd@kernel.org
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/soc/samsung/exynos-asv.c | 1 +
+ drivers/soc/samsung/exynos-chipid.c | 1 +
+ drivers/soc/samsung/exynos-pmu.c | 1 +
+ drivers/soc/samsung/exynos-usi.c | 1 +
+ drivers/soc/samsung/exynos3250-pmu.c | 1 +
+ drivers/soc/samsung/exynos5250-pmu.c | 1 +
+ drivers/soc/samsung/exynos5420-pmu.c | 1 +
+ 7 files changed, 7 insertions(+)
+
+diff --git a/drivers/soc/samsung/exynos-asv.c b/drivers/soc/samsung/exynos-asv.c
+index 97006cc3b9461..8e681f5195264 100644
+--- a/drivers/soc/samsung/exynos-asv.c
++++ b/drivers/soc/samsung/exynos-asv.c
+@@ -9,6 +9,7 @@
+ * Samsung Exynos SoC Adaptive Supply Voltage support
+ */
+
++#include <linux/array_size.h>
+ #include <linux/cpu.h>
+ #include <linux/device.h>
+ #include <linux/energy_model.h>
+diff --git a/drivers/soc/samsung/exynos-chipid.c b/drivers/soc/samsung/exynos-chipid.c
+index 95294462ff211..99c5f9c80101b 100644
+--- a/drivers/soc/samsung/exynos-chipid.c
++++ b/drivers/soc/samsung/exynos-chipid.c
+@@ -12,6 +12,7 @@
+ * Samsung Exynos SoC Adaptive Supply Voltage and Chip ID support
+ */
+
++#include <linux/array_size.h>
+ #include <linux/device.h>
+ #include <linux/errno.h>
+ #include <linux/mfd/syscon.h>
+diff --git a/drivers/soc/samsung/exynos-pmu.c b/drivers/soc/samsung/exynos-pmu.c
+index dd5256e5aae1a..c40313886a012 100644
+--- a/drivers/soc/samsung/exynos-pmu.c
++++ b/drivers/soc/samsung/exynos-pmu.c
+@@ -5,6 +5,7 @@
+ //
+ // Exynos - CPU PMU(Power Management Unit) support
+
++#include <linux/array_size.h>
+ #include <linux/arm-smccc.h>
+ #include <linux/of.h>
+ #include <linux/of_address.h>
+diff --git a/drivers/soc/samsung/exynos-usi.c b/drivers/soc/samsung/exynos-usi.c
+index 114352695ac2b..5a93a68dba87f 100644
+--- a/drivers/soc/samsung/exynos-usi.c
++++ b/drivers/soc/samsung/exynos-usi.c
+@@ -6,6 +6,7 @@
+ * Samsung Exynos USI driver (Universal Serial Interface).
+ */
+
++#include <linux/array_size.h>
+ #include <linux/clk.h>
+ #include <linux/mfd/syscon.h>
+ #include <linux/module.h>
+diff --git a/drivers/soc/samsung/exynos3250-pmu.c b/drivers/soc/samsung/exynos3250-pmu.c
+index 30f230ed1769c..4bad12a995422 100644
+--- a/drivers/soc/samsung/exynos3250-pmu.c
++++ b/drivers/soc/samsung/exynos3250-pmu.c
+@@ -5,6 +5,7 @@
+ //
+ // Exynos3250 - CPU PMU (Power Management Unit) support
+
++#include <linux/array_size.h>
+ #include <linux/soc/samsung/exynos-regs-pmu.h>
+ #include <linux/soc/samsung/exynos-pmu.h>
+
+diff --git a/drivers/soc/samsung/exynos5250-pmu.c b/drivers/soc/samsung/exynos5250-pmu.c
+index 7a2d50be6b4ac..2ae5c3e1b07a3 100644
+--- a/drivers/soc/samsung/exynos5250-pmu.c
++++ b/drivers/soc/samsung/exynos5250-pmu.c
+@@ -5,6 +5,7 @@
+ //
+ // Exynos5250 - CPU PMU (Power Management Unit) support
+
++#include <linux/array_size.h>
+ #include <linux/soc/samsung/exynos-regs-pmu.h>
+ #include <linux/soc/samsung/exynos-pmu.h>
+
+diff --git a/drivers/soc/samsung/exynos5420-pmu.c b/drivers/soc/samsung/exynos5420-pmu.c
+index 6fedcd78cb451..58a2209795f78 100644
+--- a/drivers/soc/samsung/exynos5420-pmu.c
++++ b/drivers/soc/samsung/exynos5420-pmu.c
+@@ -5,6 +5,7 @@
+ //
+ // Exynos5420 - CPU PMU (Power Management Unit) support
+
++#include <linux/array_size.h>
+ #include <linux/pm.h>
+ #include <linux/soc/samsung/exynos-regs-pmu.h>
+ #include <linux/soc/samsung/exynos-pmu.h>
+--
+2.39.5
+
--- /dev/null
+From 044546713993cae525426a110675a0e1e0efbcf0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 23 Jan 2025 12:17:26 -0600
+Subject: soc: ti: k3-socinfo: Do not use syscon helper to build regmap
+
+From: Andrew Davis <afd@ti.com>
+
+[ Upstream commit a5caf03188e44388e8c618dcbe5fffad1a249385 ]
+
+The syscon helper device_node_to_regmap() is used to fetch a regmap
+registered to a device node. It also currently creates this regmap
+if the node did not already have a regmap associated with it. This
+should only be used on "syscon" nodes. This driver is not such a
+device and instead uses device_node_to_regmap() on its own node as
+a hacky way to create a regmap for itself.
+
+This will not work going forward and so we should create our regmap
+the normal way by defining our regmap_config, fetching our memory
+resource, then using the normal regmap_init_mmio() function.
+
+Signed-off-by: Andrew Davis <afd@ti.com>
+Link: https://lore.kernel.org/r/20250123181726.597144-1-afd@ti.com
+Signed-off-by: Nishanth Menon <nm@ti.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/soc/ti/k3-socinfo.c | 13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/soc/ti/k3-socinfo.c b/drivers/soc/ti/k3-socinfo.c
+index 4fb0f0a248288..704039eb3c078 100644
+--- a/drivers/soc/ti/k3-socinfo.c
++++ b/drivers/soc/ti/k3-socinfo.c
+@@ -105,6 +105,12 @@ k3_chipinfo_variant_to_sr(unsigned int partno, unsigned int variant,
+ return -ENODEV;
+ }
+
++static const struct regmap_config k3_chipinfo_regmap_cfg = {
++ .reg_bits = 32,
++ .val_bits = 32,
++ .reg_stride = 4,
++};
++
+ static int k3_chipinfo_probe(struct platform_device *pdev)
+ {
+ struct device_node *node = pdev->dev.of_node;
+@@ -112,13 +118,18 @@ static int k3_chipinfo_probe(struct platform_device *pdev)
+ struct device *dev = &pdev->dev;
+ struct soc_device *soc_dev;
+ struct regmap *regmap;
++ void __iomem *base;
+ u32 partno_id;
+ u32 variant;
+ u32 jtag_id;
+ u32 mfg;
+ int ret;
+
+- regmap = device_node_to_regmap(node);
++ base = devm_platform_ioremap_resource(pdev, 0);
++ if (IS_ERR(base))
++ return PTR_ERR(base);
++
++ regmap = regmap_init_mmio(dev, base, &k3_chipinfo_regmap_cfg);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+--
+2.39.5
+
--- /dev/null
+From 030465ee8f32777ecab8afed05276722b9aa4301 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 7 Feb 2025 12:28:36 +0530
+Subject: soundwire: amd: change the soundwire wake enable/disable sequence
+
+From: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
+
+[ Upstream commit dcc48a73eae7f791b1a6856ea1bcc4079282c88d ]
+
+During runtime suspend scenario, SoundWire wake should be enabled and
+during system level suspend scenario SoundWire wake should be disabled.
+
+Implement the SoundWire wake enable/disable sequence as per design flow
+for SoundWire poweroff mode.
+
+Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
+Link: https://lore.kernel.org/r/20250207065841.4718-2-Vijendar.Mukunda@amd.com
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/soundwire/amd_manager.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/soundwire/amd_manager.c b/drivers/soundwire/amd_manager.c
+index 5a54b10daf77a..9d80623787247 100644
+--- a/drivers/soundwire/amd_manager.c
++++ b/drivers/soundwire/amd_manager.c
+@@ -1139,6 +1139,7 @@ static int __maybe_unused amd_suspend(struct device *dev)
+ amd_sdw_wake_enable(amd_manager, false);
+ return amd_sdw_clock_stop(amd_manager);
+ } else if (amd_manager->power_mode_mask & AMD_SDW_POWER_OFF_MODE) {
++ amd_sdw_wake_enable(amd_manager, false);
+ /*
+ * As per hardware programming sequence on AMD platforms,
+ * clock stop should be invoked first before powering-off
+@@ -1166,6 +1167,7 @@ static int __maybe_unused amd_suspend_runtime(struct device *dev)
+ amd_sdw_wake_enable(amd_manager, true);
+ return amd_sdw_clock_stop(amd_manager);
+ } else if (amd_manager->power_mode_mask & AMD_SDW_POWER_OFF_MODE) {
++ amd_sdw_wake_enable(amd_manager, true);
+ ret = amd_sdw_clock_stop(amd_manager);
+ if (ret)
+ return ret;
+--
+2.39.5
+
--- /dev/null
+From d74c8b051d08e61b7ba38588a472886b9e4d698d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Feb 2025 15:42:31 +0800
+Subject: soundwire: cadence_master: set frame shape and divider based on
+ actual clk freq
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Bard Liao <yung-chuan.liao@linux.intel.com>
+
+[ Upstream commit e738d77f78b3ac085dfb51be414e93464abba7ec ]
+
+Frame shape and curr_dr_freq could be updated by sdw_compute_bus_params().
+Peripherals will set curr_dr_freq as their frequency. Managers
+should do the same. Then update frame shape according to the actual
+bus frequency.
+
+Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
+Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
+Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
+Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.dev>
+Link: https://lore.kernel.org/r/20250205074232.87537-2-yung-chuan.liao@linux.intel.com
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/soundwire/cadence_master.c | 22 +++++++++++++++++++---
+ 1 file changed, 19 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
+index f367670ea991b..68be8ff3f02b1 100644
+--- a/drivers/soundwire/cadence_master.c
++++ b/drivers/soundwire/cadence_master.c
+@@ -1341,7 +1341,7 @@ static u32 cdns_set_initial_frame_shape(int n_rows, int n_cols)
+ return val;
+ }
+
+-static void cdns_init_clock_ctrl(struct sdw_cdns *cdns)
++static int cdns_init_clock_ctrl(struct sdw_cdns *cdns)
+ {
+ struct sdw_bus *bus = &cdns->bus;
+ struct sdw_master_prop *prop = &bus->prop;
+@@ -1355,14 +1355,25 @@ static void cdns_init_clock_ctrl(struct sdw_cdns *cdns)
+ prop->default_row,
+ prop->default_col);
+
++ if (!prop->default_frame_rate || !prop->default_row) {
++ dev_err(cdns->dev, "Default frame_rate %d or row %d is invalid\n",
++ prop->default_frame_rate, prop->default_row);
++ return -EINVAL;
++ }
++
+ /* Set clock divider */
+- divider = (prop->mclk_freq / prop->max_clk_freq) - 1;
++ divider = (prop->mclk_freq * SDW_DOUBLE_RATE_FACTOR /
++ bus->params.curr_dr_freq) - 1;
+
+ cdns_updatel(cdns, CDNS_MCP_CLK_CTRL0,
+ CDNS_MCP_CLK_MCLKD_MASK, divider);
+ cdns_updatel(cdns, CDNS_MCP_CLK_CTRL1,
+ CDNS_MCP_CLK_MCLKD_MASK, divider);
+
++ /* Set frame shape base on the actual bus frequency. */
++ prop->default_col = bus->params.curr_dr_freq /
++ prop->default_frame_rate / prop->default_row;
++
+ /*
+ * Frame shape changes after initialization have to be done
+ * with the bank switch mechanism
+@@ -1375,6 +1386,8 @@ static void cdns_init_clock_ctrl(struct sdw_cdns *cdns)
+ ssp_interval = prop->default_frame_rate / SDW_CADENCE_GSYNC_HZ;
+ cdns_writel(cdns, CDNS_MCP_SSP_CTRL0, ssp_interval);
+ cdns_writel(cdns, CDNS_MCP_SSP_CTRL1, ssp_interval);
++
++ return 0;
+ }
+
+ /**
+@@ -1408,9 +1421,12 @@ EXPORT_SYMBOL(sdw_cdns_soft_reset);
+ */
+ int sdw_cdns_init(struct sdw_cdns *cdns)
+ {
++ int ret;
+ u32 val;
+
+- cdns_init_clock_ctrl(cdns);
++ ret = cdns_init_clock_ctrl(cdns);
++ if (ret)
++ return ret;
+
+ sdw_cdns_check_self_clearing_bits(cdns, __func__, false, 0);
+
+--
+2.39.5
+
--- /dev/null
+From a71ccf7ad66d3afab204314af235f8cf57ffa479 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 21 Mar 2025 13:57:53 +0100
+Subject: spi-rockchip: Fix register out of bounds access
+
+From: Luis de Arquer <luis.dearquer@inertim.com>
+
+[ Upstream commit 7a874e8b54ea21094f7fd2d428b164394c6cb316 ]
+
+Do not write native chip select stuff for GPIO chip selects.
+GPIOs can be numbered much higher than native CS.
+Also, it makes no sense.
+
+Signed-off-by: Luis de Arquer <luis.dearquer@inertim.com>
+Link: https://patch.msgid.link/365ccddfba110549202b3520f4401a6a936e82a8.camel@gmail.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/spi/spi-rockchip.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
+index 1bc012fce7cb8..1a6381de6f33d 100644
+--- a/drivers/spi/spi-rockchip.c
++++ b/drivers/spi/spi-rockchip.c
+@@ -547,7 +547,7 @@ static int rockchip_spi_config(struct rockchip_spi *rs,
+ cr0 |= (spi->mode & 0x3U) << CR0_SCPH_OFFSET;
+ if (spi->mode & SPI_LSB_FIRST)
+ cr0 |= CR0_FBM_LSB << CR0_FBM_OFFSET;
+- if (spi->mode & SPI_CS_HIGH)
++ if ((spi->mode & SPI_CS_HIGH) && !(spi_get_csgpiod(spi, 0)))
+ cr0 |= BIT(spi_get_chipselect(spi, 0)) << CR0_SOI_OFFSET;
+
+ if (xfer->rx_buf && xfer->tx_buf)
+--
+2.39.5
+
--- /dev/null
+From d06c9ea2ff7977f7dffb3a252398f7757d8259a0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 15 Mar 2025 23:46:06 -0600
+Subject: spi: spi-mux: Fix coverity issue, unchecked return value
+
+From: Sergio Perez Gonzalez <sperezglz@gmail.com>
+
+[ Upstream commit 5a5fc308418aca275a898d638bc38c093d101855 ]
+
+The return value of spi_setup() is not captured within
+spi_mux_select() and it is assumed to be always success.
+
+CID: 1638374
+
+Signed-off-by: Sergio Perez Gonzalez <sperezglz@gmail.com>
+Link: https://patch.msgid.link/20250316054651.13242-1-sperezglz@gmail.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/spi/spi-mux.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+diff --git a/drivers/spi/spi-mux.c b/drivers/spi/spi-mux.c
+index c02c4204442f5..0eb35c4e3987e 100644
+--- a/drivers/spi/spi-mux.c
++++ b/drivers/spi/spi-mux.c
+@@ -68,9 +68,7 @@ static int spi_mux_select(struct spi_device *spi)
+
+ priv->current_cs = spi_get_chipselect(spi, 0);
+
+- spi_setup(priv->spi);
+-
+- return 0;
++ return spi_setup(priv->spi);
+ }
+
+ static int spi_mux_setup(struct spi_device *spi)
+--
+2.39.5
+
--- /dev/null
+From c67a4d9191b2fcef51ddb89abb3d7c1ae2eaa383 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Jan 2025 17:41:30 -0500
+Subject: spi: zynqmp-gqspi: Always acknowledge interrupts
+
+From: Sean Anderson <sean.anderson@linux.dev>
+
+[ Upstream commit 89785306453ce6d949e783f6936821a0b7649ee2 ]
+
+RXEMPTY can cause an IRQ, even though we may not do anything about it
+(such as if we are waiting for more received data). We must still handle
+these IRQs because we can tell they were caused by the device.
+
+Signed-off-by: Sean Anderson <sean.anderson@linux.dev>
+Link: https://patch.msgid.link/20250116224130.2684544-6-sean.anderson@linux.dev
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/spi/spi-zynqmp-gqspi.c | 20 ++++++++------------
+ 1 file changed, 8 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c
+index d800d79f62a70..12ab13edab543 100644
+--- a/drivers/spi/spi-zynqmp-gqspi.c
++++ b/drivers/spi/spi-zynqmp-gqspi.c
+@@ -799,7 +799,6 @@ static void zynqmp_process_dma_irq(struct zynqmp_qspi *xqspi)
+ static irqreturn_t zynqmp_qspi_irq(int irq, void *dev_id)
+ {
+ struct zynqmp_qspi *xqspi = (struct zynqmp_qspi *)dev_id;
+- irqreturn_t ret = IRQ_NONE;
+ u32 status, mask, dma_status = 0;
+
+ status = zynqmp_gqspi_read(xqspi, GQSPI_ISR_OFST);
+@@ -814,27 +813,24 @@ static irqreturn_t zynqmp_qspi_irq(int irq, void *dev_id)
+ dma_status);
+ }
+
+- if (mask & GQSPI_ISR_TXNOT_FULL_MASK) {
++ if (!mask && !dma_status)
++ return IRQ_NONE;
++
++ if (mask & GQSPI_ISR_TXNOT_FULL_MASK)
+ zynqmp_qspi_filltxfifo(xqspi, GQSPI_TX_FIFO_FILL);
+- ret = IRQ_HANDLED;
+- }
+
+- if (dma_status & GQSPI_QSPIDMA_DST_I_STS_DONE_MASK) {
++ if (dma_status & GQSPI_QSPIDMA_DST_I_STS_DONE_MASK)
+ zynqmp_process_dma_irq(xqspi);
+- ret = IRQ_HANDLED;
+- } else if (!(mask & GQSPI_IER_RXEMPTY_MASK) &&
+- (mask & GQSPI_IER_GENFIFOEMPTY_MASK)) {
++ else if (!(mask & GQSPI_IER_RXEMPTY_MASK) &&
++ (mask & GQSPI_IER_GENFIFOEMPTY_MASK))
+ zynqmp_qspi_readrxfifo(xqspi, GQSPI_RX_FIFO_FILL);
+- ret = IRQ_HANDLED;
+- }
+
+ if (xqspi->bytes_to_receive == 0 && xqspi->bytes_to_transfer == 0 &&
+ ((status & GQSPI_IRQ_MASK) == GQSPI_IRQ_MASK)) {
+ zynqmp_gqspi_write(xqspi, GQSPI_IDR_OFST, GQSPI_ISR_IDR_MASK);
+ complete(&xqspi->data_completion);
+- ret = IRQ_HANDLED;
+ }
+- return ret;
++ return IRQ_HANDLED;
+ }
+
+ /**
+--
+2.39.5
+
--- /dev/null
+From a5d566b380b376a8e1512ff4f8ebb395ccba63e6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 9 Mar 2025 13:50:13 +0100
+Subject: staging: vchiq_arm: Create keep-alive thread during probe
+
+From: Stefan Wahren <wahrenst@gmx.net>
+
+[ Upstream commit 86bc8821700665ad3962f3ef0d93667f59cf7031 ]
+
+Creating the keep-alive thread in vchiq_platform_init_state have
+the following advantages:
+- abort driver probe if kthread_create fails (more consistent behavior)
+- make resource release process easier
+
+Since vchiq_keepalive_thread_func is defined below
+vchiq_platform_init_state, the latter must be moved.
+
+Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
+Link: https://lore.kernel.org/r/20250309125014.37166-5-wahrenst@gmx.net
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../interface/vchiq_arm/vchiq_arm.c | 69 +++++++++----------
+ 1 file changed, 34 insertions(+), 35 deletions(-)
+
+diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+index 0c7ea2d0ee85e..64f9536f12329 100644
+--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+@@ -280,29 +280,6 @@ static int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state
+ return 0;
+ }
+
+-int
+-vchiq_platform_init_state(struct vchiq_state *state)
+-{
+- struct vchiq_arm_state *platform_state;
+-
+- platform_state = devm_kzalloc(state->dev, sizeof(*platform_state), GFP_KERNEL);
+- if (!platform_state)
+- return -ENOMEM;
+-
+- rwlock_init(&platform_state->susp_res_lock);
+-
+- init_completion(&platform_state->ka_evt);
+- atomic_set(&platform_state->ka_use_count, 0);
+- atomic_set(&platform_state->ka_use_ack_count, 0);
+- atomic_set(&platform_state->ka_release_count, 0);
+-
+- platform_state->state = state;
+-
+- state->platform_state = (struct opaque_platform_state *)platform_state;
+-
+- return 0;
+-}
+-
+ static struct vchiq_arm_state *vchiq_platform_get_arm_state(struct vchiq_state *state)
+ {
+ return (struct vchiq_arm_state *)state->platform_state;
+@@ -1011,6 +988,39 @@ vchiq_keepalive_thread_func(void *v)
+ return 0;
+ }
+
++int
++vchiq_platform_init_state(struct vchiq_state *state)
++{
++ struct vchiq_arm_state *platform_state;
++ char threadname[16];
++
++ platform_state = devm_kzalloc(state->dev, sizeof(*platform_state), GFP_KERNEL);
++ if (!platform_state)
++ return -ENOMEM;
++
++ snprintf(threadname, sizeof(threadname), "vchiq-keep/%d",
++ state->id);
++ platform_state->ka_thread = kthread_create(&vchiq_keepalive_thread_func,
++ (void *)state, threadname);
++ if (IS_ERR(platform_state->ka_thread)) {
++ dev_err(state->dev, "couldn't create thread %s\n", threadname);
++ return PTR_ERR(platform_state->ka_thread);
++ }
++
++ rwlock_init(&platform_state->susp_res_lock);
++
++ init_completion(&platform_state->ka_evt);
++ atomic_set(&platform_state->ka_use_count, 0);
++ atomic_set(&platform_state->ka_use_ack_count, 0);
++ atomic_set(&platform_state->ka_release_count, 0);
++
++ platform_state->state = state;
++
++ state->platform_state = (struct opaque_platform_state *)platform_state;
++
++ return 0;
++}
++
+ int
+ vchiq_use_internal(struct vchiq_state *state, struct vchiq_service *service,
+ enum USE_TYPE_E use_type)
+@@ -1331,7 +1341,6 @@ void vchiq_platform_conn_state_changed(struct vchiq_state *state,
+ enum vchiq_connstate newstate)
+ {
+ struct vchiq_arm_state *arm_state = vchiq_platform_get_arm_state(state);
+- char threadname[16];
+
+ dev_dbg(state->dev, "suspend: %d: %s->%s\n",
+ state->id, get_conn_state_name(oldstate), get_conn_state_name(newstate));
+@@ -1346,17 +1355,7 @@ void vchiq_platform_conn_state_changed(struct vchiq_state *state,
+
+ arm_state->first_connect = 1;
+ write_unlock_bh(&arm_state->susp_res_lock);
+- snprintf(threadname, sizeof(threadname), "vchiq-keep/%d",
+- state->id);
+- arm_state->ka_thread = kthread_create(&vchiq_keepalive_thread_func,
+- (void *)state,
+- threadname);
+- if (IS_ERR(arm_state->ka_thread)) {
+- dev_err(state->dev, "suspend: Couldn't create thread %s\n",
+- threadname);
+- } else {
+- wake_up_process(arm_state->ka_thread);
+- }
++ wake_up_process(arm_state->ka_thread);
+ }
+
+ static const struct of_device_id vchiq_of_match[] = {
+--
+2.39.5
+
--- /dev/null
+From f5df841ba4f419db4b8a9c4bb14fc2a85c4f9dc8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 28 Mar 2025 12:52:52 -0400
+Subject: SUNRPC: Don't allow waiting for exiting tasks
+
+From: Trond Myklebust <trond.myklebust@hammerspace.com>
+
+[ Upstream commit 14e41b16e8cb677bb440dca2edba8b041646c742 ]
+
+Once a task calls exit_signals() it can no longer be signalled. So do
+not allow it to do killable waits.
+
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sunrpc/sched.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
+index 9b45fbdc90cab..73bc39281ef5f 100644
+--- a/net/sunrpc/sched.c
++++ b/net/sunrpc/sched.c
+@@ -276,6 +276,8 @@ EXPORT_SYMBOL_GPL(rpc_destroy_wait_queue);
+
+ static int rpc_wait_bit_killable(struct wait_bit_key *key, int mode)
+ {
++ if (unlikely(current->flags & PF_EXITING))
++ return -EINTR;
+ schedule();
+ if (signal_pending_state(mode, current))
+ return -ERESTARTSYS;
+--
+2.39.5
+
--- /dev/null
+From 0c0e47b2eaee2ab1167168cded054c1715e87c2e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 24 Mar 2025 19:35:01 -0400
+Subject: SUNRPC: rpc_clnt_set_transport() must not change the autobind setting
+
+From: Trond Myklebust <trond.myklebust@hammerspace.com>
+
+[ Upstream commit bf9be373b830a3e48117da5d89bb6145a575f880 ]
+
+The autobind setting was supposed to be determined in rpc_create(),
+since commit c2866763b402 ("SUNRPC: use sockaddr + size when creating
+remote transport endpoints").
+
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Reviewed-by: Benjamin Coddington <bcodding@redhat.com>
+Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sunrpc/clnt.c | 3 ---
+ 1 file changed, 3 deletions(-)
+
+diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
+index 2fe88ea79a70c..c9c5f0caef6bd 100644
+--- a/net/sunrpc/clnt.c
++++ b/net/sunrpc/clnt.c
+@@ -270,9 +270,6 @@ static struct rpc_xprt *rpc_clnt_set_transport(struct rpc_clnt *clnt,
+ old = rcu_dereference_protected(clnt->cl_xprt,
+ lockdep_is_held(&clnt->cl_lock));
+
+- if (!xprt_bound(xprt))
+- clnt->cl_autobind = 1;
+-
+ clnt->cl_timeout = timeout;
+ rcu_assign_pointer(clnt->cl_xprt, xprt);
+ spin_unlock(&clnt->cl_lock);
+--
+2.39.5
+
--- /dev/null
+From 978e47a3d11e5c2d7b3abaf81ba0036a62ea3d27 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 24 Mar 2025 19:05:48 -0400
+Subject: SUNRPC: rpcbind should never reset the port to the value '0'
+
+From: Trond Myklebust <trond.myklebust@hammerspace.com>
+
+[ Upstream commit 214c13e380ad7636631279f426387f9c4e3c14d9 ]
+
+If we already had a valid port number for the RPC service, then we
+should not allow the rpcbind client to set it to the invalid value '0'.
+
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Reviewed-by: Benjamin Coddington <bcodding@redhat.com>
+Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sunrpc/rpcb_clnt.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
+index 102c3818bc54d..53bcca365fb1c 100644
+--- a/net/sunrpc/rpcb_clnt.c
++++ b/net/sunrpc/rpcb_clnt.c
+@@ -820,9 +820,10 @@ static void rpcb_getport_done(struct rpc_task *child, void *data)
+ }
+
+ trace_rpcb_setport(child, map->r_status, map->r_port);
+- xprt->ops->set_port(xprt, map->r_port);
+- if (map->r_port)
++ if (map->r_port) {
++ xprt->ops->set_port(xprt, map->r_port);
+ xprt_set_bound(xprt);
++ }
+ }
+
+ /*
+--
+2.39.5
+
--- /dev/null
+From 476d8290816075cc72ee51959d802d3af2683301 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 25 Feb 2025 17:10:48 +0000
+Subject: tcp: be less liberal in TSEcr received while in SYN_RECV state
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit 3ba075278c11cdb19e2dbb80362042f1b0c08f74 ]
+
+Yong-Hao Zou mentioned that linux was not strict as other OS in 3WHS,
+for flows using TCP TS option (RFC 7323)
+
+As hinted by an old comment in tcp_check_req(),
+we can check the TSEcr value in the incoming packet corresponds
+to one of the SYNACK TSval values we have sent.
+
+In this patch, I record the oldest and most recent values
+that SYNACK packets have used.
+
+Send a challenge ACK if we receive a TSEcr outside
+of this range, and increase a new SNMP counter.
+
+nstat -az | grep TSEcrRejected
+TcpExtTSEcrRejected 0 0.0
+
+Due to TCP fastopen implementation, do not apply yet these checks
+for fastopen flows.
+
+v2: No longer use req->num_timeout, but treq->snt_tsval_first
+ to detect when first SYNACK is prepared. This means
+ we make sure to not send an initial zero TSval.
+ Make sure MPTCP and TCP selftests are passing.
+ Change MIB name to TcpExtTSEcrRejected
+
+v1: https://lore.kernel.org/netdev/CADVnQykD8i4ArpSZaPKaoNxLJ2if2ts9m4As+=Jvdkrgx1qMHw@mail.gmail.com/T/
+
+Reported-by: Yong-Hao Zou <yonghaoz1994@gmail.com>
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Reviewed-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Reviewed-by: Neal Cardwell <ncardwell@google.com>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Link: https://patch.msgid.link/20250225171048.3105061-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../networking/net_cachelines/snmp.rst | 1 +
+ include/linux/tcp.h | 2 ++
+ include/uapi/linux/snmp.h | 1 +
+ net/ipv4/proc.c | 1 +
+ net/ipv4/syncookies.c | 1 +
+ net/ipv4/tcp_input.c | 1 +
+ net/ipv4/tcp_minisocks.c | 26 +++++++++++--------
+ net/ipv4/tcp_output.c | 6 +++++
+ 8 files changed, 28 insertions(+), 11 deletions(-)
+
+diff --git a/Documentation/networking/net_cachelines/snmp.rst b/Documentation/networking/net_cachelines/snmp.rst
+index 90ca2d92547d4..bc96efc92cf5b 100644
+--- a/Documentation/networking/net_cachelines/snmp.rst
++++ b/Documentation/networking/net_cachelines/snmp.rst
+@@ -36,6 +36,7 @@ unsigned_long LINUX_MIB_TIMEWAITRECYCLED
+ unsigned_long LINUX_MIB_TIMEWAITKILLED
+ unsigned_long LINUX_MIB_PAWSACTIVEREJECTED
+ unsigned_long LINUX_MIB_PAWSESTABREJECTED
++unsigned_long LINUX_MIB_TSECR_REJECTED
+ unsigned_long LINUX_MIB_DELAYEDACKLOST
+ unsigned_long LINUX_MIB_LISTENOVERFLOWS
+ unsigned_long LINUX_MIB_LISTENDROPS
+diff --git a/include/linux/tcp.h b/include/linux/tcp.h
+index f88daaa76d836..159b2c59eb627 100644
+--- a/include/linux/tcp.h
++++ b/include/linux/tcp.h
+@@ -160,6 +160,8 @@ struct tcp_request_sock {
+ u32 rcv_isn;
+ u32 snt_isn;
+ u32 ts_off;
++ u32 snt_tsval_first;
++ u32 snt_tsval_last;
+ u32 last_oow_ack_time; /* last SYNACK */
+ u32 rcv_nxt; /* the ack # by SYNACK. For
+ * FastOpen it's the seq#
+diff --git a/include/uapi/linux/snmp.h b/include/uapi/linux/snmp.h
+index 848c7784e684c..eb9fb776fdc3e 100644
+--- a/include/uapi/linux/snmp.h
++++ b/include/uapi/linux/snmp.h
+@@ -186,6 +186,7 @@ enum
+ LINUX_MIB_TIMEWAITKILLED, /* TimeWaitKilled */
+ LINUX_MIB_PAWSACTIVEREJECTED, /* PAWSActiveRejected */
+ LINUX_MIB_PAWSESTABREJECTED, /* PAWSEstabRejected */
++ LINUX_MIB_TSECRREJECTED, /* TSEcrRejected */
+ LINUX_MIB_PAWS_OLD_ACK, /* PAWSOldAck */
+ LINUX_MIB_DELAYEDACKS, /* DelayedACKs */
+ LINUX_MIB_DELAYEDACKLOCKED, /* DelayedACKLocked */
+diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c
+index affd21a0f5728..10cbeb76c2745 100644
+--- a/net/ipv4/proc.c
++++ b/net/ipv4/proc.c
+@@ -189,6 +189,7 @@ static const struct snmp_mib snmp4_net_list[] = {
+ SNMP_MIB_ITEM("TWKilled", LINUX_MIB_TIMEWAITKILLED),
+ SNMP_MIB_ITEM("PAWSActive", LINUX_MIB_PAWSACTIVEREJECTED),
+ SNMP_MIB_ITEM("PAWSEstab", LINUX_MIB_PAWSESTABREJECTED),
++ SNMP_MIB_ITEM("TSEcrRejected", LINUX_MIB_TSECRREJECTED),
+ SNMP_MIB_ITEM("PAWSOldAck", LINUX_MIB_PAWS_OLD_ACK),
+ SNMP_MIB_ITEM("DelayedACKs", LINUX_MIB_DELAYEDACKS),
+ SNMP_MIB_ITEM("DelayedACKLocked", LINUX_MIB_DELAYEDACKLOCKED),
+diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
+index 1948d15f1f281..25976fa7768c9 100644
+--- a/net/ipv4/syncookies.c
++++ b/net/ipv4/syncookies.c
+@@ -279,6 +279,7 @@ static int cookie_tcp_reqsk_init(struct sock *sk, struct sk_buff *skb,
+ ireq->smc_ok = 0;
+
+ treq->snt_synack = 0;
++ treq->snt_tsval_first = 0;
+ treq->tfo_listener = false;
+ treq->txhash = net_tx_rndhash();
+ treq->rcv_isn = ntohl(th->seq) - 1;
+diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
+index 23cf8f4a37214..1b09b4d76c296 100644
+--- a/net/ipv4/tcp_input.c
++++ b/net/ipv4/tcp_input.c
+@@ -7089,6 +7089,7 @@ static void tcp_openreq_init(struct request_sock *req,
+ tcp_rsk(req)->rcv_isn = TCP_SKB_CB(skb)->seq;
+ tcp_rsk(req)->rcv_nxt = TCP_SKB_CB(skb)->seq + 1;
+ tcp_rsk(req)->snt_synack = 0;
++ tcp_rsk(req)->snt_tsval_first = 0;
+ tcp_rsk(req)->last_oow_ack_time = 0;
+ req->mss = rx_opt->mss_clamp;
+ req->ts_recent = rx_opt->saw_tstamp ? rx_opt->rcv_tsval : 0;
+diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
+index dfdb7a4608a85..0d4ff5f2352f8 100644
+--- a/net/ipv4/tcp_minisocks.c
++++ b/net/ipv4/tcp_minisocks.c
+@@ -665,6 +665,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
+ struct sock *child;
+ const struct tcphdr *th = tcp_hdr(skb);
+ __be32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK);
++ bool tsecr_reject = false;
+ bool paws_reject = false;
+ bool own_req;
+
+@@ -674,8 +675,13 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
+
+ if (tmp_opt.saw_tstamp) {
+ tmp_opt.ts_recent = READ_ONCE(req->ts_recent);
+- if (tmp_opt.rcv_tsecr)
++ if (tmp_opt.rcv_tsecr) {
++ if (inet_rsk(req)->tstamp_ok && !fastopen)
++ tsecr_reject = !between(tmp_opt.rcv_tsecr,
++ tcp_rsk(req)->snt_tsval_first,
++ READ_ONCE(tcp_rsk(req)->snt_tsval_last));
+ tmp_opt.rcv_tsecr -= tcp_rsk(req)->ts_off;
++ }
+ /* We do not store true stamp, but it is not required,
+ * it can be estimated (approximately)
+ * from another data.
+@@ -790,18 +796,14 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
+ tcp_rsk(req)->snt_isn + 1))
+ return sk;
+
+- /* Also, it would be not so bad idea to check rcv_tsecr, which
+- * is essentially ACK extension and too early or too late values
+- * should cause reset in unsynchronized states.
+- */
+-
+ /* RFC793: "first check sequence number". */
+
+- if (paws_reject || !tcp_in_window(TCP_SKB_CB(skb)->seq,
+- TCP_SKB_CB(skb)->end_seq,
+- tcp_rsk(req)->rcv_nxt,
+- tcp_rsk(req)->rcv_nxt +
+- tcp_synack_window(req))) {
++ if (paws_reject || tsecr_reject ||
++ !tcp_in_window(TCP_SKB_CB(skb)->seq,
++ TCP_SKB_CB(skb)->end_seq,
++ tcp_rsk(req)->rcv_nxt,
++ tcp_rsk(req)->rcv_nxt +
++ tcp_synack_window(req))) {
+ /* Out of window: send ACK and drop. */
+ if (!(flg & TCP_FLAG_RST) &&
+ !tcp_oow_rate_limited(sock_net(sk), skb,
+@@ -810,6 +812,8 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
+ req->rsk_ops->send_ack(sk, skb, req);
+ if (paws_reject)
+ NET_INC_STATS(sock_net(sk), LINUX_MIB_PAWSESTABREJECTED);
++ else if (tsecr_reject)
++ NET_INC_STATS(sock_net(sk), LINUX_MIB_TSECRREJECTED);
+ return NULL;
+ }
+
+diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
+index bc95d2a5924fd..6031d7f7f5198 100644
+--- a/net/ipv4/tcp_output.c
++++ b/net/ipv4/tcp_output.c
+@@ -941,6 +941,12 @@ static unsigned int tcp_synack_options(const struct sock *sk,
+ opts->options |= OPTION_TS;
+ opts->tsval = tcp_skb_timestamp_ts(tcp_rsk(req)->req_usec_ts, skb) +
+ tcp_rsk(req)->ts_off;
++ if (!tcp_rsk(req)->snt_tsval_first) {
++ if (!opts->tsval)
++ opts->tsval = ~0U;
++ tcp_rsk(req)->snt_tsval_first = opts->tsval;
++ }
++ WRITE_ONCE(tcp_rsk(req)->snt_tsval_last, opts->tsval);
+ opts->tsecr = READ_ONCE(req->ts_recent);
+ remaining -= TCPOLEN_TSTAMP_ALIGNED;
+ }
+--
+2.39.5
+
--- /dev/null
+From 7e11b230d7a40473c3c68b4a8bfd38efaa35c5e0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Mar 2025 13:05:50 +0000
+Subject: tcp: bring back NUMA dispersion in inet_ehash_locks_alloc()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit f8ece40786c9342249aa0a1b55e148ee23b2a746 ]
+
+We have platforms with 6 NUMA nodes and 480 cpus.
+
+inet_ehash_locks_alloc() currently allocates a single 64KB page
+to hold all ehash spinlocks. This adds more pressure on a single node.
+
+Change inet_ehash_locks_alloc() to use vmalloc() to spread
+the spinlocks on all online nodes, driven by NUMA policies.
+
+At boot time, NUMA policy is interleave=all, meaning that
+tcp_hashinfo.ehash_locks gets hash dispersion on all nodes.
+
+Tested:
+
+lack5:~# grep inet_ehash_locks_alloc /proc/vmallocinfo
+0x00000000d9aec4d1-0x00000000a828b652 69632 inet_ehash_locks_alloc+0x90/0x100 pages=16 vmalloc N0=2 N1=3 N2=3 N3=3 N4=3 N5=2
+
+lack5:~# echo 8192 >/proc/sys/net/ipv4/tcp_child_ehash_entries
+lack5:~# numactl --interleave=all unshare -n bash -c "grep inet_ehash_locks_alloc /proc/vmallocinfo"
+0x000000004e99d30c-0x00000000763f3279 36864 inet_ehash_locks_alloc+0x90/0x100 pages=8 vmalloc N0=1 N1=2 N2=2 N3=1 N4=1 N5=1
+0x00000000d9aec4d1-0x00000000a828b652 69632 inet_ehash_locks_alloc+0x90/0x100 pages=16 vmalloc N0=2 N1=3 N2=3 N3=3 N4=3 N5=2
+
+lack5:~# numactl --interleave=0,5 unshare -n bash -c "grep inet_ehash_locks_alloc /proc/vmallocinfo"
+0x00000000fd73a33e-0x0000000004b9a177 36864 inet_ehash_locks_alloc+0x90/0x100 pages=8 vmalloc N0=4 N5=4
+0x00000000d9aec4d1-0x00000000a828b652 69632 inet_ehash_locks_alloc+0x90/0x100 pages=16 vmalloc N0=2 N1=3 N2=3 N3=3 N4=3 N5=2
+
+lack5:~# echo 1024 >/proc/sys/net/ipv4/tcp_child_ehash_entries
+lack5:~# numactl --interleave=all unshare -n bash -c "grep inet_ehash_locks_alloc /proc/vmallocinfo"
+0x00000000db07d7a2-0x00000000ad697d29 8192 inet_ehash_locks_alloc+0x90/0x100 pages=1 vmalloc N2=1
+0x00000000d9aec4d1-0x00000000a828b652 69632 inet_ehash_locks_alloc+0x90/0x100 pages=16 vmalloc N0=2 N1=3 N2=3 N3=3 N4=3 N5=2
+
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Tested-by: Jason Xing <kerneljasonxing@gmail.com>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Link: https://patch.msgid.link/20250305130550.1865988-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/inet_hashtables.c | 37 ++++++++++++++++++++++++++-----------
+ 1 file changed, 26 insertions(+), 11 deletions(-)
+
+diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
+index 9bfcfd016e182..2b4a588247639 100644
+--- a/net/ipv4/inet_hashtables.c
++++ b/net/ipv4/inet_hashtables.c
+@@ -1230,22 +1230,37 @@ int inet_ehash_locks_alloc(struct inet_hashinfo *hashinfo)
+ {
+ unsigned int locksz = sizeof(spinlock_t);
+ unsigned int i, nblocks = 1;
++ spinlock_t *ptr = NULL;
+
+- if (locksz != 0) {
+- /* allocate 2 cache lines or at least one spinlock per cpu */
+- nblocks = max(2U * L1_CACHE_BYTES / locksz, 1U);
+- nblocks = roundup_pow_of_two(nblocks * num_possible_cpus());
++ if (locksz == 0)
++ goto set_mask;
+
+- /* no more locks than number of hash buckets */
+- nblocks = min(nblocks, hashinfo->ehash_mask + 1);
++ /* Allocate 2 cache lines or at least one spinlock per cpu. */
++ nblocks = max(2U * L1_CACHE_BYTES / locksz, 1U) * num_possible_cpus();
+
+- hashinfo->ehash_locks = kvmalloc_array(nblocks, locksz, GFP_KERNEL);
+- if (!hashinfo->ehash_locks)
+- return -ENOMEM;
++ /* At least one page per NUMA node. */
++ nblocks = max(nblocks, num_online_nodes() * PAGE_SIZE / locksz);
++
++ nblocks = roundup_pow_of_two(nblocks);
++
++ /* No more locks than number of hash buckets. */
++ nblocks = min(nblocks, hashinfo->ehash_mask + 1);
+
+- for (i = 0; i < nblocks; i++)
+- spin_lock_init(&hashinfo->ehash_locks[i]);
++ if (num_online_nodes() > 1) {
++ /* Use vmalloc() to allow NUMA policy to spread pages
++ * on all available nodes if desired.
++ */
++ ptr = vmalloc_array(nblocks, locksz);
++ }
++ if (!ptr) {
++ ptr = kvmalloc_array(nblocks, locksz, GFP_KERNEL);
++ if (!ptr)
++ return -ENOMEM;
+ }
++ for (i = 0; i < nblocks; i++)
++ spin_lock_init(&ptr[i]);
++ hashinfo->ehash_locks = ptr;
++set_mask:
+ hashinfo->ehash_locks_mask = nblocks - 1;
+ return 0;
+ }
+--
+2.39.5
+
--- /dev/null
+From 017111cf65afee4b6f344cfc56272251f7bff005 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Mar 2025 23:38:41 +0100
+Subject: tcp: reorganize tcp_in_ack_event() and tcp_count_delivered()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Ilpo Järvinen <ij@kernel.org>
+
+[ Upstream commit 149dfb31615e22271d2525f078c95ea49bc4db24 ]
+
+- Move tcp_count_delivered() earlier and split tcp_count_delivered_ce()
+ out of it
+- Move tcp_in_ack_event() later
+- While at it, remove the inline from tcp_in_ack_event() and let
+ the compiler to decide
+
+Accurate ECN's heuristics does not know if there is going
+to be ACE field based CE counter increase or not until after
+rtx queue has been processed. Only then the number of ACKed
+bytes/pkts is available. As CE or not affects presence of
+FLAG_ECE, that information for tcp_in_ack_event is not yet
+available in the old location of the call to tcp_in_ack_event().
+
+Signed-off-by: Ilpo Järvinen <ij@kernel.org>
+Signed-off-by: Chia-Yu Chang <chia-yu.chang@nokia-bell-labs.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/tcp_input.c | 56 +++++++++++++++++++++++++-------------------
+ 1 file changed, 32 insertions(+), 24 deletions(-)
+
+diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
+index 0cbf81bf3d451..23cf8f4a37214 100644
+--- a/net/ipv4/tcp_input.c
++++ b/net/ipv4/tcp_input.c
+@@ -419,6 +419,20 @@ static bool tcp_ecn_rcv_ecn_echo(const struct tcp_sock *tp, const struct tcphdr
+ return false;
+ }
+
++static void tcp_count_delivered_ce(struct tcp_sock *tp, u32 ecn_count)
++{
++ tp->delivered_ce += ecn_count;
++}
++
++/* Updates the delivered and delivered_ce counts */
++static void tcp_count_delivered(struct tcp_sock *tp, u32 delivered,
++ bool ece_ack)
++{
++ tp->delivered += delivered;
++ if (ece_ack)
++ tcp_count_delivered_ce(tp, delivered);
++}
++
+ /* Buffer size and advertised window tuning.
+ *
+ * 1. Tuning sk->sk_sndbuf, when connection enters established state.
+@@ -1154,15 +1168,6 @@ void tcp_mark_skb_lost(struct sock *sk, struct sk_buff *skb)
+ }
+ }
+
+-/* Updates the delivered and delivered_ce counts */
+-static void tcp_count_delivered(struct tcp_sock *tp, u32 delivered,
+- bool ece_ack)
+-{
+- tp->delivered += delivered;
+- if (ece_ack)
+- tp->delivered_ce += delivered;
+-}
+-
+ /* This procedure tags the retransmission queue when SACKs arrive.
+ *
+ * We have three tag bits: SACKED(S), RETRANS(R) and LOST(L).
+@@ -3862,12 +3867,23 @@ static void tcp_process_tlp_ack(struct sock *sk, u32 ack, int flag)
+ }
+ }
+
+-static inline void tcp_in_ack_event(struct sock *sk, u32 flags)
++static void tcp_in_ack_event(struct sock *sk, int flag)
+ {
+ const struct inet_connection_sock *icsk = inet_csk(sk);
+
+- if (icsk->icsk_ca_ops->in_ack_event)
+- icsk->icsk_ca_ops->in_ack_event(sk, flags);
++ if (icsk->icsk_ca_ops->in_ack_event) {
++ u32 ack_ev_flags = 0;
++
++ if (flag & FLAG_WIN_UPDATE)
++ ack_ev_flags |= CA_ACK_WIN_UPDATE;
++ if (flag & FLAG_SLOWPATH) {
++ ack_ev_flags |= CA_ACK_SLOWPATH;
++ if (flag & FLAG_ECE)
++ ack_ev_flags |= CA_ACK_ECE;
++ }
++
++ icsk->icsk_ca_ops->in_ack_event(sk, ack_ev_flags);
++ }
+ }
+
+ /* Congestion control has updated the cwnd already. So if we're in
+@@ -3984,12 +4000,8 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
+ tcp_snd_una_update(tp, ack);
+ flag |= FLAG_WIN_UPDATE;
+
+- tcp_in_ack_event(sk, CA_ACK_WIN_UPDATE);
+-
+ NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPHPACKS);
+ } else {
+- u32 ack_ev_flags = CA_ACK_SLOWPATH;
+-
+ if (ack_seq != TCP_SKB_CB(skb)->end_seq)
+ flag |= FLAG_DATA;
+ else
+@@ -4001,19 +4013,12 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
+ flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una,
+ &sack_state);
+
+- if (tcp_ecn_rcv_ecn_echo(tp, tcp_hdr(skb))) {
++ if (tcp_ecn_rcv_ecn_echo(tp, tcp_hdr(skb)))
+ flag |= FLAG_ECE;
+- ack_ev_flags |= CA_ACK_ECE;
+- }
+
+ if (sack_state.sack_delivered)
+ tcp_count_delivered(tp, sack_state.sack_delivered,
+ flag & FLAG_ECE);
+-
+- if (flag & FLAG_WIN_UPDATE)
+- ack_ev_flags |= CA_ACK_WIN_UPDATE;
+-
+- tcp_in_ack_event(sk, ack_ev_flags);
+ }
+
+ /* This is a deviation from RFC3168 since it states that:
+@@ -4040,6 +4045,8 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
+
+ tcp_rack_update_reo_wnd(sk, &rs);
+
++ tcp_in_ack_event(sk, flag);
++
+ if (tp->tlp_high_seq)
+ tcp_process_tlp_ack(sk, ack, flag);
+
+@@ -4071,6 +4078,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
+ return 1;
+
+ no_queue:
++ tcp_in_ack_event(sk, flag);
+ /* If data was DSACKed, see if we can undo a cwnd reduction. */
+ if (flag & FLAG_DSACKING_ACK) {
+ tcp_fastretrans_alert(sk, prior_snd_una, num_dupack, &flag,
+--
+2.39.5
+
--- /dev/null
+From 1823e72fd611e1a99be6b5a5d2ffe77d57d5d711 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Jan 2025 10:27:15 -0300
+Subject: thermal/drivers/mediatek/lvts: Start sensor interrupts disabled
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Nícolas F. R. A. Prado <nfraprado@collabora.com>
+
+[ Upstream commit 2738fb3ec6838a10d2c4ce65cefdb3b90b11bd61 ]
+
+Interrupts are enabled per sensor in lvts_update_irq_mask() as needed,
+there's no point in enabling all of them during initialization. Change
+the MONINT register initial value so all sensor interrupts start
+disabled.
+
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Signed-off-by: Nícolas F. R. A. Prado <nfraprado@collabora.com>
+Link: https://lore.kernel.org/r/20250113-mt8192-lvts-filtered-suspend-fix-v2-4-07a25200c7c6@collabora.com
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/drivers/thermal/mediatek/lvts_thermal.c b/drivers/thermal/mediatek/lvts_thermal.c
+index 0aaa44b734ca4..d0901d8ac85da 100644
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -65,7 +65,6 @@
+ #define LVTS_HW_FILTER 0x0
+ #define LVTS_TSSEL_CONF 0x13121110
+ #define LVTS_CALSCALE_CONF 0x300
+-#define LVTS_MONINT_CONF 0x0300318C
+
+ #define LVTS_MONINT_OFFSET_SENSOR0 0xC
+ #define LVTS_MONINT_OFFSET_SENSOR1 0x180
+@@ -929,7 +928,7 @@ static int lvts_irq_init(struct lvts_ctrl *lvts_ctrl)
+ * The LVTS_MONINT register layout is the same as the LVTS_MONINTSTS
+ * register, except we set the bits to enable the interrupt.
+ */
+- writel(LVTS_MONINT_CONF, LVTS_MONINT(lvts_ctrl->base));
++ writel(0, LVTS_MONINT(lvts_ctrl->base));
+
+ return 0;
+ }
+--
+2.39.5
+
--- /dev/null
+From 6c437eb9b183aefd4934624385eb7701f13c20b5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 9 Dec 2024 11:48:59 -0500
+Subject: thermal/drivers/qoriq: Power down TMU on system suspend
+
+From: Alice Guo <alice.guo@nxp.com>
+
+[ Upstream commit 229f3feb4b0442835b27d519679168bea2de96c2 ]
+
+Enable power-down of TMU (Thermal Management Unit) for TMU version 2 during
+system suspend to save power. Save approximately 4.3mW on VDD_ANA_1P8 on
+i.MX93 platforms.
+
+Signed-off-by: Alice Guo <alice.guo@nxp.com>
+Signed-off-by: Frank Li <Frank.Li@nxp.com>
+Link: https://lore.kernel.org/r/20241209164859.3758906-2-Frank.Li@nxp.com
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/thermal/qoriq_thermal.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/drivers/thermal/qoriq_thermal.c b/drivers/thermal/qoriq_thermal.c
+index 52e26be8c53df..aed2729f63d06 100644
+--- a/drivers/thermal/qoriq_thermal.c
++++ b/drivers/thermal/qoriq_thermal.c
+@@ -18,6 +18,7 @@
+ #define SITES_MAX 16
+ #define TMR_DISABLE 0x0
+ #define TMR_ME 0x80000000
++#define TMR_CMD BIT(29)
+ #define TMR_ALPF 0x0c000000
+ #define TMR_ALPF_V2 0x03000000
+ #define TMTMIR_DEFAULT 0x0000000f
+@@ -356,6 +357,12 @@ static int qoriq_tmu_suspend(struct device *dev)
+ if (ret)
+ return ret;
+
++ if (data->ver > TMU_VER1) {
++ ret = regmap_set_bits(data->regmap, REGS_TMR, TMR_CMD);
++ if (ret)
++ return ret;
++ }
++
+ clk_disable_unprepare(data->clk);
+
+ return 0;
+@@ -370,6 +377,12 @@ static int qoriq_tmu_resume(struct device *dev)
+ if (ret)
+ return ret;
+
++ if (data->ver > TMU_VER1) {
++ ret = regmap_clear_bits(data->regmap, REGS_TMR, TMR_CMD);
++ if (ret)
++ return ret;
++ }
++
+ /* Enable monitoring */
+ return regmap_update_bits(data->regmap, REGS_TMR, TMR_ME, TMR_ME);
+ }
+--
+2.39.5
+
--- /dev/null
+From 52173ff99a637d0b433ffbd256dd27ccdf4d1bf3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Mar 2025 14:56:20 +0200
+Subject: thunderbolt: Do not add non-active NVM if NVM upgrade is disabled for
+ retimer
+
+From: Mika Westerberg <mika.westerberg@linux.intel.com>
+
+[ Upstream commit ad79c278e478ca8c1a3bf8e7a0afba8f862a48a1 ]
+
+This is only used to write a new NVM in order to upgrade the retimer
+firmware. It does not make sense to expose it if upgrade is disabled.
+This also makes it consistent with the router NVM upgrade.
+
+Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/thunderbolt/retimer.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/thunderbolt/retimer.c b/drivers/thunderbolt/retimer.c
+index 1f25529fe05da..361fece3d8188 100644
+--- a/drivers/thunderbolt/retimer.c
++++ b/drivers/thunderbolt/retimer.c
+@@ -93,9 +93,11 @@ static int tb_retimer_nvm_add(struct tb_retimer *rt)
+ if (ret)
+ goto err_nvm;
+
+- ret = tb_nvm_add_non_active(nvm, nvm_write);
+- if (ret)
+- goto err_nvm;
++ if (!rt->no_nvm_upgrade) {
++ ret = tb_nvm_add_non_active(nvm, nvm_write);
++ if (ret)
++ goto err_nvm;
++ }
+
+ rt->nvm = nvm;
+ dev_dbg(&rt->dev, "NVM version %x.%x\n", nvm->major, nvm->minor);
+--
+2.39.5
+
--- /dev/null
+From e2775bc4f1bfe8e9dc65b105c19d8a0b20f7a633 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Mar 2025 10:54:47 +0100
+Subject: timer_list: Don't use %pK through printk()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
+
+[ Upstream commit a52067c24ccf6ee4c85acffa0f155e9714f9adce ]
+
+This reverts commit f590308536db ("timer debug: Hide kernel addresses via
+%pK in /proc/timer_list")
+
+The timer list helper SEQ_printf() uses either the real seq_printf() for
+procfs output or vprintk() to print to the kernel log, when invoked from
+SysRq-q. It uses %pK for printing pointers.
+
+In the past %pK was prefered over %p as it would not leak raw pointer
+values into the kernel log. Since commit ad67b74d2469 ("printk: hash
+addresses printed with %p") the regular %p has been improved to avoid this
+issue.
+
+Furthermore, restricted pointers ("%pK") were never meant to be used
+through printk(). They can still unintentionally leak raw pointers or
+acquire sleeping looks in atomic contexts.
+
+Switch to the regular pointer formatting which is safer, easier to reason
+about and sufficient here.
+
+Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Link: https://lore.kernel.org/lkml/20250113171731-dc10e3c1-da64-4af0-b767-7c7070468023@linutronix.de/
+Link: https://lore.kernel.org/all/20250311-restricted-pointers-timer-v1-1-6626b91e54ab@linutronix.de
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/time/timer_list.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/kernel/time/timer_list.c b/kernel/time/timer_list.c
+index 1c311c46da507..cfbb46cc4e761 100644
+--- a/kernel/time/timer_list.c
++++ b/kernel/time/timer_list.c
+@@ -46,7 +46,7 @@ static void
+ print_timer(struct seq_file *m, struct hrtimer *taddr, struct hrtimer *timer,
+ int idx, u64 now)
+ {
+- SEQ_printf(m, " #%d: <%pK>, %ps", idx, taddr, timer->function);
++ SEQ_printf(m, " #%d: <%p>, %ps", idx, taddr, timer->function);
+ SEQ_printf(m, ", S:%02x", timer->state);
+ SEQ_printf(m, "\n");
+ SEQ_printf(m, " # expires at %Lu-%Lu nsecs [in %Ld to %Ld nsecs]\n",
+@@ -98,7 +98,7 @@ print_active_timers(struct seq_file *m, struct hrtimer_clock_base *base,
+ static void
+ print_base(struct seq_file *m, struct hrtimer_clock_base *base, u64 now)
+ {
+- SEQ_printf(m, " .base: %pK\n", base);
++ SEQ_printf(m, " .base: %p\n", base);
+ SEQ_printf(m, " .index: %d\n", base->index);
+
+ SEQ_printf(m, " .resolution: %u nsecs\n", hrtimer_resolution);
+--
+2.39.5
+
--- /dev/null
+From 3d702b4757066eac0638436630fbbd660fcc09e3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Mar 2025 14:36:23 -0700
+Subject: tools/build: Don't pass test log files to linker
+
+From: Ian Rogers <irogers@google.com>
+
+[ Upstream commit 935e7cb5bb80106ff4f2fe39640f430134ef8cd8 ]
+
+Separate test log files from object files. Depend on test log output
+but don't pass to the linker.
+
+Reviewed-by: James Clark <james.clark@linaro.org>
+Signed-off-by: Ian Rogers <irogers@google.com>
+Link: https://lore.kernel.org/r/20250311213628.569562-2-irogers@google.com
+Signed-off-by: Namhyung Kim <namhyung@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/build/Makefile.build | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/tools/build/Makefile.build b/tools/build/Makefile.build
+index e710ed67a1b49..3584ff3086078 100644
+--- a/tools/build/Makefile.build
++++ b/tools/build/Makefile.build
+@@ -129,6 +129,10 @@ objprefix := $(subst ./,,$(OUTPUT)$(dir)/)
+ obj-y := $(addprefix $(objprefix),$(obj-y))
+ subdir-obj-y := $(addprefix $(objprefix),$(subdir-obj-y))
+
++# Separate out test log files from real build objects.
++test-y := $(filter %_log, $(obj-y))
++obj-y := $(filter-out %_log, $(obj-y))
++
+ # Final '$(obj)-in.o' object
+ in-target := $(objprefix)$(obj)-in.o
+
+@@ -139,7 +143,7 @@ $(subdir-y):
+
+ $(sort $(subdir-obj-y)): $(subdir-y) ;
+
+-$(in-target): $(obj-y) FORCE
++$(in-target): $(obj-y) $(test-y) FORCE
+ $(call rule_mkdir)
+ $(call if_changed,$(host)ld_multi)
+
+--
+2.39.5
+
--- /dev/null
+From a6b4419ce4f9ee417ae4493d86428febdfc58aac Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Feb 2025 21:46:24 -0600
+Subject: tools/power turbostat: Clustered Uncore MHz counters should honor
+ show/hide options
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Len Brown <len.brown@intel.com>
+
+[ Upstream commit 1c7c7388e6c31f46b26a884d80b45efbad8237b2 ]
+
+The clustered uncore frequency counters, UMHz*.*
+should honor the --show and --hide options.
+
+All non-specified counters should be implicityly hidden.
+But when --show was used, UMHz*.* showed up anyway:
+
+$ sudo turbostat -q -S --show Busy%
+Busy% UMHz0.0 UMHz1.0 UMHz2.0 UMHz3.0 UMHz4.0
+
+Indeed, there was no string that can be used to explicitly
+show or hide clustered uncore counters.
+
+Even through they are dynamically probed and added,
+group the clustered UMHz*.* counters with the legacy
+built-in-counter "UncMHz" for show/hide.
+
+turbostat --show Busy%
+ does not show UMHz*.*.
+turbostat --show UncMHz
+ shows either UncMHz or UMHz*.*, if present
+turbostat --hide UncMHz
+ hides either UncMHz or UMHz*.*, if present
+
+Reported-by: Artem Bityutskiy <artem.bityutskiy@intel.com>
+Signed-off-by: Len Brown <len.brown@intel.com>
+Tested-by: Artem Bityutskiy <artem.bityutskiy@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/power/x86/turbostat/turbostat.8 | 1 +
+ tools/power/x86/turbostat/turbostat.c | 13 ++++++++++++-
+ 2 files changed, 13 insertions(+), 1 deletion(-)
+
+diff --git a/tools/power/x86/turbostat/turbostat.8 b/tools/power/x86/turbostat/turbostat.8
+index e4f9f93c123a2..abee03ddc7f09 100644
+--- a/tools/power/x86/turbostat/turbostat.8
++++ b/tools/power/x86/turbostat/turbostat.8
+@@ -201,6 +201,7 @@ The system configuration dump (if --quiet is not used) is followed by statistics
+ \fBUncMHz\fP per-package uncore MHz, instantaneous sample.
+ .PP
+ \fBUMHz1.0\fP per-package uncore MHz for domain=1 and fabric_cluster=0, instantaneous sample. System summary is the average of all packages.
++For the "--show" and "--hide" options, use "UncMHz" to operate on all UMHz*.* as a group.
+ .SH TOO MUCH INFORMATION EXAMPLE
+ By default, turbostat dumps all possible information -- a system configuration header, followed by columns for all counters.
+ This is ideal for remote debugging, use the "--out" option to save everything to a text file, and get that file to the expert helping you debug.
+diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
+index 4155d9bfcfc6d..505b07b5be19b 100644
+--- a/tools/power/x86/turbostat/turbostat.c
++++ b/tools/power/x86/turbostat/turbostat.c
+@@ -6713,7 +6713,18 @@ static void probe_intel_uncore_frequency_cluster(void)
+ sprintf(path, "%s/current_freq_khz", path_base);
+ sprintf(name_buf, "UMHz%d.%d", domain_id, cluster_id);
+
+- add_counter(0, path, name_buf, 0, SCOPE_PACKAGE, COUNTER_K2M, FORMAT_AVERAGE, 0, package_id);
++ /*
++ * Once add_couter() is called, that counter is always read
++ * and reported -- So it is effectively (enabled & present).
++ * Only call add_counter() here if legacy BIC_UNCORE_MHZ (UncMHz)
++ * is (enabled). Since we are in this routine, we
++ * know we will not probe and set (present) the legacy counter.
++ *
++ * This allows "--show/--hide UncMHz" to be effective for
++ * the clustered MHz counters, as a group.
++ */
++ if BIC_IS_ENABLED(BIC_UNCORE_MHZ)
++ add_counter(0, path, name_buf, 0, SCOPE_PACKAGE, COUNTER_K2M, FORMAT_AVERAGE, 0, package_id);
+
+ if (quiet)
+ continue;
+--
+2.39.5
+
--- /dev/null
+From dbab61b04f2e2ce57a47353afb6661207173fad8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Feb 2025 13:55:09 -0800
+Subject: tools: ynl-gen: don't output external constants
+
+From: Jakub Kicinski <kuba@kernel.org>
+
+[ Upstream commit 7e8b24e24ac46038e48c9a042e7d9b31855cbca5 ]
+
+A definition with a "header" property is an "external" definition
+for C code, as in it is defined already in another C header file.
+Other languages will need the exact value but C codegen should
+not recreate it. So don't output those definitions in the uAPI
+header.
+
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Link: https://patch.msgid.link/20250203215510.1288728-1-kuba@kernel.org
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/net/ynl/pyynl/ynl_gen_c.py | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py
+index c2eabc90dce8c..aa08b8b1463d0 100755
+--- a/tools/net/ynl/pyynl/ynl_gen_c.py
++++ b/tools/net/ynl/pyynl/ynl_gen_c.py
+@@ -2549,6 +2549,9 @@ def render_uapi(family, cw):
+
+ defines = []
+ for const in family['definitions']:
++ if const.get('header'):
++ continue
++
+ if const['type'] != 'const':
+ cw.writes_defines(defines)
+ defines = []
+--
+2.39.5
+
--- /dev/null
+From 892a1a58dfb108bf55e41fd74c09dca63b7d1f0f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 2 May 2025 21:30:50 -0700
+Subject: tools: ynl-gen: validate 0 len strings from kernel
+
+From: David Wei <dw@davidwei.uk>
+
+[ Upstream commit 4720f9707c783f642332dee3d56dccaefa850e42 ]
+
+Strings from the kernel are guaranteed to be null terminated and
+ynl_attr_validate() checks for this. But it doesn't check if the string
+has a len of 0, which would cause problems when trying to access
+data[len - 1]. Fix this by checking that len is positive.
+
+Signed-off-by: David Wei <dw@davidwei.uk>
+Link: https://patch.msgid.link/20250503043050.861238-1-dw@davidwei.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/net/ynl/lib/ynl.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/tools/net/ynl/lib/ynl.c b/tools/net/ynl/lib/ynl.c
+index ce32cb35007d6..c4da34048ef85 100644
+--- a/tools/net/ynl/lib/ynl.c
++++ b/tools/net/ynl/lib/ynl.c
+@@ -364,7 +364,7 @@ int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr)
+ "Invalid attribute (binary %s)", policy->name);
+ return -1;
+ case YNL_PT_NUL_STR:
+- if ((!policy->len || len <= policy->len) && !data[len - 1])
++ if (len && (!policy->len || len <= policy->len) && !data[len - 1])
+ break;
+ yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
+ "Invalid attribute (string %s)", policy->name);
+--
+2.39.5
+
--- /dev/null
+From 0fe5d7ef69b3e0748045d57a7287a4b952946056 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 7 Mar 2025 10:56:44 +0000
+Subject: tpm: Convert warn to dbg in tpm2_start_auth_session()
+
+From: Jonathan McDowell <noodles@meta.com>
+
+[ Upstream commit 6359691b4fbcaf3ed86f53043a1f7c6cc54c09be ]
+
+TPM2 sessions have been flushed lazily since commit df745e25098dc ("tpm:
+Lazily flush the auth session"). If /dev/tpm{rm}0 is not accessed
+in-between two in-kernel calls, it is possible that a TPM2 session is
+re-started before the previous one has been completed.
+
+This causes a spurios warning in a legit run-time condition, which is also
+correctly addressed with a fast return path:
+
+[ 2.944047] tpm tpm0: auth session is active
+
+Address the issue by changing dev_warn_once() call to a dev_dbg_once()
+call.
+
+[jarkko: Rewrote the commit message, and instead of dropping converted
+ to a debug message.]
+Signed-off-by: Jonathan McDowell <noodles@meta.com>
+Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/char/tpm/tpm2-sessions.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/char/tpm/tpm2-sessions.c b/drivers/char/tpm/tpm2-sessions.c
+index a894dbc40e43b..7b5049b3d476e 100644
+--- a/drivers/char/tpm/tpm2-sessions.c
++++ b/drivers/char/tpm/tpm2-sessions.c
+@@ -974,7 +974,7 @@ int tpm2_start_auth_session(struct tpm_chip *chip)
+ int rc;
+
+ if (chip->auth) {
+- dev_warn_once(&chip->dev, "auth session is active\n");
++ dev_dbg_once(&chip->dev, "auth session is active\n");
+ return 0;
+ }
+
+--
+2.39.5
+
--- /dev/null
+From c426debe58a60bdd4eb36a9d9c0ece447f7889a4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 21 Mar 2025 16:40:49 +0200
+Subject: tracing: Mark binary printing functions with __printf() attribute
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+
+[ Upstream commit 196a062641fe68d9bfe0ad36b6cd7628c99ad22c ]
+
+Binary printing functions are using printf() type of format, and compiler
+is not happy about them as is:
+
+kernel/trace/trace.c:3292:9: error: function ‘trace_vbprintk’ might be a candidate for ‘gnu_printf’ format attribute [-Werror=suggest-attribute=format]
+kernel/trace/trace_seq.c:182:9: error: function ‘trace_seq_bprintf’ might be a candidate for ‘gnu_printf’ format attribute [-Werror=suggest-attribute=format]
+
+Fix the compilation errors by adding __printf() attribute.
+
+While at it, move existing __printf() attributes from the implementations
+to the declarations. IT also fixes incorrect attribute parameters that are
+used for trace_array_printk().
+
+Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Reviewed-by: Kees Cook <kees@kernel.org>
+Reviewed-by: Petr Mladek <pmladek@suse.com>
+Link: https://lore.kernel.org/r/20250321144822.324050-4-andriy.shevchenko@linux.intel.com
+Signed-off-by: Petr Mladek <pmladek@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/trace.h | 4 ++--
+ include/linux/trace_seq.h | 8 ++++----
+ kernel/trace/trace.c | 11 +++--------
+ kernel/trace/trace.h | 16 +++++++++-------
+ 4 files changed, 18 insertions(+), 21 deletions(-)
+
+diff --git a/include/linux/trace.h b/include/linux/trace.h
+index fdcd76b7be83d..7eaad857dee04 100644
+--- a/include/linux/trace.h
++++ b/include/linux/trace.h
+@@ -72,8 +72,8 @@ static inline int unregister_ftrace_export(struct trace_export *export)
+ static inline void trace_printk_init_buffers(void)
+ {
+ }
+-static inline int trace_array_printk(struct trace_array *tr, unsigned long ip,
+- const char *fmt, ...)
++static inline __printf(3, 4)
++int trace_array_printk(struct trace_array *tr, unsigned long ip, const char *fmt, ...)
+ {
+ return 0;
+ }
+diff --git a/include/linux/trace_seq.h b/include/linux/trace_seq.h
+index 1ef95c0287f05..a93ed5ac32265 100644
+--- a/include/linux/trace_seq.h
++++ b/include/linux/trace_seq.h
+@@ -88,8 +88,8 @@ extern __printf(2, 3)
+ void trace_seq_printf(struct trace_seq *s, const char *fmt, ...);
+ extern __printf(2, 0)
+ void trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args);
+-extern void
+-trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary);
++extern __printf(2, 0)
++void trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary);
+ extern int trace_print_seq(struct seq_file *m, struct trace_seq *s);
+ extern int trace_seq_to_user(struct trace_seq *s, char __user *ubuf,
+ int cnt);
+@@ -113,8 +113,8 @@ static inline __printf(2, 3)
+ void trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
+ {
+ }
+-static inline void
+-trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary)
++static inline __printf(2, 0)
++void trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary)
+ {
+ }
+
+diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
+index c3f1365ec9609..b1738563bdc3b 100644
+--- a/kernel/trace/trace.c
++++ b/kernel/trace/trace.c
+@@ -3322,10 +3322,9 @@ int trace_vbprintk(unsigned long ip, const char *fmt, va_list args)
+ }
+ EXPORT_SYMBOL_GPL(trace_vbprintk);
+
+-__printf(3, 0)
+-static int
+-__trace_array_vprintk(struct trace_buffer *buffer,
+- unsigned long ip, const char *fmt, va_list args)
++static __printf(3, 0)
++int __trace_array_vprintk(struct trace_buffer *buffer,
++ unsigned long ip, const char *fmt, va_list args)
+ {
+ struct ring_buffer_event *event;
+ int len = 0, size;
+@@ -3375,7 +3374,6 @@ __trace_array_vprintk(struct trace_buffer *buffer,
+ return len;
+ }
+
+-__printf(3, 0)
+ int trace_array_vprintk(struct trace_array *tr,
+ unsigned long ip, const char *fmt, va_list args)
+ {
+@@ -3405,7 +3403,6 @@ int trace_array_vprintk(struct trace_array *tr,
+ * Note, trace_array_init_printk() must be called on @tr before this
+ * can be used.
+ */
+-__printf(3, 0)
+ int trace_array_printk(struct trace_array *tr,
+ unsigned long ip, const char *fmt, ...)
+ {
+@@ -3450,7 +3447,6 @@ int trace_array_init_printk(struct trace_array *tr)
+ }
+ EXPORT_SYMBOL_GPL(trace_array_init_printk);
+
+-__printf(3, 4)
+ int trace_array_printk_buf(struct trace_buffer *buffer,
+ unsigned long ip, const char *fmt, ...)
+ {
+@@ -3466,7 +3462,6 @@ int trace_array_printk_buf(struct trace_buffer *buffer,
+ return ret;
+ }
+
+-__printf(2, 0)
+ int trace_vprintk(unsigned long ip, const char *fmt, va_list args)
+ {
+ return trace_array_vprintk(printk_trace, ip, fmt, args);
+diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
+index abe8169c3e879..ccf3874823f5f 100644
+--- a/kernel/trace/trace.h
++++ b/kernel/trace/trace.h
+@@ -837,13 +837,15 @@ static inline void __init disable_tracing_selftest(const char *reason)
+
+ extern void *head_page(struct trace_array_cpu *data);
+ extern unsigned long long ns2usecs(u64 nsec);
+-extern int
+-trace_vbprintk(unsigned long ip, const char *fmt, va_list args);
+-extern int
+-trace_vprintk(unsigned long ip, const char *fmt, va_list args);
+-extern int
+-trace_array_vprintk(struct trace_array *tr,
+- unsigned long ip, const char *fmt, va_list args);
++
++__printf(2, 0)
++int trace_vbprintk(unsigned long ip, const char *fmt, va_list args);
++__printf(2, 0)
++int trace_vprintk(unsigned long ip, const char *fmt, va_list args);
++__printf(3, 0)
++int trace_array_vprintk(struct trace_array *tr,
++ unsigned long ip, const char *fmt, va_list args);
++__printf(3, 4)
+ int trace_array_printk_buf(struct trace_buffer *buffer,
+ unsigned long ip, const char *fmt, ...);
+ void trace_printk_seq(struct trace_seq *s);
+--
+2.39.5
+
--- /dev/null
+From 0399853a460c8aab3b99358b51653516c9b22553 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 25 Feb 2025 14:24:55 -0700
+Subject: ublk: complete command synchronously on error
+
+From: Caleb Sander Mateos <csander@purestorage.com>
+
+[ Upstream commit 603f9be21c1894e462416e3324962d6c9c2b95f8 ]
+
+In case of an error, ublk's ->uring_cmd() functions currently return
+-EIOCBQUEUED and immediately call io_uring_cmd_done(). -EIOCBQUEUED and
+io_uring_cmd_done() are intended for asynchronous completions. For
+synchronous completions, the ->uring_cmd() function can just return the
+negative return code directly. This skips io_uring_cmd_del_cancelable(),
+and deferring the completion to task work. So return the error code
+directly from __ublk_ch_uring_cmd() and ublk_ctrl_uring_cmd().
+
+Update ublk_ch_uring_cmd_cb(), which currently ignores the return value
+from __ublk_ch_uring_cmd(), to call io_uring_cmd_done() for synchronous
+completions.
+
+Signed-off-by: Caleb Sander Mateos <csander@purestorage.com>
+Reviewed-by: Ming Lei <ming.lei@redhat.com>
+Reviewed-by: Keith Busch <kbusch@kernel.org>
+Link: https://lore.kernel.org/r/20250225212456.2902549-1-csander@purestorage.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/block/ublk_drv.c | 11 ++++++-----
+ 1 file changed, 6 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
+index b462f7d16ee55..08694d7d18db4 100644
+--- a/drivers/block/ublk_drv.c
++++ b/drivers/block/ublk_drv.c
+@@ -2053,10 +2053,9 @@ static int __ublk_ch_uring_cmd(struct io_uring_cmd *cmd,
+ return -EIOCBQUEUED;
+
+ out:
+- io_uring_cmd_done(cmd, ret, 0, issue_flags);
+ pr_devel("%s: complete: cmd op %d, tag %d ret %x io_flags %x\n",
+ __func__, cmd_op, tag, ret, io->flags);
+- return -EIOCBQUEUED;
++ return ret;
+ }
+
+ static inline struct request *__ublk_check_and_get_req(struct ublk_device *ub,
+@@ -2112,7 +2111,10 @@ static inline int ublk_ch_uring_cmd_local(struct io_uring_cmd *cmd,
+ static void ublk_ch_uring_cmd_cb(struct io_uring_cmd *cmd,
+ unsigned int issue_flags)
+ {
+- ublk_ch_uring_cmd_local(cmd, issue_flags);
++ int ret = ublk_ch_uring_cmd_local(cmd, issue_flags);
++
++ if (ret != -EIOCBQUEUED)
++ io_uring_cmd_done(cmd, ret, 0, issue_flags);
+ }
+
+ static int ublk_ch_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
+@@ -3201,10 +3203,9 @@ static int ublk_ctrl_uring_cmd(struct io_uring_cmd *cmd,
+ if (ub)
+ ublk_put_device(ub);
+ out:
+- io_uring_cmd_done(cmd, ret, 0, issue_flags);
+ 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);
+- return -EIOCBQUEUED;
++ return ret;
+ }
+
+ static const struct file_operations ublk_ctl_fops = {
+--
+2.39.5
+
--- /dev/null
+From 9513bae680bc9a57ce79630337e7582e3d3ab88b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 28 Feb 2025 21:31:48 -0700
+Subject: ublk: enforce ublks_max only for unprivileged devices
+
+From: Uday Shankar <ushankar@purestorage.com>
+
+[ Upstream commit 80bdfbb3545b6f16680a72c825063d08a6b44c7a ]
+
+Commit 403ebc877832 ("ublk_drv: add module parameter of ublks_max for
+limiting max allowed ublk dev"), claimed ublks_max was added to prevent
+a DoS situation with an untrusted user creating too many ublk devices.
+If that's the case, ublks_max should only restrict the number of
+unprivileged ublk devices in the system. Enforce the limit only for
+unprivileged ublk devices, and rename variables accordingly. Leave the
+external-facing parameter name unchanged, since changing it may break
+systems which use it (but still update its documentation to reflect its
+new meaning).
+
+As a result of this change, in a system where there are only normal
+(non-unprivileged) devices, the maximum number of such devices is
+increased to 1 << MINORBITS, or 1048576. That ought to be enough for
+anyone, right?
+
+Signed-off-by: Uday Shankar <ushankar@purestorage.com>
+Reviewed-by: Ming Lei <ming.lei@redhat.com>
+Link: https://lore.kernel.org/r/20250228-ublks_max-v1-1-04b7379190c0@purestorage.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/block/ublk_drv.c | 42 ++++++++++++++++++++++++++--------------
+ 1 file changed, 27 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
+index 7bbfc20f116a4..b462f7d16ee55 100644
+--- a/drivers/block/ublk_drv.c
++++ b/drivers/block/ublk_drv.c
+@@ -490,15 +490,17 @@ static wait_queue_head_t ublk_idr_wq; /* wait until one idr is freed */
+
+ static DEFINE_MUTEX(ublk_ctl_mutex);
+
++
++#define UBLK_MAX_UBLKS UBLK_MINORS
++
+ /*
+- * Max ublk devices allowed to add
++ * Max unprivileged ublk devices allowed to add
+ *
+ * It can be extended to one per-user limit in future or even controlled
+ * by cgroup.
+ */
+-#define UBLK_MAX_UBLKS UBLK_MINORS
+-static unsigned int ublks_max = 64;
+-static unsigned int ublks_added; /* protected by ublk_ctl_mutex */
++static unsigned int unprivileged_ublks_max = 64;
++static unsigned int unprivileged_ublks_added; /* protected by ublk_ctl_mutex */
+
+ static struct miscdevice ublk_misc;
+
+@@ -2375,7 +2377,8 @@ static int ublk_add_chdev(struct ublk_device *ub)
+ if (ret)
+ goto fail;
+
+- ublks_added++;
++ if (ub->dev_info.flags & UBLK_F_UNPRIVILEGED_DEV)
++ unprivileged_ublks_added++;
+ return 0;
+ fail:
+ put_device(dev);
+@@ -2404,10 +2407,15 @@ static int ublk_add_tag_set(struct ublk_device *ub)
+
+ static void ublk_remove(struct ublk_device *ub)
+ {
++ bool unprivileged;
++
+ ublk_stop_dev(ub);
+ cdev_device_del(&ub->cdev, &ub->cdev_dev);
++ unprivileged = ub->dev_info.flags & UBLK_F_UNPRIVILEGED_DEV;
+ ublk_put_device(ub);
+- ublks_added--;
++
++ if (unprivileged)
++ unprivileged_ublks_added--;
+ }
+
+ static struct ublk_device *ublk_get_device_from_id(int idx)
+@@ -2669,7 +2677,8 @@ static int ublk_ctrl_add_dev(struct io_uring_cmd *cmd)
+ return ret;
+
+ ret = -EACCES;
+- if (ublks_added >= ublks_max)
++ if ((info.flags & UBLK_F_UNPRIVILEGED_DEV) &&
++ unprivileged_ublks_added >= unprivileged_ublks_max)
+ goto out_unlock;
+
+ ret = -ENOMEM;
+@@ -3259,23 +3268,26 @@ static void __exit ublk_exit(void)
+ module_init(ublk_init);
+ module_exit(ublk_exit);
+
+-static int ublk_set_max_ublks(const char *buf, const struct kernel_param *kp)
++static int ublk_set_max_unprivileged_ublks(const char *buf,
++ const struct kernel_param *kp)
+ {
+ return param_set_uint_minmax(buf, kp, 0, UBLK_MAX_UBLKS);
+ }
+
+-static int ublk_get_max_ublks(char *buf, const struct kernel_param *kp)
++static int ublk_get_max_unprivileged_ublks(char *buf,
++ const struct kernel_param *kp)
+ {
+- return sysfs_emit(buf, "%u\n", ublks_max);
++ return sysfs_emit(buf, "%u\n", unprivileged_ublks_max);
+ }
+
+-static const struct kernel_param_ops ublk_max_ublks_ops = {
+- .set = ublk_set_max_ublks,
+- .get = ublk_get_max_ublks,
++static const struct kernel_param_ops ublk_max_unprivileged_ublks_ops = {
++ .set = ublk_set_max_unprivileged_ublks,
++ .get = ublk_get_max_unprivileged_ublks,
+ };
+
+-module_param_cb(ublks_max, &ublk_max_ublks_ops, &ublks_max, 0644);
+-MODULE_PARM_DESC(ublks_max, "max number of ublk devices allowed to add(default: 64)");
++module_param_cb(ublks_max, &ublk_max_unprivileged_ublks_ops,
++ &unprivileged_ublks_max, 0644);
++MODULE_PARM_DESC(ublks_max, "max number of unprivileged ublk devices allowed to add(default: 64)");
+
+ MODULE_AUTHOR("Ming Lei <ming.lei@redhat.com>");
+ MODULE_DESCRIPTION("Userspace block device");
+--
+2.39.5
+
--- /dev/null
+From 28d4fa564c8a2230a490b23404bd5b8e64c60060 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 24 Feb 2025 19:18:19 +0100
+Subject: um: Store full CSGSFS and SS register from mcontext
+
+From: Benjamin Berg <benjamin@sipsolutions.net>
+
+[ Upstream commit cef721e0d53d2b64f2ba177c63a0dfdd7c0daf17 ]
+
+Doing this allows using registers as retrieved from an mcontext to be
+pushed to a process using PTRACE_SETREGS.
+
+It is not entirely clear to me why CSGSFS was masked. Doing so creates
+issues when using the mcontext as process state in seccomp and simply
+copying the register appears to work perfectly fine for ptrace.
+
+Signed-off-by: Benjamin Berg <benjamin@sipsolutions.net>
+Link: https://patch.msgid.link/20250224181827.647129-2-benjamin@sipsolutions.net
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/um/os-Linux/mcontext.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/arch/x86/um/os-Linux/mcontext.c b/arch/x86/um/os-Linux/mcontext.c
+index e80ab7d281177..1b0d95328b2c7 100644
+--- a/arch/x86/um/os-Linux/mcontext.c
++++ b/arch/x86/um/os-Linux/mcontext.c
+@@ -27,7 +27,6 @@ void get_regs_from_mc(struct uml_pt_regs *regs, mcontext_t *mc)
+ COPY(RIP);
+ COPY2(EFLAGS, EFL);
+ COPY2(CS, CSGSFS);
+- regs->gp[CS / sizeof(unsigned long)] &= 0xffff;
+- regs->gp[CS / sizeof(unsigned long)] |= 3;
++ regs->gp[SS / sizeof(unsigned long)] = mc->gregs[REG_CSGSFS] >> 48;
+ #endif
+ }
+--
+2.39.5
+
--- /dev/null
+From e6c08b7a852846704105ca8dd647ce3b858c1506 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 21 Feb 2025 12:18:55 +0800
+Subject: um: Update min_low_pfn to match changes in uml_reserved
+
+From: Tiwei Bie <tiwei.btw@antgroup.com>
+
+[ Upstream commit e82cf3051e6193f61e03898f8dba035199064d36 ]
+
+When uml_reserved is updated, min_low_pfn must also be updated
+accordingly. Otherwise, min_low_pfn will not accurately reflect
+the lowest available PFN.
+
+Signed-off-by: Tiwei Bie <tiwei.btw@antgroup.com>
+Link: https://patch.msgid.link/20250221041855.1156109-1-tiwei.btw@antgroup.com
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/um/kernel/mem.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c
+index befed230aac28..91b7710c0a5f4 100644
+--- a/arch/um/kernel/mem.c
++++ b/arch/um/kernel/mem.c
+@@ -66,6 +66,7 @@ void __init mem_init(void)
+ map_memory(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0);
+ memblock_free((void *)brk_end, uml_reserved - brk_end);
+ uml_reserved = brk_end;
++ min_low_pfn = PFN_UP(__pa(uml_reserved));
+
+ /* this will put all low memory onto the freelists */
+ memblock_free_all();
+--
+2.39.5
+
--- /dev/null
+From 65f3e90097ec2d8929254e482e75be5f563f7e6d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Mar 2025 17:45:50 +0200
+Subject: usb: xhci: Don't change the status of stalled TDs on failed Stop EP
+
+From: Michal Pecio <michal.pecio@gmail.com>
+
+[ Upstream commit dfc88357b6b6356dadea06b2c0bc8041f5e11720 ]
+
+When the device stalls an endpoint, current TD is assigned -EPIPE
+status and Reset Endpoint is queued. If a Stop Endpoint is pending
+at the time, it will run before Reset Endpoint and fail due to the
+stall. Its handler will change TD's status to -EPROTO before Reset
+Endpoint handler runs and initiates giveback.
+
+Check if the stall has already been handled and don't try to do it
+again. Since xhci_handle_halted_endpoint() performs this check too,
+not overwriting td->status is the only difference.
+
+I haven't seen this case yet, but I have seen a related one where
+the xHC has already executed Reset Endpoint, EP Context state is
+now Stopped and EP_HALTED is set. If the xHC took a bit longer to
+execute Reset Endpoint, said case would become this one.
+
+Signed-off-by: Michal Pecio <michal.pecio@gmail.com>
+Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
+Link: https://lore.kernel.org/r/20250311154551.4035726-3-mathias.nyman@linux.intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/host/xhci-ring.c | 12 +++++++++++-
+ 1 file changed, 11 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
+index 5a0e361818c27..073b0acd8a742 100644
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -1164,7 +1164,14 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id,
+ */
+ switch (GET_EP_CTX_STATE(ep_ctx)) {
+ case EP_STATE_HALTED:
+- xhci_dbg(xhci, "Stop ep completion raced with stall, reset ep\n");
++ xhci_dbg(xhci, "Stop ep completion raced with stall\n");
++ /*
++ * If the halt happened before Stop Endpoint failed, its transfer event
++ * should have already been handled and Reset Endpoint should be pending.
++ */
++ if (ep->ep_state & EP_HALTED)
++ goto reset_done;
++
+ if (ep->ep_state & EP_HAS_STREAMS) {
+ reset_type = EP_SOFT_RESET;
+ } else {
+@@ -1175,8 +1182,11 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id,
+ }
+ /* reset ep, reset handler cleans up cancelled tds */
+ err = xhci_handle_halted_endpoint(xhci, ep, td, reset_type);
++ xhci_dbg(xhci, "Stop ep completion resetting ep, status %d\n", err);
+ if (err)
+ break;
++reset_done:
++ /* Reset EP handler will clean up cancelled TDs */
+ ep->ep_state &= ~EP_STOP_CMD_PENDING;
+ return;
+ case EP_STATE_STOPPED:
+--
+2.39.5
+
--- /dev/null
+From ddf28dfef649686bf9578b0fa1ff7c66fe7d5451 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Mar 2025 16:49:48 +0200
+Subject: usb: xhci: set page size to the xHCI-supported size
+
+From: Niklas Neronin <niklas.neronin@linux.intel.com>
+
+[ Upstream commit 68c1f1671650b49bbd26e6a65ddcf33f2565efa3 ]
+
+The current xHCI driver does not validate whether a page size of 4096
+bytes is supported. Address the issue by setting the page size to the
+value supported by the xHCI controller, as read from the Page Size
+register. In the event of an unexpected value; default to a 4K page size.
+
+Additionally, this commit removes unnecessary debug messages and instead
+prints the supported and used page size once.
+
+The xHCI controller supports page sizes of (2^{(n+12)}) bytes, where 'n'
+is the Page Size Bit. Only one page size is supported, with a maximum
+page size of 128 KB.
+
+Signed-off-by: Niklas Neronin <niklas.neronin@linux.intel.com>
+Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
+Link: https://lore.kernel.org/r/20250306144954.3507700-10-mathias.nyman@linux.intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/host/xhci-mem.c | 34 ++++++++++++++++++----------------
+ drivers/usb/host/xhci.h | 8 ++++----
+ 2 files changed, 22 insertions(+), 20 deletions(-)
+
+diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
+index 9aa7e2a876ec1..d698095fc88d3 100644
+--- a/drivers/usb/host/xhci-mem.c
++++ b/drivers/usb/host/xhci-mem.c
+@@ -1953,7 +1953,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
+ xhci->interrupters = NULL;
+
+ xhci->page_size = 0;
+- xhci->page_shift = 0;
+ xhci->usb2_rhub.bus_state.bus_suspended = 0;
+ xhci->usb3_rhub.bus_state.bus_suspended = 0;
+ }
+@@ -2372,6 +2371,22 @@ xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs,
+ }
+ EXPORT_SYMBOL_GPL(xhci_create_secondary_interrupter);
+
++static void xhci_hcd_page_size(struct xhci_hcd *xhci)
++{
++ u32 page_size;
++
++ page_size = readl(&xhci->op_regs->page_size) & XHCI_PAGE_SIZE_MASK;
++ if (!is_power_of_2(page_size)) {
++ xhci_warn(xhci, "Invalid page size register = 0x%x\n", page_size);
++ /* Fallback to 4K page size, since that's common */
++ page_size = 1;
++ }
++
++ xhci->page_size = page_size << 12;
++ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "HCD page size set to %iK",
++ xhci->page_size >> 10);
++}
++
+ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
+ {
+ struct xhci_interrupter *ir;
+@@ -2379,7 +2394,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
+ dma_addr_t dma;
+ unsigned int val, val2;
+ u64 val_64;
+- u32 page_size, temp;
++ u32 temp;
+ int i;
+
+ INIT_LIST_HEAD(&xhci->cmd_list);
+@@ -2388,20 +2403,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
+ INIT_DELAYED_WORK(&xhci->cmd_timer, xhci_handle_command_timeout);
+ init_completion(&xhci->cmd_ring_stop_completion);
+
+- page_size = readl(&xhci->op_regs->page_size);
+- xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+- "Supported page size register = 0x%x", page_size);
+- val = ffs(page_size) - 1;
+- if (val < 16)
+- xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+- "Supported page size of %iK", (1 << (val + 12)) / 1024);
+- else
+- xhci_warn(xhci, "WARN: no supported page size\n");
+- /* Use 4K pages, since that's common and the minimum the HC supports */
+- xhci->page_shift = 12;
+- xhci->page_size = 1 << xhci->page_shift;
+- xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+- "HCD page size set to %iK", xhci->page_size / 1024);
++ xhci_hcd_page_size(xhci);
+
+ /*
+ * Program the Number of Device Slots Enabled field in the CONFIG
+diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
+index 2c394cba120f1..7d22617417fe0 100644
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -211,6 +211,9 @@ struct xhci_op_regs {
+ #define CONFIG_CIE (1 << 9)
+ /* bits 10:31 - reserved and should be preserved */
+
++/* bits 15:0 - HCD page shift bit */
++#define XHCI_PAGE_SIZE_MASK 0xffff
++
+ /**
+ * struct xhci_intr_reg - Interrupt Register Set
+ * @irq_pending: IMAN - Interrupt Management Register. Used to enable
+@@ -1514,10 +1517,7 @@ struct xhci_hcd {
+ u16 max_interrupters;
+ /* imod_interval in ns (I * 250ns) */
+ u32 imod_interval;
+- /* 4KB min, 128MB max */
+- int page_size;
+- /* Valid values are 12 to 20, inclusive */
+- int page_shift;
++ u32 page_size;
+ /* MSI-X/MSI vectors */
+ int nvecs;
+ /* optional clocks */
+--
+2.39.5
+
--- /dev/null
+From 6b463aa15b2287c2faa911e3719635f2f26732c6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Feb 2025 11:31:27 -0600
+Subject: vdpa/mlx5: Fix mlx5_vdpa_get_config() endianness on big-endian
+ machines
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Konstantin Shkolnyy <kshk@linux.ibm.com>
+
+[ Upstream commit 439252e167ac45a5d46f573aac1da7d8f3e051ad ]
+
+mlx5_vdpa_dev_add() doesn’t initialize mvdev->actual_features. It’s
+initialized later by mlx5_vdpa_set_driver_features(). However,
+mlx5_vdpa_get_config() depends on the VIRTIO_F_VERSION_1 flag in
+actual_features, to return data with correct endianness. When it’s called
+before mlx5_vdpa_set_driver_features(), the data are incorrectly returned
+as big-endian on big-endian machines, while QEMU then interprets them as
+little-endian.
+
+The fix is to initialize this VIRTIO_F_VERSION_1 as early as possible,
+especially considering that mlx5_vdpa_dev_add() insists on this flag to
+always be set anyway.
+
+Signed-off-by: Konstantin Shkolnyy <kshk@linux.ibm.com>
+Message-Id: <20250204173127.166673-1-kshk@linux.ibm.com>
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Reviewed-by: Dragos Tatulea <dtatulea@nvidia.com>
+Acked-by: Jason Wang <jasowang@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/vdpa/mlx5/net/mlx5_vnet.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c
+index 36099047560df..cccc49a08a1ab 100644
+--- a/drivers/vdpa/mlx5/net/mlx5_vnet.c
++++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c
+@@ -3884,6 +3884,9 @@ static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name,
+ ndev->mvdev.max_vqs = max_vqs;
+ mvdev = &ndev->mvdev;
+ mvdev->mdev = mdev;
++ /* cpu_to_mlx5vdpa16() below depends on this flag */
++ mvdev->actual_features =
++ (device_features & BIT_ULL(VIRTIO_F_VERSION_1));
+
+ ndev->vqs = kcalloc(max_vqs, sizeof(*ndev->vqs), GFP_KERNEL);
+ ndev->event_cbs = kcalloc(max_vqs + 1, sizeof(*ndev->event_cbs), GFP_KERNEL);
+--
+2.39.5
+
--- /dev/null
+From ecd65b6a38ccf5cf27922b6af3234307e76005cb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Mar 2025 17:06:21 -0600
+Subject: vfio/pci: Handle INTx IRQ_NOTCONNECTED
+
+From: Alex Williamson <alex.williamson@redhat.com>
+
+[ Upstream commit 860be250fc32de9cb24154bf21b4e36f40925707 ]
+
+Some systems report INTx as not routed by setting pdev->irq to
+IRQ_NOTCONNECTED, resulting in a -ENOTCONN error when trying to
+setup eventfd signaling. Include this in the set of conditions
+for which the PIN register is virtualized to zero.
+
+Additionally consolidate vfio_pci_get_irq_count() to use this
+virtualized value in reporting INTx support via ioctl and sanity
+checking ioctl paths since pdev->irq is re-used when the device
+is in MSI mode.
+
+The combination of these results in both the config space of the
+device and the ioctl interface behaving as if the device does not
+support INTx.
+
+Reviewed-by: Kevin Tian <kevin.tian@intel.com>
+Link: https://lore.kernel.org/r/20250311230623.1264283-1-alex.williamson@redhat.com
+Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/vfio/pci/vfio_pci_config.c | 3 ++-
+ drivers/vfio/pci/vfio_pci_core.c | 10 +---------
+ drivers/vfio/pci/vfio_pci_intrs.c | 2 +-
+ 3 files changed, 4 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c
+index 94142581c98ce..14437396d7211 100644
+--- a/drivers/vfio/pci/vfio_pci_config.c
++++ b/drivers/vfio/pci/vfio_pci_config.c
+@@ -1814,7 +1814,8 @@ int vfio_config_init(struct vfio_pci_core_device *vdev)
+ cpu_to_le16(PCI_COMMAND_MEMORY);
+ }
+
+- if (!IS_ENABLED(CONFIG_VFIO_PCI_INTX) || vdev->nointx)
++ if (!IS_ENABLED(CONFIG_VFIO_PCI_INTX) || vdev->nointx ||
++ vdev->pdev->irq == IRQ_NOTCONNECTED)
+ vconfig[PCI_INTERRUPT_PIN] = 0;
+
+ ret = vfio_cap_init(vdev);
+diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c
+index a071f42511d3b..b8bfc909fd5d8 100644
+--- a/drivers/vfio/pci/vfio_pci_core.c
++++ b/drivers/vfio/pci/vfio_pci_core.c
+@@ -727,15 +727,7 @@ EXPORT_SYMBOL_GPL(vfio_pci_core_finish_enable);
+ static int vfio_pci_get_irq_count(struct vfio_pci_core_device *vdev, int irq_type)
+ {
+ if (irq_type == VFIO_PCI_INTX_IRQ_INDEX) {
+- u8 pin;
+-
+- if (!IS_ENABLED(CONFIG_VFIO_PCI_INTX) ||
+- vdev->nointx || vdev->pdev->is_virtfn)
+- return 0;
+-
+- pci_read_config_byte(vdev->pdev, PCI_INTERRUPT_PIN, &pin);
+-
+- return pin ? 1 : 0;
++ return vdev->vconfig[PCI_INTERRUPT_PIN] ? 1 : 0;
+ } else if (irq_type == VFIO_PCI_MSI_IRQ_INDEX) {
+ u8 pos;
+ u16 flags;
+diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c
+index 8382c58343356..565966351dfad 100644
+--- a/drivers/vfio/pci/vfio_pci_intrs.c
++++ b/drivers/vfio/pci/vfio_pci_intrs.c
+@@ -259,7 +259,7 @@ static int vfio_intx_enable(struct vfio_pci_core_device *vdev,
+ if (!is_irq_none(vdev))
+ return -EINVAL;
+
+- if (!pdev->irq)
++ if (!pdev->irq || pdev->irq == IRQ_NOTCONNECTED)
+ return -ENODEV;
+
+ name = kasprintf(GFP_KERNEL_ACCOUNT, "vfio-intx(%s)", pci_name(pdev));
+--
+2.39.5
+
--- /dev/null
+From ed89a4834307c5fd985c90b6365a58d114530a50 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 2 Apr 2025 23:29:46 -0700
+Subject: vhost-scsi: protect vq->log_used with vq->mutex
+
+From: Dongli Zhang <dongli.zhang@oracle.com>
+
+[ Upstream commit f591cf9fce724e5075cc67488c43c6e39e8cbe27 ]
+
+The vhost-scsi completion path may access vq->log_base when vq->log_used is
+already set to false.
+
+ vhost-thread QEMU-thread
+
+vhost_scsi_complete_cmd_work()
+-> vhost_add_used()
+ -> vhost_add_used_n()
+ if (unlikely(vq->log_used))
+ QEMU disables vq->log_used
+ via VHOST_SET_VRING_ADDR.
+ mutex_lock(&vq->mutex);
+ vq->log_used = false now!
+ mutex_unlock(&vq->mutex);
+
+ QEMU gfree(vq->log_base)
+ log_used()
+ -> log_write(vq->log_base)
+
+Assuming the VMM is QEMU. The vq->log_base is from QEMU userpace and can be
+reclaimed via gfree(). As a result, this causes invalid memory writes to
+QEMU userspace.
+
+The control queue path has the same issue.
+
+Signed-off-by: Dongli Zhang <dongli.zhang@oracle.com>
+Acked-by: Jason Wang <jasowang@redhat.com>
+Reviewed-by: Mike Christie <michael.christie@oracle.com>
+Message-Id: <20250403063028.16045-2-dongli.zhang@oracle.com>
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/vhost/scsi.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c
+index 35a03306d1345..ecad2f53b7635 100644
+--- a/drivers/vhost/scsi.c
++++ b/drivers/vhost/scsi.c
+@@ -571,6 +571,9 @@ static void vhost_scsi_complete_cmd_work(struct vhost_work *work)
+ int ret;
+
+ llnode = llist_del_all(&svq->completion_list);
++
++ mutex_lock(&svq->vq.mutex);
++
+ llist_for_each_entry_safe(cmd, t, llnode, tvc_completion_list) {
+ se_cmd = &cmd->tvc_se_cmd;
+
+@@ -604,6 +607,8 @@ static void vhost_scsi_complete_cmd_work(struct vhost_work *work)
+ vhost_scsi_release_cmd_res(se_cmd);
+ }
+
++ mutex_unlock(&svq->vq.mutex);
++
+ if (signal)
+ vhost_signal(&svq->vs->dev, &svq->vq);
+ }
+@@ -1346,8 +1351,11 @@ static void vhost_scsi_tmf_resp_work(struct vhost_work *work)
+ else
+ resp_code = VIRTIO_SCSI_S_FUNCTION_REJECTED;
+
++ mutex_lock(&tmf->svq->vq.mutex);
+ vhost_scsi_send_tmf_resp(tmf->vhost, &tmf->svq->vq, tmf->in_iovs,
+ tmf->vq_desc, &tmf->resp_iov, resp_code);
++ mutex_unlock(&tmf->svq->vq.mutex);
++
+ vhost_scsi_release_tmf_res(tmf);
+ }
+
+--
+2.39.5
+
--- /dev/null
+From 5db376431d39798fc8157327eff23d899cc20b2c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Dec 2024 13:15:11 -0600
+Subject: vhost-scsi: Return queue full for page alloc failures during copy
+
+From: Mike Christie <michael.christie@oracle.com>
+
+[ Upstream commit 891b99eab0f89dbe08d216f4ab71acbeaf7a3102 ]
+
+This has us return queue full if we can't allocate a page during the
+copy operation so the initiator can retry.
+
+Signed-off-by: Mike Christie <michael.christie@oracle.com>
+Message-Id: <20241203191705.19431-5-michael.christie@oracle.com>
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/vhost/scsi.c | 15 +++++++++------
+ 1 file changed, 9 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c
+index ecad2f53b7635..38d243d914d00 100644
+--- a/drivers/vhost/scsi.c
++++ b/drivers/vhost/scsi.c
+@@ -762,7 +762,7 @@ vhost_scsi_copy_iov_to_sgl(struct vhost_scsi_cmd *cmd, struct iov_iter *iter,
+ size_t len = iov_iter_count(iter);
+ unsigned int nbytes = 0;
+ struct page *page;
+- int i;
++ int i, ret;
+
+ if (cmd->tvc_data_direction == DMA_FROM_DEVICE) {
+ cmd->saved_iter_addr = dup_iter(&cmd->saved_iter, iter,
+@@ -775,6 +775,7 @@ vhost_scsi_copy_iov_to_sgl(struct vhost_scsi_cmd *cmd, struct iov_iter *iter,
+ page = alloc_page(GFP_KERNEL);
+ if (!page) {
+ i--;
++ ret = -ENOMEM;
+ goto err;
+ }
+
+@@ -782,8 +783,10 @@ vhost_scsi_copy_iov_to_sgl(struct vhost_scsi_cmd *cmd, struct iov_iter *iter,
+ sg_set_page(&sg[i], page, nbytes, 0);
+
+ if (cmd->tvc_data_direction == DMA_TO_DEVICE &&
+- copy_page_from_iter(page, 0, nbytes, iter) != nbytes)
++ copy_page_from_iter(page, 0, nbytes, iter) != nbytes) {
++ ret = -EFAULT;
+ goto err;
++ }
+
+ len -= nbytes;
+ }
+@@ -798,7 +801,7 @@ vhost_scsi_copy_iov_to_sgl(struct vhost_scsi_cmd *cmd, struct iov_iter *iter,
+ for (; i >= 0; i--)
+ __free_page(sg_page(&sg[i]));
+ kfree(cmd->saved_iter_addr);
+- return -ENOMEM;
++ return ret;
+ }
+
+ static int
+@@ -1282,9 +1285,9 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
+ " %d\n", cmd, exp_data_len, prot_bytes, data_direction);
+
+ if (data_direction != DMA_NONE) {
+- if (unlikely(vhost_scsi_mapal(cmd, prot_bytes,
+- &prot_iter, exp_data_len,
+- &data_iter))) {
++ ret = vhost_scsi_mapal(cmd, prot_bytes, &prot_iter,
++ exp_data_len, &data_iter);
++ if (unlikely(ret)) {
+ vq_err(vq, "Failed to map iov to sgl\n");
+ vhost_scsi_release_cmd_res(&cmd->tvc_se_cmd);
+ goto err;
+--
+2.39.5
+
--- /dev/null
+From 44ffd8b64006a7eed800ec7c6ed6f85209a941df Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Mar 2025 13:44:35 +0100
+Subject: vhost_task: fix vhost_task_create() documentation
+
+From: Stefano Garzarella <sgarzare@redhat.com>
+
+[ Upstream commit fec0abf52609c20279243699d08b660c142ce0aa ]
+
+Commit cb380909ae3b ("vhost: return task creation error instead of NULL")
+changed the return value of vhost_task_create(), but did not update the
+documentation.
+
+Reflect the change in the documentation: on an error, vhost_task_create()
+returns an ERR_PTR() and no longer NULL.
+
+Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
+Message-Id: <20250327124435.142831-1-sgarzare@redhat.com>
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/vhost_task.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/kernel/vhost_task.c b/kernel/vhost_task.c
+index 2ef2e1b800916..2f844c279a3e0 100644
+--- a/kernel/vhost_task.c
++++ b/kernel/vhost_task.c
+@@ -111,7 +111,7 @@ EXPORT_SYMBOL_GPL(vhost_task_stop);
+ * @arg: data to be passed to fn and handled_kill
+ * @name: the thread's name
+ *
+- * This returns a specialized task for use by the vhost layer or NULL on
++ * This returns a specialized task for use by the vhost layer or ERR_PTR() on
+ * failure. The returned task is inactive, and the caller must fire it up
+ * through vhost_task_start().
+ */
+--
+2.39.5
+
--- /dev/null
+From 8efa7286e3e47d1da3d7b89c2198e5a413acdd52 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 10 Apr 2025 03:16:26 -0400
+Subject: virtgpu: don't reset on shutdown
+
+From: Michael S. Tsirkin <mst@redhat.com>
+
+[ Upstream commit 183a08715af1491d381b4e22efd61578fbe05fa5 ]
+
+It looks like GPUs are used after shutdown is invoked.
+Thus, breaking virtio gpu in the shutdown callback is not a good idea -
+guest hangs attempting to finish console drawing, with these warnings:
+
+[ 20.504464] WARNING: CPU: 0 PID: 568 at drivers/gpu/drm/virtio/virtgpu_vq.c:358 virtio_gpu_queue_ctrl_sgs+0x236/0x290 [virtio_gpu]
+[ 20.505685] Modules linked in: nft_fib_inet nft_fib_ipv4 nft_fib_ipv6 nft_fib nft_reject_inet nf_reject_ipv4 nf_reject_ipv6 nft_reject nft_ct nft_chain_nat nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 rfkill ip_set nf_tables nfnetlink vfat fat intel_rapl_msr intel_rapl_common intel_uncore_frequency_common nfit libnvdimm kvm_intel kvm rapl iTCO_wdt iTCO_vendor_support virtio_gpu virtio_dma_buf pcspkr drm_shmem_helper i2c_i801 drm_kms_helper lpc_ich i2c_smbus virtio_balloon joydev drm fuse xfs libcrc32c ahci libahci crct10dif_pclmul crc32_pclmul crc32c_intel libata virtio_net ghash_clmulni_intel net_failover virtio_blk failover serio_raw dm_mirror dm_region_hash dm_log dm_mod
+[ 20.511847] CPU: 0 PID: 568 Comm: kworker/0:3 Kdump: loaded Tainted: G W ------- --- 5.14.0-578.6675_1757216455.el9.x86_64 #1
+[ 20.513157] Hardware name: Red Hat KVM/RHEL, BIOS edk2-20241117-3.el9 11/17/2024
+[ 20.513918] Workqueue: events drm_fb_helper_damage_work [drm_kms_helper]
+[ 20.514626] RIP: 0010:virtio_gpu_queue_ctrl_sgs+0x236/0x290 [virtio_gpu]
+[ 20.515332] Code: 00 00 48 85 c0 74 0c 48 8b 78 08 48 89 ee e8 51 50 00 00 65 ff 0d 42 e3 74 3f 0f 85 69 ff ff ff 0f 1f 44 00 00 e9 5f ff ff ff <0f> 0b e9 3f ff ff ff 48 83 3c 24 00 74 0e 49 8b 7f 40 48 85 ff 74
+[ 20.517272] RSP: 0018:ff34f0a8c0787ad8 EFLAGS: 00010282
+[ 20.517820] RAX: 00000000fffffffb RBX: 0000000000000000 RCX: 0000000000000820
+[ 20.518565] RDX: 0000000000000000 RSI: ff34f0a8c0787be0 RDI: ff218bef03a26300
+[ 20.519308] RBP: ff218bef03a26300 R08: 0000000000000001 R09: ff218bef07224360
+[ 20.520059] R10: 0000000000008dc0 R11: 0000000000000002 R12: ff218bef02630028
+[ 20.520806] R13: ff218bef0263fb48 R14: ff218bef00cb8000 R15: ff218bef07224360
+[ 20.521555] FS: 0000000000000000(0000) GS:ff218bef7ba00000(0000) knlGS:0000000000000000
+[ 20.522397] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[ 20.522996] CR2: 000055ac4f7871c0 CR3: 000000010b9f2002 CR4: 0000000000771ef0
+[ 20.523740] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
+[ 20.524477] DR3: 0000000000000000 DR6: 00000000fffe07f0 DR7: 0000000000000400
+[ 20.525223] PKRU: 55555554
+[ 20.525515] Call Trace:
+[ 20.525777] <TASK>
+[ 20.526003] ? show_trace_log_lvl+0x1c4/0x2df
+[ 20.526464] ? show_trace_log_lvl+0x1c4/0x2df
+[ 20.526925] ? virtio_gpu_queue_fenced_ctrl_buffer+0x82/0x2c0 [virtio_gpu]
+[ 20.527643] ? virtio_gpu_queue_ctrl_sgs+0x236/0x290 [virtio_gpu]
+[ 20.528282] ? __warn+0x7e/0xd0
+[ 20.528621] ? virtio_gpu_queue_ctrl_sgs+0x236/0x290 [virtio_gpu]
+[ 20.529256] ? report_bug+0x100/0x140
+[ 20.529643] ? handle_bug+0x3c/0x70
+[ 20.530010] ? exc_invalid_op+0x14/0x70
+[ 20.530421] ? asm_exc_invalid_op+0x16/0x20
+[ 20.530862] ? virtio_gpu_queue_ctrl_sgs+0x236/0x290 [virtio_gpu]
+[ 20.531506] ? virtio_gpu_queue_ctrl_sgs+0x174/0x290 [virtio_gpu]
+[ 20.532148] virtio_gpu_queue_fenced_ctrl_buffer+0x82/0x2c0 [virtio_gpu]
+[ 20.532843] virtio_gpu_primary_plane_update+0x3e2/0x460 [virtio_gpu]
+[ 20.533520] drm_atomic_helper_commit_planes+0x108/0x320 [drm_kms_helper]
+[ 20.534233] drm_atomic_helper_commit_tail+0x45/0x80 [drm_kms_helper]
+[ 20.534914] commit_tail+0xd2/0x130 [drm_kms_helper]
+[ 20.535446] drm_atomic_helper_commit+0x11b/0x140 [drm_kms_helper]
+[ 20.536097] drm_atomic_commit+0xa4/0xe0 [drm]
+[ 20.536588] ? __pfx___drm_printfn_info+0x10/0x10 [drm]
+[ 20.537162] drm_atomic_helper_dirtyfb+0x192/0x270 [drm_kms_helper]
+[ 20.537823] drm_fbdev_shmem_helper_fb_dirty+0x43/0xa0 [drm_shmem_helper]
+[ 20.538536] drm_fb_helper_damage_work+0x87/0x160 [drm_kms_helper]
+[ 20.539188] process_one_work+0x194/0x380
+[ 20.539612] worker_thread+0x2fe/0x410
+[ 20.540007] ? __pfx_worker_thread+0x10/0x10
+[ 20.540456] kthread+0xdd/0x100
+[ 20.540791] ? __pfx_kthread+0x10/0x10
+[ 20.541190] ret_from_fork+0x29/0x50
+[ 20.541566] </TASK>
+[ 20.541802] ---[ end trace 0000000000000000 ]---
+
+It looks like the shutdown is called in the middle of console drawing, so
+we should either wait for it to finish, or let drm handle the shutdown.
+
+This patch implements this second option:
+
+Add an option for drivers to bypass the common break+reset handling.
+As DRM is careful to flush/synchronize outstanding buffers, it looks like
+GPU can just have a NOP there.
+
+Reviewed-by: Eric Auger <eric.auger@redhat.com>
+Tested-by: Eric Auger <eric.auger@redhat.com>
+Fixes: 8bd2fa086a04 ("virtio: break and reset virtio devices on device_shutdown()")
+Cc: Eric Auger <eauger@redhat.com>
+Cc: Jocelyn Falempe <jfalempe@redhat.com>
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Message-Id: <8490dbeb6f79ed039e6c11d121002618972538a3.1744293540.git.mst@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/virtio/virtgpu_drv.c | 9 +++++++++
+ drivers/virtio/virtio.c | 6 ++++++
+ include/linux/virtio.h | 3 +++
+ 3 files changed, 18 insertions(+)
+
+diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c b/drivers/gpu/drm/virtio/virtgpu_drv.c
+index 6a67c6297d583..8719b778a1ff0 100644
+--- a/drivers/gpu/drm/virtio/virtgpu_drv.c
++++ b/drivers/gpu/drm/virtio/virtgpu_drv.c
+@@ -125,6 +125,14 @@ static void virtio_gpu_remove(struct virtio_device *vdev)
+ drm_dev_put(dev);
+ }
+
++static void virtio_gpu_shutdown(struct virtio_device *vdev)
++{
++ /*
++ * drm does its own synchronization on shutdown.
++ * Do nothing here, opt out of device reset.
++ */
++}
++
+ static void virtio_gpu_config_changed(struct virtio_device *vdev)
+ {
+ struct drm_device *dev = vdev->priv;
+@@ -159,6 +167,7 @@ static struct virtio_driver virtio_gpu_driver = {
+ .id_table = id_table,
+ .probe = virtio_gpu_probe,
+ .remove = virtio_gpu_remove,
++ .shutdown = virtio_gpu_shutdown,
+ .config_changed = virtio_gpu_config_changed
+ };
+
+diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c
+index 150753c3b5782..95d5d7993e5b1 100644
+--- a/drivers/virtio/virtio.c
++++ b/drivers/virtio/virtio.c
+@@ -407,6 +407,12 @@ static void virtio_dev_shutdown(struct device *_d)
+ if (!drv)
+ return;
+
++ /* If the driver has its own shutdown method, use that. */
++ if (drv->shutdown) {
++ drv->shutdown(dev);
++ return;
++ }
++
+ /*
+ * Some devices get wedged if you kick them after they are
+ * reset. Mark all vqs as broken to make sure we don't.
+diff --git a/include/linux/virtio.h b/include/linux/virtio.h
+index 4d16c13d0df58..64cb4b04be7ad 100644
+--- a/include/linux/virtio.h
++++ b/include/linux/virtio.h
+@@ -220,6 +220,8 @@ size_t virtio_max_dma_size(const struct virtio_device *vdev);
+ * occurs.
+ * @reset_done: optional function to call after transport specific reset
+ * operation has finished.
++ * @shutdown: synchronize with the device on shutdown. If provided, replaces
++ * the virtio core implementation.
+ */
+ struct virtio_driver {
+ struct device_driver driver;
+@@ -237,6 +239,7 @@ struct virtio_driver {
+ int (*restore)(struct virtio_device *dev);
+ int (*reset_prepare)(struct virtio_device *dev);
+ int (*reset_done)(struct virtio_device *dev);
++ void (*shutdown)(struct virtio_device *dev);
+ };
+
+ #define drv_to_virtio(__drv) container_of_const(__drv, struct virtio_driver, driver)
+--
+2.39.5
+
--- /dev/null
+From 092b389e506f3fdf21f656026301480396135817 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 8 Aug 2024 10:51:41 +0300
+Subject: virtio: break and reset virtio devices on device_shutdown()
+
+From: Michael S. Tsirkin <mst@redhat.com>
+
+[ Upstream commit 8bd2fa086a04886798b505f28db4002525895203 ]
+
+Hongyu reported a hang on kexec in a VM. QEMU reported invalid memory
+accesses during the hang.
+
+ Invalid read at addr 0x102877002, size 2, region '(null)', reason: rejected
+ Invalid write at addr 0x102877A44, size 2, region '(null)', reason: rejected
+ ...
+
+It was traced down to virtio-console. Kexec works fine if virtio-console
+is not in use.
+
+The issue is that virtio-console continues to write to the MMIO even after
+underlying virtio-pci device is reset.
+
+Additionally, Eric noticed that IOMMUs are reset before devices, if
+devices are not reset on shutdown they continue to poke at guest memory
+and get errors from the IOMMU. Some devices get wedged then.
+
+The problem can be solved by breaking all virtio devices on virtio
+bus shutdown, then resetting them.
+
+Reported-by: Eric Auger <eauger@redhat.com>
+Reported-by: Hongyu Ning <hongyu.ning@linux.intel.com>
+Message-ID: <c1dbc7dbad9b445245d3348f19e6742b0be07347.1740094946.git.mst@redhat.com>
+Tested-by: Eric Auger <eric.auger@redhat.com>
+Acked-by: Jason Wang <jasowang@redhat.com>
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/virtio/virtio.c | 29 +++++++++++++++++++++++++++++
+ 1 file changed, 29 insertions(+)
+
+diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c
+index ba37665188b51..150753c3b5782 100644
+--- a/drivers/virtio/virtio.c
++++ b/drivers/virtio/virtio.c
+@@ -395,6 +395,34 @@ static const struct cpumask *virtio_irq_get_affinity(struct device *_d,
+ return dev->config->get_vq_affinity(dev, irq_vec);
+ }
+
++static void virtio_dev_shutdown(struct device *_d)
++{
++ struct virtio_device *dev = dev_to_virtio(_d);
++ struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
++
++ /*
++ * Stop accesses to or from the device.
++ * We only need to do it if there's a driver - no accesses otherwise.
++ */
++ if (!drv)
++ return;
++
++ /*
++ * Some devices get wedged if you kick them after they are
++ * reset. Mark all vqs as broken to make sure we don't.
++ */
++ virtio_break_device(dev);
++ /*
++ * Guarantee that any callback will see vq->broken as true.
++ */
++ virtio_synchronize_cbs(dev);
++ /*
++ * As IOMMUs are reset on shutdown, this will block device access to memory.
++ * Some devices get wedged if this happens, so reset to make sure it does not.
++ */
++ dev->config->reset(dev);
++}
++
+ static const struct bus_type virtio_bus = {
+ .name = "virtio",
+ .match = virtio_dev_match,
+@@ -403,6 +431,7 @@ static const struct bus_type virtio_bus = {
+ .probe = virtio_dev_probe,
+ .remove = virtio_dev_remove,
+ .irq_get_affinity = virtio_irq_get_affinity,
++ .shutdown = virtio_dev_shutdown,
+ };
+
+ int __register_virtio_driver(struct virtio_driver *driver, struct module *owner)
+--
+2.39.5
+
--- /dev/null
+From ccb1a74ef5907ff47bbadba64c560dc6d1e6eff5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 12 Mar 2025 21:04:12 +0800
+Subject: virtio_ring: Fix data race by tagging event_triggered as racy for
+ KCSAN
+
+From: Zhongqiu Han <quic_zhonhan@quicinc.com>
+
+[ Upstream commit 2e2f925fe737576df2373931c95e1a2b66efdfef ]
+
+syzbot reports a data-race when accessing the event_triggered, here is the
+simplified stack when the issue occurred:
+
+==================================================================
+BUG: KCSAN: data-race in virtqueue_disable_cb / virtqueue_enable_cb_delayed
+
+write to 0xffff8881025bc452 of 1 bytes by task 3288 on cpu 0:
+ virtqueue_enable_cb_delayed+0x42/0x3c0 drivers/virtio/virtio_ring.c:2653
+ start_xmit+0x230/0x1310 drivers/net/virtio_net.c:3264
+ __netdev_start_xmit include/linux/netdevice.h:5151 [inline]
+ netdev_start_xmit include/linux/netdevice.h:5160 [inline]
+ xmit_one net/core/dev.c:3800 [inline]
+
+read to 0xffff8881025bc452 of 1 bytes by interrupt on cpu 1:
+ virtqueue_disable_cb_split drivers/virtio/virtio_ring.c:880 [inline]
+ virtqueue_disable_cb+0x92/0x180 drivers/virtio/virtio_ring.c:2566
+ skb_xmit_done+0x5f/0x140 drivers/net/virtio_net.c:777
+ vring_interrupt+0x161/0x190 drivers/virtio/virtio_ring.c:2715
+ __handle_irq_event_percpu+0x95/0x490 kernel/irq/handle.c:158
+ handle_irq_event_percpu kernel/irq/handle.c:193 [inline]
+
+value changed: 0x01 -> 0x00
+==================================================================
+
+When the data race occurs, the function virtqueue_enable_cb_delayed() sets
+event_triggered to false, and virtqueue_disable_cb_split/packed() reads it
+as false due to the race condition. Since event_triggered is an unreliable
+hint used for optimization, this should only cause the driver temporarily
+suggest that the device not send an interrupt notification when the event
+index is used.
+
+Fix this KCSAN reported data-race issue by explicitly tagging the access as
+data_racy.
+
+Reported-by: syzbot+efe683d57990864b8c8e@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/all/67c7761a.050a0220.15b4b9.0018.GAE@google.com/
+Signed-off-by: Zhongqiu Han <quic_zhonhan@quicinc.com>
+Message-Id: <20250312130412.3516307-1-quic_zhonhan@quicinc.com>
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Acked-by: Jason Wang <jasowang@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/virtio/virtio_ring.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
+index fdd2d2b07b5a2..b784aab668670 100644
+--- a/drivers/virtio/virtio_ring.c
++++ b/drivers/virtio/virtio_ring.c
+@@ -2650,7 +2650,7 @@ bool virtqueue_enable_cb_delayed(struct virtqueue *_vq)
+ struct vring_virtqueue *vq = to_vvq(_vq);
+
+ if (vq->event_triggered)
+- vq->event_triggered = false;
++ data_race(vq->event_triggered = false);
+
+ return vq->packed_ring ? virtqueue_enable_cb_delayed_packed(_vq) :
+ virtqueue_enable_cb_delayed_split(_vq);
+--
+2.39.5
+
--- /dev/null
+From 458ad6523828350ce83cd8c7f0662dceb4c926bc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Feb 2025 16:55:42 +0200
+Subject: vxlan: Annotate FDB data races
+
+From: Ido Schimmel <idosch@nvidia.com>
+
+[ Upstream commit f6205f8215f12a96518ac9469ff76294ae7bd612 ]
+
+The 'used' and 'updated' fields in the FDB entry structure can be
+accessed concurrently by multiple threads, leading to reports such as
+[1]. Can be reproduced using [2].
+
+Suppress these reports by annotating these accesses using
+READ_ONCE() / WRITE_ONCE().
+
+[1]
+BUG: KCSAN: data-race in vxlan_xmit / vxlan_xmit
+
+write to 0xffff942604d263a8 of 8 bytes by task 286 on cpu 0:
+ vxlan_xmit+0xb29/0x2380
+ dev_hard_start_xmit+0x84/0x2f0
+ __dev_queue_xmit+0x45a/0x1650
+ packet_xmit+0x100/0x150
+ packet_sendmsg+0x2114/0x2ac0
+ __sys_sendto+0x318/0x330
+ __x64_sys_sendto+0x76/0x90
+ x64_sys_call+0x14e8/0x1c00
+ do_syscall_64+0x9e/0x1a0
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+
+read to 0xffff942604d263a8 of 8 bytes by task 287 on cpu 2:
+ vxlan_xmit+0xadf/0x2380
+ dev_hard_start_xmit+0x84/0x2f0
+ __dev_queue_xmit+0x45a/0x1650
+ packet_xmit+0x100/0x150
+ packet_sendmsg+0x2114/0x2ac0
+ __sys_sendto+0x318/0x330
+ __x64_sys_sendto+0x76/0x90
+ x64_sys_call+0x14e8/0x1c00
+ do_syscall_64+0x9e/0x1a0
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+
+value changed: 0x00000000fffbac6e -> 0x00000000fffbac6f
+
+Reported by Kernel Concurrency Sanitizer on:
+CPU: 2 UID: 0 PID: 287 Comm: mausezahn Not tainted 6.13.0-rc7-01544-gb4b270f11a02 #5
+Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.3-3.fc41 04/01/2014
+
+[2]
+ #!/bin/bash
+
+ set +H
+ echo whitelist > /sys/kernel/debug/kcsan
+ echo !vxlan_xmit > /sys/kernel/debug/kcsan
+
+ ip link add name vx0 up type vxlan id 10010 dstport 4789 local 192.0.2.1
+ bridge fdb add 00:11:22:33:44:55 dev vx0 self static dst 198.51.100.1
+ taskset -c 0 mausezahn vx0 -a own -b 00:11:22:33:44:55 -c 0 -q &
+ taskset -c 2 mausezahn vx0 -a own -b 00:11:22:33:44:55 -c 0 -q &
+
+Reviewed-by: Petr Machata <petrm@nvidia.com>
+Signed-off-by: Ido Schimmel <idosch@nvidia.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org>
+Link: https://patch.msgid.link/20250204145549.1216254-2-idosch@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/vxlan/vxlan_core.c | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
+index ae0e2edfde1aa..cdd2a78badf55 100644
+--- a/drivers/net/vxlan/vxlan_core.c
++++ b/drivers/net/vxlan/vxlan_core.c
+@@ -227,9 +227,9 @@ static int vxlan_fdb_info(struct sk_buff *skb, struct vxlan_dev *vxlan,
+ be32_to_cpu(fdb->vni)))
+ goto nla_put_failure;
+
+- ci.ndm_used = jiffies_to_clock_t(now - fdb->used);
++ ci.ndm_used = jiffies_to_clock_t(now - READ_ONCE(fdb->used));
+ ci.ndm_confirmed = 0;
+- ci.ndm_updated = jiffies_to_clock_t(now - fdb->updated);
++ ci.ndm_updated = jiffies_to_clock_t(now - READ_ONCE(fdb->updated));
+ ci.ndm_refcnt = 0;
+
+ if (nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci))
+@@ -434,8 +434,8 @@ static struct vxlan_fdb *vxlan_find_mac(struct vxlan_dev *vxlan,
+ struct vxlan_fdb *f;
+
+ f = __vxlan_find_mac(vxlan, mac, vni);
+- if (f && f->used != jiffies)
+- f->used = jiffies;
++ if (f && READ_ONCE(f->used) != jiffies)
++ WRITE_ONCE(f->used, jiffies);
+
+ return f;
+ }
+@@ -1009,12 +1009,12 @@ static int vxlan_fdb_update_existing(struct vxlan_dev *vxlan,
+ !(f->flags & NTF_VXLAN_ADDED_BY_USER)) {
+ if (f->state != state) {
+ f->state = state;
+- f->updated = jiffies;
++ WRITE_ONCE(f->updated, jiffies);
+ notify = 1;
+ }
+ if (f->flags != fdb_flags) {
+ f->flags = fdb_flags;
+- f->updated = jiffies;
++ WRITE_ONCE(f->updated, jiffies);
+ notify = 1;
+ }
+ }
+@@ -1048,7 +1048,7 @@ static int vxlan_fdb_update_existing(struct vxlan_dev *vxlan,
+ }
+
+ if (ndm_flags & NTF_USE)
+- f->used = jiffies;
++ WRITE_ONCE(f->used, jiffies);
+
+ if (notify) {
+ if (rd == NULL)
+@@ -1481,7 +1481,7 @@ static enum skb_drop_reason vxlan_snoop(struct net_device *dev,
+ src_mac, &rdst->remote_ip.sa, &src_ip->sa);
+
+ rdst->remote_ip = *src_ip;
+- f->updated = jiffies;
++ WRITE_ONCE(f->updated, jiffies);
+ vxlan_fdb_notify(vxlan, f, rdst, RTM_NEWNEIGH, true, NULL);
+ } else {
+ u32 hash_index = fdb_head_index(vxlan, src_mac, vni);
+@@ -2852,7 +2852,7 @@ static void vxlan_cleanup(struct timer_list *t)
+ if (f->flags & NTF_EXT_LEARNED)
+ continue;
+
+- timeout = f->used + vxlan->cfg.age_interval * HZ;
++ timeout = READ_ONCE(f->used) + vxlan->cfg.age_interval * HZ;
+ if (time_before_eq(timeout, jiffies)) {
+ netdev_dbg(vxlan->dev,
+ "garbage collect %pM\n",
+--
+2.39.5
+
--- /dev/null
+From 3e036b1af282b3b0e0142912bf0b3dde7aa7e16e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 14 Feb 2025 17:18:21 +0100
+Subject: vxlan: Join / leave MC group after remote changes
+
+From: Petr Machata <petrm@nvidia.com>
+
+[ Upstream commit d42d543368343c0449a4e433b5f02e063a86209c ]
+
+When a vxlan netdevice is brought up, if its default remote is a multicast
+address, the device joins the indicated group.
+
+Therefore when the multicast remote address changes, the device should
+leave the current group and subscribe to the new one. Similarly when the
+interface used for endpoint communication is changed in a situation when
+multicast remote is configured. This is currently not done.
+
+Both vxlan_igmp_join() and vxlan_igmp_leave() can however fail. So it is
+possible that with such fix, the netdevice will end up in an inconsistent
+situation where the old group is not joined anymore, but joining the new
+group fails. Should we join the new group first, and leave the old one
+second, we might end up in the opposite situation, where both groups are
+joined. Undoing any of this during rollback is going to be similarly
+problematic.
+
+One solution would be to just forbid the change when the netdevice is up.
+However in vnifilter mode, changing the group address is allowed, and these
+problems are simply ignored (see vxlan_vni_update_group()):
+
+ # ip link add name br up type bridge vlan_filtering 1
+ # ip link add vx1 up master br type vxlan external vnifilter local 192.0.2.1 dev lo dstport 4789
+ # bridge vni add dev vx1 vni 200 group 224.0.0.1
+ # tcpdump -i lo &
+ # bridge vni add dev vx1 vni 200 group 224.0.0.2
+ 18:55:46.523438 IP 0.0.0.0 > 224.0.0.22: igmp v3 report, 1 group record(s)
+ 18:55:46.943447 IP 0.0.0.0 > 224.0.0.22: igmp v3 report, 1 group record(s)
+ # bridge vni
+ dev vni group/remote
+ vx1 200 224.0.0.2
+
+Having two different modes of operation for conceptually the same interface
+is silly, so in this patch, just do what the vnifilter code does and deal
+with the errors by crossing fingers real hard.
+
+The vnifilter code leaves old before joining new, and in case of join /
+leave failures does not roll back the configuration changes that have
+already been applied, but bails out of joining if it could not leave. Do
+the same here: leave before join, apply changes unconditionally and do not
+attempt to join if we couldn't leave.
+
+Signed-off-by: Petr Machata <petrm@nvidia.com>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/vxlan/vxlan_core.c | 18 ++++++++++++++++--
+ 1 file changed, 16 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
+index 92516189e792f..ae0e2edfde1aa 100644
+--- a/drivers/net/vxlan/vxlan_core.c
++++ b/drivers/net/vxlan/vxlan_core.c
+@@ -4415,6 +4415,7 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[],
+ struct netlink_ext_ack *extack)
+ {
+ struct vxlan_dev *vxlan = netdev_priv(dev);
++ bool rem_ip_changed, change_igmp;
+ struct net_device *lowerdev;
+ struct vxlan_config conf;
+ struct vxlan_rdst *dst;
+@@ -4438,8 +4439,13 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[],
+ if (err)
+ return err;
+
++ rem_ip_changed = !vxlan_addr_equal(&conf.remote_ip, &dst->remote_ip);
++ change_igmp = vxlan->dev->flags & IFF_UP &&
++ (rem_ip_changed ||
++ dst->remote_ifindex != conf.remote_ifindex);
++
+ /* handle default dst entry */
+- if (!vxlan_addr_equal(&conf.remote_ip, &dst->remote_ip)) {
++ if (rem_ip_changed) {
+ u32 hash_index = fdb_head_index(vxlan, all_zeros_mac, conf.vni);
+
+ spin_lock_bh(&vxlan->hash_lock[hash_index]);
+@@ -4483,6 +4489,9 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[],
+ }
+ }
+
++ if (change_igmp && vxlan_addr_multicast(&dst->remote_ip))
++ err = vxlan_multicast_leave(vxlan);
++
+ if (conf.age_interval != vxlan->cfg.age_interval)
+ mod_timer(&vxlan->age_timer, jiffies);
+
+@@ -4490,7 +4499,12 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[],
+ if (lowerdev && lowerdev != dst->remote_dev)
+ dst->remote_dev = lowerdev;
+ vxlan_config_apply(dev, &conf, lowerdev, vxlan->net, true);
+- return 0;
++
++ if (!err && change_igmp &&
++ vxlan_addr_multicast(&dst->remote_ip))
++ err = vxlan_multicast_join(vxlan);
++
++ return err;
+ }
+
+ static void vxlan_dellink(struct net_device *dev, struct list_head *head)
+--
+2.39.5
+
--- /dev/null
+From 6bd60675b9e44a821db0fac6d88070247d8d750d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 14 Mar 2025 17:02:44 +0100
+Subject: watchdog: aspeed: fix 64-bit division
+
+From: Arnd Bergmann <arnd@arndb.de>
+
+[ Upstream commit 48a136639ec233614a61653e19f559977d5da2b5 ]
+
+On 32-bit architectures, the new calculation causes a build failure:
+
+ld.lld-21: error: undefined symbol: __aeabi_uldivmod
+
+Since neither value is ever larger than a register, cast both
+sides into a uintptr_t.
+
+Fixes: 5c03f9f4d362 ("watchdog: aspeed: Update bootstatus handling")
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Reviewed-by: Guenter Roeck <linux@roeck-us.net>
+Link: https://lore.kernel.org/r/20250314160248.502324-1-arnd@kernel.org
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Wim Van Sebroeck <wim@linux-watchdog.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/watchdog/aspeed_wdt.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/watchdog/aspeed_wdt.c b/drivers/watchdog/aspeed_wdt.c
+index 369635b38ca0e..837e15701c0e2 100644
+--- a/drivers/watchdog/aspeed_wdt.c
++++ b/drivers/watchdog/aspeed_wdt.c
+@@ -254,7 +254,7 @@ static void aspeed_wdt_update_bootstatus(struct platform_device *pdev,
+
+ if (!of_device_is_compatible(pdev->dev.of_node, "aspeed,ast2400-wdt")) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+- idx = ((intptr_t)wdt->base & 0x00000fff) / resource_size(res);
++ idx = ((intptr_t)wdt->base & 0x00000fff) / (uintptr_t)resource_size(res);
+ }
+
+ scu_base = syscon_regmap_lookup_by_compatible(scu.compatible);
+--
+2.39.5
+
--- /dev/null
+From c3803ca0190f3d22bb546577f7fd9022404f6689 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Jan 2025 17:37:37 +0800
+Subject: watchdog: aspeed: Update bootstatus handling
+
+From: Chin-Ting Kuo <chin-ting_kuo@aspeedtech.com>
+
+[ Upstream commit 5c03f9f4d36292150c14ebd90788c4d3273ed9dc ]
+
+The boot status in the watchdog device struct is updated during
+controller probe stage. Application layer can get the boot status
+through the command, cat /sys/class/watchdog/watchdogX/bootstatus.
+The bootstatus can be,
+WDIOF_CARDRESET => System is reset due to WDT timeout occurs.
+Others => Other reset events, e.g., power on reset.
+
+On ASPEED platforms, boot status is recorded in the SCU registers.
+- AST2400: Only a bit is used to represent system reset triggered by
+ any WDT controller.
+- AST2500/AST2600: System reset triggered by different WDT controllers
+ can be distinguished by different SCU bits.
+
+Besides, on AST2400 and AST2500, since alternating boot event is
+also triggered by using WDT timeout mechanism, it is classified
+as WDIOF_CARDRESET.
+
+Signed-off-by: Chin-Ting Kuo <chin-ting_kuo@aspeedtech.com>
+Reviewed-by: Andrew Jeffery <andrew@codeconstruct.com.au>
+Reviewed-by: Guenter Roeck <linux@roeck-us.net>
+Link: https://lore.kernel.org/r/20250113093737.845097-2-chin-ting_kuo@aspeedtech.com
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Wim Van Sebroeck <wim@linux-watchdog.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/watchdog/aspeed_wdt.c | 81 ++++++++++++++++++++++++++++++++++-
+ 1 file changed, 79 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/watchdog/aspeed_wdt.c b/drivers/watchdog/aspeed_wdt.c
+index b4773a6aaf8cc..369635b38ca0e 100644
+--- a/drivers/watchdog/aspeed_wdt.c
++++ b/drivers/watchdog/aspeed_wdt.c
+@@ -11,21 +11,30 @@
+ #include <linux/io.h>
+ #include <linux/kernel.h>
+ #include <linux/kstrtox.h>
++#include <linux/mfd/syscon.h>
+ #include <linux/module.h>
+ #include <linux/of.h>
+ #include <linux/of_irq.h>
+ #include <linux/platform_device.h>
++#include <linux/regmap.h>
+ #include <linux/watchdog.h>
+
+ static bool nowayout = WATCHDOG_NOWAYOUT;
+ module_param(nowayout, bool, 0);
+ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
++struct aspeed_wdt_scu {
++ const char *compatible;
++ u32 reset_status_reg;
++ u32 wdt_reset_mask;
++ u32 wdt_reset_mask_shift;
++};
+
+ struct aspeed_wdt_config {
+ u32 ext_pulse_width_mask;
+ u32 irq_shift;
+ u32 irq_mask;
++ struct aspeed_wdt_scu scu;
+ };
+
+ struct aspeed_wdt {
+@@ -39,18 +48,36 @@ static const struct aspeed_wdt_config ast2400_config = {
+ .ext_pulse_width_mask = 0xff,
+ .irq_shift = 0,
+ .irq_mask = 0,
++ .scu = {
++ .compatible = "aspeed,ast2400-scu",
++ .reset_status_reg = 0x3c,
++ .wdt_reset_mask = 0x1,
++ .wdt_reset_mask_shift = 1,
++ },
+ };
+
+ static const struct aspeed_wdt_config ast2500_config = {
+ .ext_pulse_width_mask = 0xfffff,
+ .irq_shift = 12,
+ .irq_mask = GENMASK(31, 12),
++ .scu = {
++ .compatible = "aspeed,ast2500-scu",
++ .reset_status_reg = 0x3c,
++ .wdt_reset_mask = 0x1,
++ .wdt_reset_mask_shift = 2,
++ },
+ };
+
+ static const struct aspeed_wdt_config ast2600_config = {
+ .ext_pulse_width_mask = 0xfffff,
+ .irq_shift = 0,
+ .irq_mask = GENMASK(31, 10),
++ .scu = {
++ .compatible = "aspeed,ast2600-scu",
++ .reset_status_reg = 0x74,
++ .wdt_reset_mask = 0xf,
++ .wdt_reset_mask_shift = 16,
++ },
+ };
+
+ static const struct of_device_id aspeed_wdt_of_table[] = {
+@@ -213,6 +240,56 @@ static int aspeed_wdt_restart(struct watchdog_device *wdd,
+ return 0;
+ }
+
++static void aspeed_wdt_update_bootstatus(struct platform_device *pdev,
++ struct aspeed_wdt *wdt)
++{
++ const struct resource *res;
++ struct aspeed_wdt_scu scu = wdt->cfg->scu;
++ struct regmap *scu_base;
++ u32 reset_mask_width;
++ u32 reset_mask_shift;
++ u32 idx = 0;
++ u32 status;
++ int ret;
++
++ if (!of_device_is_compatible(pdev->dev.of_node, "aspeed,ast2400-wdt")) {
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ idx = ((intptr_t)wdt->base & 0x00000fff) / resource_size(res);
++ }
++
++ scu_base = syscon_regmap_lookup_by_compatible(scu.compatible);
++ if (IS_ERR(scu_base)) {
++ wdt->wdd.bootstatus = WDIOS_UNKNOWN;
++ return;
++ }
++
++ ret = regmap_read(scu_base, scu.reset_status_reg, &status);
++ if (ret) {
++ wdt->wdd.bootstatus = WDIOS_UNKNOWN;
++ return;
++ }
++
++ reset_mask_width = hweight32(scu.wdt_reset_mask);
++ reset_mask_shift = scu.wdt_reset_mask_shift +
++ reset_mask_width * idx;
++
++ if (status & (scu.wdt_reset_mask << reset_mask_shift))
++ wdt->wdd.bootstatus = WDIOF_CARDRESET;
++
++ /* clear wdt reset event flag */
++ if (of_device_is_compatible(pdev->dev.of_node, "aspeed,ast2400-wdt") ||
++ of_device_is_compatible(pdev->dev.of_node, "aspeed,ast2500-wdt")) {
++ ret = regmap_read(scu_base, scu.reset_status_reg, &status);
++ if (!ret) {
++ status &= ~(scu.wdt_reset_mask << reset_mask_shift);
++ regmap_write(scu_base, scu.reset_status_reg, status);
++ }
++ } else {
++ regmap_write(scu_base, scu.reset_status_reg,
++ scu.wdt_reset_mask << reset_mask_shift);
++ }
++}
++
+ /* access_cs0 shows if cs0 is accessible, hence the reverted bit */
+ static ssize_t access_cs0_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+@@ -458,10 +535,10 @@ static int aspeed_wdt_probe(struct platform_device *pdev)
+ writel(duration - 1, wdt->base + WDT_RESET_WIDTH);
+ }
+
++ aspeed_wdt_update_bootstatus(pdev, wdt);
++
+ status = readl(wdt->base + WDT_TIMEOUT_STATUS);
+ if (status & WDT_TIMEOUT_STATUS_BOOT_SECONDARY) {
+- wdt->wdd.bootstatus = WDIOF_CARDRESET;
+-
+ if (of_device_is_compatible(np, "aspeed,ast2400-wdt") ||
+ of_device_is_compatible(np, "aspeed,ast2500-wdt"))
+ wdt->wdd.groups = bswitch_groups;
+--
+2.39.5
+
--- /dev/null
+From a49cc6c5e7eb71e02fcf9b7c62b25b5a705542ba Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 13 Feb 2025 09:41:04 +0900
+Subject: watchdog: s3c2410_wdt: Fix PMU register bits for ExynosAutoV920 SoC
+
+From: Kyunghwan Seo <khwan.seo@samsung.com>
+
+[ Upstream commit 480ee8a260e6f87cbcdaff77ac2cbf6dc03f0f4f ]
+
+Fix the PMU register bits for the ExynosAutoV920 SoC.
+This SoC has different bit information compared to its previous
+version, ExynosAutoV9, and we have made the necessary adjustments.
+
+rst_stat_bit:
+ - ExynosAutoV920 cl0 : 0
+ - ExynosAutoV920 cl1 : 1
+
+cnt_en_bit:
+ - ExynosAutoV920 cl0 : 8
+ - ExynosAutoV920 cl1 : 8
+
+Signed-off-by: Kyunghwan Seo <khwan.seo@samsung.com>
+Signed-off-by: Sangwook Shin <sw617.shin@samsung.com>
+Reviewed-by: Alim Akhtar <alim.akhtar@samsung.com>
+Reviewed-by: Guenter Roeck <linux@roeck-us.net>
+Link: https://lore.kernel.org/r/20250213004104.3881711-1-sw617.shin@samsung.com
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Wim Van Sebroeck <wim@linux-watchdog.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/watchdog/s3c2410_wdt.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c
+index 30450e99e5e9d..bdd81d8074b24 100644
+--- a/drivers/watchdog/s3c2410_wdt.c
++++ b/drivers/watchdog/s3c2410_wdt.c
+@@ -72,6 +72,8 @@
+ #define EXYNOS850_CLUSTER1_WDTRESET_BIT 23
+ #define EXYNOSAUTOV9_CLUSTER0_WDTRESET_BIT 25
+ #define EXYNOSAUTOV9_CLUSTER1_WDTRESET_BIT 24
++#define EXYNOSAUTOV920_CLUSTER0_WDTRESET_BIT 0
++#define EXYNOSAUTOV920_CLUSTER1_WDTRESET_BIT 1
+
+ #define GS_CLUSTER0_NONCPU_OUT 0x1220
+ #define GS_CLUSTER1_NONCPU_OUT 0x1420
+@@ -312,9 +314,9 @@ static const struct s3c2410_wdt_variant drv_data_exynosautov920_cl0 = {
+ .mask_bit = 2,
+ .mask_reset_inv = true,
+ .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET,
+- .rst_stat_bit = EXYNOSAUTOV9_CLUSTER0_WDTRESET_BIT,
++ .rst_stat_bit = EXYNOSAUTOV920_CLUSTER0_WDTRESET_BIT,
+ .cnt_en_reg = EXYNOSAUTOV920_CLUSTER0_NONCPU_OUT,
+- .cnt_en_bit = 7,
++ .cnt_en_bit = 8,
+ .quirks = QUIRK_HAS_WTCLRINT_REG | QUIRK_HAS_PMU_MASK_RESET |
+ QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_CNT_EN |
+ QUIRK_HAS_DBGACK_BIT,
+@@ -325,9 +327,9 @@ static const struct s3c2410_wdt_variant drv_data_exynosautov920_cl1 = {
+ .mask_bit = 2,
+ .mask_reset_inv = true,
+ .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET,
+- .rst_stat_bit = EXYNOSAUTOV9_CLUSTER1_WDTRESET_BIT,
++ .rst_stat_bit = EXYNOSAUTOV920_CLUSTER1_WDTRESET_BIT,
+ .cnt_en_reg = EXYNOSAUTOV920_CLUSTER1_NONCPU_OUT,
+- .cnt_en_bit = 7,
++ .cnt_en_bit = 8,
+ .quirks = QUIRK_HAS_WTCLRINT_REG | QUIRK_HAS_PMU_MASK_RESET |
+ QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_CNT_EN |
+ QUIRK_HAS_DBGACK_BIT,
+--
+2.39.5
+
--- /dev/null
+From a535644548aecf29d355fb6bec779f186a19723c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 19 Jan 2025 22:12:19 +0530
+Subject: wifi: ath11k: Use dma_alloc_noncoherent for rx_tid buffer allocation
+
+From: P Praneesh <quic_ppranees@quicinc.com>
+
+[ Upstream commit eeadc6baf8b3dcd32787cc84f0473dc2a2850370 ]
+
+Currently, the driver allocates cacheable DMA buffers for the rx_tid
+structure using kzalloc() and dma_map_single(). These buffers are
+long-lived and can persist for the lifetime of the peer, which is not
+advisable. Instead of using kzalloc() and dma_map_single() for allocating
+cacheable DMA buffers, utilize the dma_alloc_noncoherent() helper for the
+allocation of long-lived cacheable DMA buffers, such as the peer's rx_tid.
+Since dma_alloc_noncoherent() returns unaligned physical and virtual
+addresses, align them internally before use within the driver. This
+ensures proper allocation of non-coherent memory through the kernel
+helper.
+
+Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
+Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3
+
+Signed-off-by: P Praneesh <quic_ppranees@quicinc.com>
+Tested-by: Tim Harvey <tharvey@gateworks.com>
+Link: https://patch.msgid.link/20250119164219.647059-3-quic_ppranees@quicinc.com
+Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ath/ath11k/dp.h | 6 +-
+ drivers/net/wireless/ath/ath11k/dp_rx.c | 117 +++++++++++-------------
+ 2 files changed, 58 insertions(+), 65 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath11k/dp.h b/drivers/net/wireless/ath/ath11k/dp.h
+index f777314db8b36..7a55afd33be82 100644
+--- a/drivers/net/wireless/ath/ath11k/dp.h
++++ b/drivers/net/wireless/ath/ath11k/dp.h
+@@ -1,7 +1,7 @@
+ /* SPDX-License-Identifier: BSD-3-Clause-Clear */
+ /*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+- * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
++ * Copyright (c) 2021-2023, 2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+ #ifndef ATH11K_DP_H
+@@ -20,7 +20,6 @@ struct ath11k_ext_irq_grp;
+
+ struct dp_rx_tid {
+ u8 tid;
+- u32 *vaddr;
+ dma_addr_t paddr;
+ u32 size;
+ u32 ba_win_sz;
+@@ -37,6 +36,9 @@ struct dp_rx_tid {
+ /* Timer info related to fragments */
+ struct timer_list frag_timer;
+ struct ath11k_base *ab;
++ u32 *vaddr_unaligned;
++ dma_addr_t paddr_unaligned;
++ u32 unaligned_size;
+ };
+
+ #define DP_REO_DESC_FREE_THRESHOLD 64
+diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c
+index b8b3dce9cdb53..a7a484a9ba7fb 100644
+--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
+@@ -1,7 +1,7 @@
+ // SPDX-License-Identifier: BSD-3-Clause-Clear
+ /*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+- * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
++ * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+ #include <linux/ieee80211.h>
+@@ -675,11 +675,11 @@ void ath11k_dp_reo_cmd_list_cleanup(struct ath11k_base *ab)
+ list_for_each_entry_safe(cmd, tmp, &dp->reo_cmd_list, list) {
+ list_del(&cmd->list);
+ rx_tid = &cmd->data;
+- if (rx_tid->vaddr) {
+- dma_unmap_single(ab->dev, rx_tid->paddr,
+- rx_tid->size, DMA_BIDIRECTIONAL);
+- kfree(rx_tid->vaddr);
+- rx_tid->vaddr = NULL;
++ if (rx_tid->vaddr_unaligned) {
++ dma_free_noncoherent(ab->dev, rx_tid->unaligned_size,
++ rx_tid->vaddr_unaligned,
++ rx_tid->paddr_unaligned, DMA_BIDIRECTIONAL);
++ rx_tid->vaddr_unaligned = NULL;
+ }
+ kfree(cmd);
+ }
+@@ -689,11 +689,11 @@ void ath11k_dp_reo_cmd_list_cleanup(struct ath11k_base *ab)
+ list_del(&cmd_cache->list);
+ dp->reo_cmd_cache_flush_count--;
+ rx_tid = &cmd_cache->data;
+- if (rx_tid->vaddr) {
+- dma_unmap_single(ab->dev, rx_tid->paddr,
+- rx_tid->size, DMA_BIDIRECTIONAL);
+- kfree(rx_tid->vaddr);
+- rx_tid->vaddr = NULL;
++ if (rx_tid->vaddr_unaligned) {
++ dma_free_noncoherent(ab->dev, rx_tid->unaligned_size,
++ rx_tid->vaddr_unaligned,
++ rx_tid->paddr_unaligned, DMA_BIDIRECTIONAL);
++ rx_tid->vaddr_unaligned = NULL;
+ }
+ kfree(cmd_cache);
+ }
+@@ -708,11 +708,11 @@ static void ath11k_dp_reo_cmd_free(struct ath11k_dp *dp, void *ctx,
+ if (status != HAL_REO_CMD_SUCCESS)
+ ath11k_warn(dp->ab, "failed to flush rx tid hw desc, tid %d status %d\n",
+ rx_tid->tid, status);
+- if (rx_tid->vaddr) {
+- dma_unmap_single(dp->ab->dev, rx_tid->paddr, rx_tid->size,
+- DMA_BIDIRECTIONAL);
+- kfree(rx_tid->vaddr);
+- rx_tid->vaddr = NULL;
++ if (rx_tid->vaddr_unaligned) {
++ dma_free_noncoherent(dp->ab->dev, rx_tid->unaligned_size,
++ rx_tid->vaddr_unaligned,
++ rx_tid->paddr_unaligned, DMA_BIDIRECTIONAL);
++ rx_tid->vaddr_unaligned = NULL;
+ }
+ }
+
+@@ -749,10 +749,10 @@ static void ath11k_dp_reo_cache_flush(struct ath11k_base *ab,
+ if (ret) {
+ ath11k_err(ab, "failed to send HAL_REO_CMD_FLUSH_CACHE cmd, tid %d (%d)\n",
+ rx_tid->tid, ret);
+- dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size,
+- DMA_BIDIRECTIONAL);
+- kfree(rx_tid->vaddr);
+- rx_tid->vaddr = NULL;
++ dma_free_noncoherent(ab->dev, rx_tid->unaligned_size,
++ rx_tid->vaddr_unaligned,
++ rx_tid->paddr_unaligned, DMA_BIDIRECTIONAL);
++ rx_tid->vaddr_unaligned = NULL;
+ }
+ }
+
+@@ -802,10 +802,10 @@ static void ath11k_dp_rx_tid_del_func(struct ath11k_dp *dp, void *ctx,
+
+ return;
+ free_desc:
+- dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size,
+- DMA_BIDIRECTIONAL);
+- kfree(rx_tid->vaddr);
+- rx_tid->vaddr = NULL;
++ dma_free_noncoherent(ab->dev, rx_tid->unaligned_size,
++ rx_tid->vaddr_unaligned,
++ rx_tid->paddr_unaligned, DMA_BIDIRECTIONAL);
++ rx_tid->vaddr_unaligned = NULL;
+ }
+
+ void ath11k_peer_rx_tid_delete(struct ath11k *ar,
+@@ -831,14 +831,16 @@ void ath11k_peer_rx_tid_delete(struct ath11k *ar,
+ if (ret != -ESHUTDOWN)
+ ath11k_err(ar->ab, "failed to send HAL_REO_CMD_UPDATE_RX_QUEUE cmd, tid %d (%d)\n",
+ tid, ret);
+- dma_unmap_single(ar->ab->dev, rx_tid->paddr, rx_tid->size,
+- DMA_BIDIRECTIONAL);
+- kfree(rx_tid->vaddr);
+- rx_tid->vaddr = NULL;
++ dma_free_noncoherent(ar->ab->dev, rx_tid->unaligned_size,
++ rx_tid->vaddr_unaligned,
++ rx_tid->paddr_unaligned, DMA_BIDIRECTIONAL);
++ rx_tid->vaddr_unaligned = NULL;
+ }
+
+ rx_tid->paddr = 0;
++ rx_tid->paddr_unaligned = 0;
+ rx_tid->size = 0;
++ rx_tid->unaligned_size = 0;
+ }
+
+ static int ath11k_dp_rx_link_desc_return(struct ath11k_base *ab,
+@@ -982,10 +984,9 @@ static void ath11k_dp_rx_tid_mem_free(struct ath11k_base *ab,
+ if (!rx_tid->active)
+ goto unlock_exit;
+
+- dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size,
+- DMA_BIDIRECTIONAL);
+- kfree(rx_tid->vaddr);
+- rx_tid->vaddr = NULL;
++ dma_free_noncoherent(ab->dev, rx_tid->unaligned_size, rx_tid->vaddr_unaligned,
++ rx_tid->paddr_unaligned, DMA_BIDIRECTIONAL);
++ rx_tid->vaddr_unaligned = NULL;
+
+ rx_tid->active = false;
+
+@@ -1000,9 +1001,8 @@ int ath11k_peer_rx_tid_setup(struct ath11k *ar, const u8 *peer_mac, int vdev_id,
+ struct ath11k_base *ab = ar->ab;
+ struct ath11k_peer *peer;
+ struct dp_rx_tid *rx_tid;
+- u32 hw_desc_sz;
+- u32 *addr_aligned;
+- void *vaddr;
++ u32 hw_desc_sz, *vaddr;
++ void *vaddr_unaligned;
+ dma_addr_t paddr;
+ int ret;
+
+@@ -1050,49 +1050,40 @@ int ath11k_peer_rx_tid_setup(struct ath11k *ar, const u8 *peer_mac, int vdev_id,
+ else
+ hw_desc_sz = ath11k_hal_reo_qdesc_size(DP_BA_WIN_SZ_MAX, tid);
+
+- vaddr = kzalloc(hw_desc_sz + HAL_LINK_DESC_ALIGN - 1, GFP_ATOMIC);
+- if (!vaddr) {
++ rx_tid->unaligned_size = hw_desc_sz + HAL_LINK_DESC_ALIGN - 1;
++ vaddr_unaligned = dma_alloc_noncoherent(ab->dev, rx_tid->unaligned_size, &paddr,
++ DMA_BIDIRECTIONAL, GFP_ATOMIC);
++ if (!vaddr_unaligned) {
+ spin_unlock_bh(&ab->base_lock);
+ return -ENOMEM;
+ }
+
+- addr_aligned = PTR_ALIGN(vaddr, HAL_LINK_DESC_ALIGN);
+-
+- ath11k_hal_reo_qdesc_setup(addr_aligned, tid, ba_win_sz,
+- ssn, pn_type);
+-
+- paddr = dma_map_single(ab->dev, addr_aligned, hw_desc_sz,
+- DMA_BIDIRECTIONAL);
+-
+- ret = dma_mapping_error(ab->dev, paddr);
+- if (ret) {
+- spin_unlock_bh(&ab->base_lock);
+- ath11k_warn(ab, "failed to setup dma map for peer %pM rx tid %d: %d\n",
+- peer_mac, tid, ret);
+- goto err_mem_free;
+- }
+-
+- rx_tid->vaddr = vaddr;
+- rx_tid->paddr = paddr;
++ rx_tid->vaddr_unaligned = vaddr_unaligned;
++ vaddr = PTR_ALIGN(vaddr_unaligned, HAL_LINK_DESC_ALIGN);
++ rx_tid->paddr_unaligned = paddr;
++ rx_tid->paddr = rx_tid->paddr_unaligned + ((unsigned long)vaddr -
++ (unsigned long)rx_tid->vaddr_unaligned);
++ ath11k_hal_reo_qdesc_setup(vaddr, tid, ba_win_sz, ssn, pn_type);
+ rx_tid->size = hw_desc_sz;
+ rx_tid->active = true;
+
++ /* After dma_alloc_noncoherent, vaddr is being modified for reo qdesc setup.
++ * Since these changes are not reflected in the device, driver now needs to
++ * explicitly call dma_sync_single_for_device.
++ */
++ dma_sync_single_for_device(ab->dev, rx_tid->paddr,
++ rx_tid->size,
++ DMA_TO_DEVICE);
+ spin_unlock_bh(&ab->base_lock);
+
+- ret = ath11k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id, peer_mac,
+- paddr, tid, 1, ba_win_sz);
++ ret = ath11k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id, peer_mac, rx_tid->paddr,
++ tid, 1, ba_win_sz);
+ if (ret) {
+ ath11k_warn(ar->ab, "failed to setup rx reorder queue for peer %pM tid %d: %d\n",
+ peer_mac, tid, ret);
+ ath11k_dp_rx_tid_mem_free(ab, peer_mac, vdev_id, tid);
+ }
+
+- return ret;
+-
+-err_mem_free:
+- kfree(rx_tid->vaddr);
+- rx_tid->vaddr = NULL;
+-
+ return ret;
+ }
+
+--
+2.39.5
+
--- /dev/null
+From 1b06e3d70050de0615ca810193fd3259059b8547 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 24 Jan 2025 14:30:58 +0530
+Subject: wifi: ath12k: Avoid napi_sync() before napi_enable()
+
+From: Avula Sri Charan <quic_asrichar@quicinc.com>
+
+[ Upstream commit 268c73d470a5790a492a2fc2ded084b909d144f3 ]
+
+In case of MHI error a reset work will be queued which will try
+napi_disable() after napi_synchronize().
+
+As the napi will be only enabled after qmi_firmware_ready event,
+trying napi_synchronize() before napi_enable() will result in
+indefinite sleep in case of a firmware crash in QMI init sequence.
+
+To avoid this, introduce napi_enabled flag to check if napi is enabled
+or not before calling napi_synchronize().
+
+Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1
+
+Signed-off-by: Avula Sri Charan <quic_asrichar@quicinc.com>
+Signed-off-by: Tamizh Chelvam Raja <quic_tamizhr@quicinc.com>
+Reviewed-by: Aditya Kumar Singh <aditya.kumar.singh@oss.qualcomm.com>
+Link: https://patch.msgid.link/20250124090058.3194299-1-quic_tamizhr@quicinc.com
+Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ath/ath12k/core.h | 1 +
+ drivers/net/wireless/ath/ath12k/pci.c | 13 ++++++++++---
+ 2 files changed, 11 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
+index 6325ac493f82c..2699c383fc4c9 100644
+--- a/drivers/net/wireless/ath/ath12k/core.h
++++ b/drivers/net/wireless/ath/ath12k/core.h
+@@ -166,6 +166,7 @@ struct ath12k_ext_irq_grp {
+ u32 num_irq;
+ u32 grp_id;
+ u64 timestamp;
++ bool napi_enabled;
+ struct napi_struct napi;
+ struct net_device *napi_ndev;
+ };
+diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c
+index ee14b84845487..895b2314d1d58 100644
+--- a/drivers/net/wireless/ath/ath12k/pci.c
++++ b/drivers/net/wireless/ath/ath12k/pci.c
+@@ -483,8 +483,11 @@ static void __ath12k_pci_ext_irq_disable(struct ath12k_base *ab)
+
+ ath12k_pci_ext_grp_disable(irq_grp);
+
+- napi_synchronize(&irq_grp->napi);
+- napi_disable(&irq_grp->napi);
++ if (irq_grp->napi_enabled) {
++ napi_synchronize(&irq_grp->napi);
++ napi_disable(&irq_grp->napi);
++ irq_grp->napi_enabled = false;
++ }
+ }
+ }
+
+@@ -1114,7 +1117,11 @@ void ath12k_pci_ext_irq_enable(struct ath12k_base *ab)
+ for (i = 0; i < ATH12K_EXT_IRQ_GRP_NUM_MAX; i++) {
+ struct ath12k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
+
+- napi_enable(&irq_grp->napi);
++ if (!irq_grp->napi_enabled) {
++ napi_enable(&irq_grp->napi);
++ irq_grp->napi_enabled = true;
++ }
++
+ ath12k_pci_ext_grp_enable(irq_grp);
+ }
+
+--
+2.39.5
+
--- /dev/null
+From 85f91df4ece637c376a2a944a0ba38247f5f4772 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 7 Feb 2025 10:33:25 +0530
+Subject: wifi: ath12k: Enable MLO setup ready and teardown commands for single
+ split-phy device
+
+From: Aaradhana Sahu <quic_aarasahu@quicinc.com>
+
+[ Upstream commit 5cec2d86c7f4242fb30a696d8e6fd48109bf3e8f ]
+
+When multi-link operation(MLO) is enabled through follow-up patches in
+the single split-phy device, the firmware expects hardware links
+(hw_links) information from the driver.
+
+If driver does not send WMI multi-link setup and ready command to the
+firmware during MLO setup for single split-phy device, the firmware will
+be unaware of the hw_links component of the multi-link operation. This may
+lead to firmware assert during multi-link association.
+
+Therefore, enable WMI setup, ready and teardown commands for single
+split-phy PCI device.
+
+Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1
+Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3
+
+Signed-off-by: Aaradhana Sahu <quic_aarasahu@quicinc.com>
+Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
+Link: https://patch.msgid.link/20250207050327.360987-2-quic_aarasahu@quicinc.com
+Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ath/ath12k/core.c | 33 +++++++++++++++++++++++++-
+ drivers/net/wireless/ath/ath12k/core.h | 1 +
+ drivers/net/wireless/ath/ath12k/mac.c | 9 +++++++
+ 3 files changed, 42 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
+index 212cd935e60a0..ffd173ff7b08c 100644
+--- a/drivers/net/wireless/ath/ath12k/core.c
++++ b/drivers/net/wireless/ath/ath12k/core.c
+@@ -887,10 +887,41 @@ static void ath12k_core_hw_group_stop(struct ath12k_hw_group *ag)
+ ath12k_mac_destroy(ag);
+ }
+
++u8 ath12k_get_num_partner_link(struct ath12k *ar)
++{
++ struct ath12k_base *partner_ab, *ab = ar->ab;
++ struct ath12k_hw_group *ag = ab->ag;
++ struct ath12k_pdev *pdev;
++ u8 num_link = 0;
++ int i, j;
++
++ lockdep_assert_held(&ag->mutex);
++
++ for (i = 0; i < ag->num_devices; i++) {
++ partner_ab = ag->ab[i];
++
++ for (j = 0; j < partner_ab->num_radios; j++) {
++ pdev = &partner_ab->pdevs[j];
++
++ /* Avoid the self link */
++ if (ar == pdev->ar)
++ continue;
++
++ num_link++;
++ }
++ }
++
++ return num_link;
++}
++
+ static int __ath12k_mac_mlo_ready(struct ath12k *ar)
+ {
++ u8 num_link = ath12k_get_num_partner_link(ar);
+ int ret;
+
++ if (num_link == 0)
++ return 0;
++
+ ret = ath12k_wmi_mlo_ready(ar);
+ if (ret) {
+ ath12k_err(ar->ab, "MLO ready failed for pdev %d: %d\n",
+@@ -932,7 +963,7 @@ static int ath12k_core_mlo_setup(struct ath12k_hw_group *ag)
+ {
+ int ret, i;
+
+- if (!ag->mlo_capable || ag->num_devices == 1)
++ if (!ag->mlo_capable)
+ return 0;
+
+ ret = ath12k_mac_mlo_setup(ag);
+diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
+index ee595794a7aee..6325ac493f82c 100644
+--- a/drivers/net/wireless/ath/ath12k/core.h
++++ b/drivers/net/wireless/ath/ath12k/core.h
+@@ -1084,6 +1084,7 @@ int ath12k_core_resume(struct ath12k_base *ab);
+ int ath12k_core_suspend(struct ath12k_base *ab);
+ int ath12k_core_suspend_late(struct ath12k_base *ab);
+ void ath12k_core_hw_group_unassign(struct ath12k_base *ab);
++u8 ath12k_get_num_partner_link(struct ath12k *ar);
+
+ const struct firmware *ath12k_core_firmware_request(struct ath12k_base *ab,
+ const char *filename);
+diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
+index 9c3e66dbe0c3b..9123ffab55b52 100644
+--- a/drivers/net/wireless/ath/ath12k/mac.c
++++ b/drivers/net/wireless/ath/ath12k/mac.c
+@@ -11140,6 +11140,9 @@ static int __ath12k_mac_mlo_setup(struct ath12k *ar)
+ }
+ }
+
++ if (num_link == 0)
++ return 0;
++
+ mlo.group_id = cpu_to_le32(ag->id);
+ mlo.partner_link_id = partner_link_id;
+ mlo.num_partner_links = num_link;
+@@ -11169,10 +11172,16 @@ static int __ath12k_mac_mlo_teardown(struct ath12k *ar)
+ {
+ struct ath12k_base *ab = ar->ab;
+ int ret;
++ u8 num_link;
+
+ if (test_bit(ATH12K_FLAG_RECOVERY, &ab->dev_flags))
+ return 0;
+
++ num_link = ath12k_get_num_partner_link(ar);
++
++ if (num_link == 0)
++ return 0;
++
+ ret = ath12k_wmi_mlo_teardown(ar);
+ if (ret) {
+ ath12k_warn(ab, "failed to send MLO teardown WMI command for pdev %d: %d\n",
+--
+2.39.5
+
--- /dev/null
+From d35663feacb955bdfb2769b04231c0172af119b3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Jan 2025 08:58:35 +0530
+Subject: wifi: ath12k: Fetch regdb.bin file from board-2.bin
+
+From: Aaradhana Sahu <quic_aarasahu@quicinc.com>
+
+[ Upstream commit 24f587572acf7509127dbdfcbf1b681ef84eeba0 ]
+
+Currently, ath12k_core_fetch_regdb() finds regdb.bin file through
+board id's but in board-2.bin file regdb.bin file is present with
+default board id because of which regdb.bin is not fetched.
+
+Add support to fetch regdb.bin file from board-2.bin through
+default board id.
+
+Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1
+
+Signed-off-by: Aaradhana Sahu <quic_aarasahu@quicinc.com>
+Reviewed-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
+Link: https://patch.msgid.link/20250116032835.118397-1-quic_aarasahu@quicinc.com
+Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ath/ath12k/core.c | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
+index ffd173ff7b08c..d0aed4c56050d 100644
+--- a/drivers/net/wireless/ath/ath12k/core.c
++++ b/drivers/net/wireless/ath/ath12k/core.c
+@@ -173,7 +173,7 @@ EXPORT_SYMBOL(ath12k_core_resume);
+
+ static int __ath12k_core_create_board_name(struct ath12k_base *ab, char *name,
+ size_t name_len, bool with_variant,
+- bool bus_type_mode)
++ bool bus_type_mode, bool with_default)
+ {
+ /* strlen(',variant=') + strlen(ab->qmi.target.bdf_ext) */
+ char variant[9 + ATH12K_QMI_BDF_EXT_STR_LENGTH] = { 0 };
+@@ -204,7 +204,9 @@ static int __ath12k_core_create_board_name(struct ath12k_base *ab, char *name,
+ "bus=%s,qmi-chip-id=%d,qmi-board-id=%d%s",
+ ath12k_bus_str(ab->hif.bus),
+ ab->qmi.target.chip_id,
+- ab->qmi.target.board_id, variant);
++ with_default ?
++ ATH12K_BOARD_ID_DEFAULT : ab->qmi.target.board_id,
++ variant);
+ break;
+ }
+
+@@ -216,19 +218,19 @@ static int __ath12k_core_create_board_name(struct ath12k_base *ab, char *name,
+ static int ath12k_core_create_board_name(struct ath12k_base *ab, char *name,
+ size_t name_len)
+ {
+- return __ath12k_core_create_board_name(ab, name, name_len, true, false);
++ return __ath12k_core_create_board_name(ab, name, name_len, true, false, false);
+ }
+
+ static int ath12k_core_create_fallback_board_name(struct ath12k_base *ab, char *name,
+ size_t name_len)
+ {
+- return __ath12k_core_create_board_name(ab, name, name_len, false, false);
++ return __ath12k_core_create_board_name(ab, name, name_len, false, false, true);
+ }
+
+ static int ath12k_core_create_bus_type_board_name(struct ath12k_base *ab, char *name,
+ size_t name_len)
+ {
+- return __ath12k_core_create_board_name(ab, name, name_len, false, true);
++ return __ath12k_core_create_board_name(ab, name, name_len, false, true, true);
+ }
+
+ const struct firmware *ath12k_core_firmware_request(struct ath12k_base *ab,
+--
+2.39.5
+
--- /dev/null
+From 2e21d5fa7b90cd290907de47b44aa0cb25a95ee2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jan 2025 08:13:06 +0100
+Subject: wifi: ath12k: fix ath12k_hal_tx_cmd_ext_desc_setup() info1 override
+
+From: Nicolas Escande <nico.escande@gmail.com>
+
+[ Upstream commit df11edfba49e5fb69f4c9e7cb76082b89c417f78 ]
+
+Since inception there is an obvious typo laying around in
+ath12k_hal_tx_cmd_ext_desc_setup(). Instead of initializing + adding
+flags to tcl_ext_cmd->info1, we initialize + override. This will be needed
+in the future to make broadcast frames work with ethernet encapsulation.
+
+Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1
+
+Signed-off-by: Nicolas Escande <nico.escande@gmail.com>
+Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
+Link: https://patch.msgid.link/20250127071306.1454699-1-nico.escande@gmail.com
+Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ath/ath12k/dp_tx.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c
+index 75608ae027afe..a39bfb959797a 100644
+--- a/drivers/net/wireless/ath/ath12k/dp_tx.c
++++ b/drivers/net/wireless/ath/ath12k/dp_tx.c
+@@ -117,7 +117,7 @@ static void ath12k_hal_tx_cmd_ext_desc_setup(struct ath12k_base *ab,
+ le32_encode_bits(ti->data_len,
+ HAL_TX_MSDU_EXT_INFO1_BUF_LEN);
+
+- tcl_ext_cmd->info1 = le32_encode_bits(1, HAL_TX_MSDU_EXT_INFO1_EXTN_OVERRIDE) |
++ tcl_ext_cmd->info1 |= le32_encode_bits(1, HAL_TX_MSDU_EXT_INFO1_EXTN_OVERRIDE) |
+ le32_encode_bits(ti->encap_type,
+ HAL_TX_MSDU_EXT_INFO1_ENCAP_TYPE) |
+ le32_encode_bits(ti->encrypt_type,
+--
+2.39.5
+
--- /dev/null
+From db321df1c4513a1a8ebe618ba9e9e093cd26cb94 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 23 Dec 2024 11:31:25 +0530
+Subject: wifi: ath12k: Fix end offset bit definition in monitor ring
+ descriptor
+
+From: P Praneesh <quic_ppranees@quicinc.com>
+
+[ Upstream commit 6788a666000d600bd8f2e9f991cad9cc805e7f01 ]
+
+End offset for the monitor destination ring descriptor is defined as
+16 bits, while the firmware definition specifies only 12 bits.
+The remaining bits (bit 12 to bit 15) are reserved and may contain
+junk values, leading to invalid information retrieval. Fix this issue
+by updating the correct genmask values.
+
+Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1
+Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3
+
+Signed-off-by: P Praneesh <quic_ppranees@quicinc.com>
+Link: https://patch.msgid.link/20241223060132.3506372-8-quic_ppranees@quicinc.com
+Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ath/ath12k/hal_desc.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/ath/ath12k/hal_desc.h b/drivers/net/wireless/ath/ath12k/hal_desc.h
+index 7b0403d245e59..a102d27e5785f 100644
+--- a/drivers/net/wireless/ath/ath12k/hal_desc.h
++++ b/drivers/net/wireless/ath/ath12k/hal_desc.h
+@@ -2968,7 +2968,7 @@ struct hal_mon_buf_ring {
+
+ #define HAL_MON_DEST_COOKIE_BUF_ID GENMASK(17, 0)
+
+-#define HAL_MON_DEST_INFO0_END_OFFSET GENMASK(15, 0)
++#define HAL_MON_DEST_INFO0_END_OFFSET GENMASK(11, 0)
+ #define HAL_MON_DEST_INFO0_FLUSH_DETECTED BIT(16)
+ #define HAL_MON_DEST_INFO0_END_OF_PPDU BIT(17)
+ #define HAL_MON_DEST_INFO0_INITIATOR BIT(18)
+--
+2.39.5
+
--- /dev/null
+From c9cec9ed440ecd27ad77da9bb0f7cd48b642caf5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Feb 2025 07:08:51 +0530
+Subject: wifi: ath12k: fix the ampdu id fetch in the HAL_RX_MPDU_START TLV
+
+From: P Praneesh <quic_ppranees@quicinc.com>
+
+[ Upstream commit dff4f278ee1ef12d822b7ed2a1048d27037209bb ]
+
+Currently, ampdu id is update with peer id mask which is incorrect.
+Therefore, update the ampdu id with PPDU id mask value. Also move
+the ampdu_id field inside the user stats since it is a user id based
+statistics.
+
+Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1
+Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3
+
+Signed-off-by: P Praneesh <quic_ppranees@quicinc.com>
+Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
+Signed-off-by: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
+Link: https://patch.msgid.link/20250206013854.174765-7-quic_periyasa@quicinc.com
+Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ath/ath12k/dp_mon.c | 16 ++++++++++------
+ drivers/net/wireless/ath/ath12k/hal_rx.h | 3 ++-
+ 2 files changed, 12 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c
+index b952e79179d01..f23fee7055abc 100644
+--- a/drivers/net/wireless/ath/ath12k/dp_mon.c
++++ b/drivers/net/wireless/ath/ath12k/dp_mon.c
+@@ -1,7 +1,7 @@
+ // SPDX-License-Identifier: BSD-3-Clause-Clear
+ /*
+ * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
+- * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
++ * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+ #include "dp_mon.h"
+@@ -655,6 +655,11 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab,
+ if (userid < HAL_MAX_UL_MU_USERS) {
+ struct hal_rx_user_status *rxuser_stats =
+ &ppdu_info->userstats[userid];
++
++ if (ppdu_info->num_mpdu_fcs_ok > 1 ||
++ ppdu_info->num_mpdu_fcs_err > 1)
++ ppdu_info->userstats[userid].ampdu_present = true;
++
+ ppdu_info->num_users += 1;
+
+ ath12k_dp_mon_rx_handle_ofdma_info(eu_stats, rxuser_stats);
+@@ -755,8 +760,8 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab,
+ if (userid < HAL_MAX_UL_MU_USERS) {
+ info[0] = __le32_to_cpu(mpdu_start->info0);
+ ppdu_info->userid = userid;
+- ppdu_info->ampdu_id[userid] =
+- u32_get_bits(info[0], HAL_RX_MPDU_START_INFO1_PEERID);
++ ppdu_info->userstats[userid].ampdu_id =
++ u32_get_bits(info[0], HAL_RX_MPDU_START_INFO0_PPDU_ID);
+ }
+
+ break;
+@@ -956,15 +961,14 @@ static void ath12k_dp_mon_update_radiotap(struct ath12k *ar,
+ {
+ struct ieee80211_supported_band *sband;
+ u8 *ptr = NULL;
+- u16 ampdu_id = ppduinfo->ampdu_id[ppduinfo->userid];
+
+ rxs->flag |= RX_FLAG_MACTIME_START;
+ rxs->signal = ppduinfo->rssi_comb + ATH12K_DEFAULT_NOISE_FLOOR;
+ rxs->nss = ppduinfo->nss + 1;
+
+- if (ampdu_id) {
++ if (ppduinfo->userstats[ppduinfo->userid].ampdu_present) {
+ rxs->flag |= RX_FLAG_AMPDU_DETAILS;
+- rxs->ampdu_reference = ampdu_id;
++ rxs->ampdu_reference = ppduinfo->userstats[ppduinfo->userid].ampdu_id;
+ }
+
+ if (ppduinfo->he_mu_flags) {
+diff --git a/drivers/net/wireless/ath/ath12k/hal_rx.h b/drivers/net/wireless/ath/ath12k/hal_rx.h
+index 54f3eaeca8bb9..55b2dd5b76f6b 100644
+--- a/drivers/net/wireless/ath/ath12k/hal_rx.h
++++ b/drivers/net/wireless/ath/ath12k/hal_rx.h
+@@ -146,6 +146,8 @@ struct hal_rx_user_status {
+ u32 mpdu_fcs_ok_bitmap[HAL_RX_NUM_WORDS_PER_PPDU_BITMAP];
+ u32 mpdu_ok_byte_count;
+ u32 mpdu_err_byte_count;
++ bool ampdu_present;
++ u16 ampdu_id;
+ };
+
+ #define HAL_MAX_UL_MU_USERS 37
+@@ -230,7 +232,6 @@ struct hal_rx_mon_ppdu_info {
+ u8 addr4[ETH_ALEN];
+ struct hal_rx_user_status userstats[HAL_MAX_UL_MU_USERS];
+ u8 userid;
+- u16 ampdu_id[HAL_MAX_UL_MU_USERS];
+ bool first_msdu_in_mpdu;
+ bool is_ampdu;
+ u8 medium_prot_type;
+--
+2.39.5
+
--- /dev/null
+From 8a36034f765975fabc00b1de0d5eb4a01c522dcb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 7 Feb 2025 11:30:05 +0530
+Subject: wifi: ath12k: Improve BSS discovery with hidden SSID in 6 GHz band
+
+From: Ramasamy Kaliappan <quic_rkaliapp@quicinc.com>
+
+[ Upstream commit 27d38bdfd416f4db70e09c3bef3b030c86fd235a ]
+
+Currently, sometimes, the station is unable to identify the configured
+AP SSID in its scan results when the AP is not broadcasting its name
+publicly and has a hidden SSID.
+
+Currently, channel dwell time for an ath12k station is 30 ms. Sometimes,
+station can send broadcast probe request to AP close to the end of dwell
+time. In some of these cases, before AP sends a response to the received
+probe request, the dwell time on the station side would come to an end.
+So, the station will move to scan next channel and will not be able to
+acknowledge the unicast probe response.
+
+Resolve this issue by increasing station's channel dwell time to 70 ms,
+so that the it remains on the same channel for a longer period. This
+would increase the station's chance of receiving probe response from the
+AP. The station will then send a response acknowledgment back to the AP,
+thus leading to successful scan and BSS discovery.
+
+With an increased dwell time, scan would take longer than it takes now.
+But, this fix is an improvement for hidden SSID scan issue.
+
+Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1
+
+Signed-off-by: Ramasamy Kaliappan <quic_rkaliapp@quicinc.com>
+Signed-off-by: Roopni Devanathan <quic_rdevanat@quicinc.com>
+Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
+Link: https://patch.msgid.link/20250207060005.153835-1-quic_rdevanat@quicinc.com
+Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ath/ath12k/wmi.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
+index 7a87777e0a047..9cd7ceae5a4f8 100644
+--- a/drivers/net/wireless/ath/ath12k/wmi.c
++++ b/drivers/net/wireless/ath/ath12k/wmi.c
+@@ -2373,8 +2373,8 @@ void ath12k_wmi_start_scan_init(struct ath12k *ar,
+ arg->dwell_time_active = 50;
+ arg->dwell_time_active_2g = 0;
+ arg->dwell_time_passive = 150;
+- arg->dwell_time_active_6g = 40;
+- arg->dwell_time_passive_6g = 30;
++ arg->dwell_time_active_6g = 70;
++ arg->dwell_time_passive_6g = 70;
+ arg->min_rest_time = 50;
+ arg->max_rest_time = 500;
+ arg->repeat_probe_time = 0;
+--
+2.39.5
+
--- /dev/null
+From 66186ba383d93d524caa4a2abac7a88ce9aee5b9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 22 Nov 2024 23:04:32 +0530
+Subject: wifi: ath12k: Report proper tx completion status to mac80211
+
+From: Vinith Kumar R <quic_vinithku@quicinc.com>
+
+[ Upstream commit d2d9c9b8de725e1006d3aa3d18678a732f5d3584 ]
+
+Currently Tx completion for few exception packets are received from
+firmware and the tx status updated to mac80211. The tx status values of
+HAL_WBM_REL_HTT_TX_COMP_STATUS_DROP and HAL_WBM_REL_HTT_TX_COMP_STATUS_TTL
+are considered as tx failure and reported as tx failure to mac80211.
+But these failure status is due to internal firmware tx drop and these
+packets were not tried to transmit in the air.
+In case of mesh this invalid tx status report might trigger mpath broken
+issue due to increase in mpath fail average.
+So do not report these tx status as tx failure instead free the skb
+by calling ieee80211_free_txskb(), and that will be accounted as dropped
+frame.
+
+Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1
+
+Signed-off-by: Vinith Kumar R <quic_vinithku@quicinc.com>
+Signed-off-by: Tamizh Chelvam Raja <quic_tamizhr@quicinc.com>
+Acked-by: Jeff Johnson <quic_jjohnson@quicinc.com>
+Link: https://patch.msgid.link/20241122173432.2064858-1-quic_tamizhr@quicinc.com
+Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ath/ath12k/dp_tx.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c
+index 1fffabaca527a..75608ae027afe 100644
+--- a/drivers/net/wireless/ath/ath12k/dp_tx.c
++++ b/drivers/net/wireless/ath/ath12k/dp_tx.c
+@@ -560,13 +560,13 @@ ath12k_dp_tx_process_htt_tx_complete(struct ath12k_base *ab,
+
+ switch (wbm_status) {
+ case HAL_WBM_REL_HTT_TX_COMP_STATUS_OK:
+- case HAL_WBM_REL_HTT_TX_COMP_STATUS_DROP:
+- case HAL_WBM_REL_HTT_TX_COMP_STATUS_TTL:
+ ts.acked = (wbm_status == HAL_WBM_REL_HTT_TX_COMP_STATUS_OK);
+ ts.ack_rssi = le32_get_bits(status_desc->info2,
+ HTT_TX_WBM_COMP_INFO2_ACK_RSSI);
+ ath12k_dp_tx_htt_tx_complete_buf(ab, msdu, tx_ring, &ts);
+ break;
++ case HAL_WBM_REL_HTT_TX_COMP_STATUS_DROP:
++ case HAL_WBM_REL_HTT_TX_COMP_STATUS_TTL:
+ case HAL_WBM_REL_HTT_TX_COMP_STATUS_REINJ:
+ case HAL_WBM_REL_HTT_TX_COMP_STATUS_INSPECT:
+ ath12k_dp_tx_free_txbuf(ab, msdu, mac_id, tx_ring);
+--
+2.39.5
+
--- /dev/null
+From dd3ba246e6556b447753b6a462e0ab45c18adc15 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 15 Jan 2025 14:35:36 +0800
+Subject: wifi: ath12k: report station mode receive rate for IEEE 802.11be
+
+From: Lingbo Kong <quic_lingbok@quicinc.com>
+
+[ Upstream commit 5e73276c814fc1a5a1bce6be743e1a07baa6d4bc ]
+
+Currently, the receive rate of EHT of "iw dev xxx station dump" command
+always show an invalid value.
+
+This is because ath12k does not pass information about the rx_status of EHT
+to mac80211. So, mac80211 not calculate the receive rate.
+
+To address this issue, add logic for handling rx_status of EHT to the
+ath12k_dp_rx_h_rate() function.
+
+After that, "iw dev xxx station dump" show the correct receive rate.
+Such as:
+
+Station 00:03:7f:12:03:03 (on wlo1)
+ inactive time: 48 ms
+ rx bytes: 59226
+ rx packets: 320
+ tx bytes: 26556
+ tx packets: 191
+ tx retries: 99
+ tx failed: 0
+ beacon loss: 0
+ beacon rx: 79
+ rx drop misc: 68
+ signal: -95 dBm
+ beacon signal avg: -20 dBm
+ tx bitrate: 688.2 MBit/s 40MHz EHT-MCS 13 EHT-NSS 2 EHT-GI 0
+ tx duration: 0 us
+ rx bitrate: 619.5 MBit/s 40MHz EHT-MCS 8 EHT-NSS 3 EHT-GI 0
+
+This patch affects the station mode of WCN7850 and QCN9274.
+
+Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3
+Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00214-QCAHKSWPL_SILICONZ-1
+
+Signed-off-by: Lingbo Kong <quic_lingbok@quicinc.com>
+Closes: https://bugzilla.kernel.org/show_bug.cgi?id=219715
+Link: https://patch.msgid.link/20250115063537.35797-3-quic_lingbok@quicinc.com
+Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ath/ath12k/dp_rx.c | 22 ++++++++++++++++++++--
+ drivers/net/wireless/ath/ath12k/rx_desc.h | 2 ++
+ 2 files changed, 22 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c
+index ae6608b10bb57..ff6a709b5042c 100644
+--- a/drivers/net/wireless/ath/ath12k/dp_rx.c
++++ b/drivers/net/wireless/ath/ath12k/dp_rx.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-2024 Qualcomm Innovation Center, Inc. All rights reserved.
++ * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+ #include <linux/ieee80211.h>
+@@ -2392,6 +2392,23 @@ static void ath12k_dp_rx_h_rate(struct ath12k *ar, struct hal_rx_desc *rx_desc,
+ rx_status->he_gi = ath12k_he_gi_to_nl80211_he_gi(sgi);
+ rx_status->bw = ath12k_mac_bw_to_mac80211_bw(bw);
+ break;
++ case RX_MSDU_START_PKT_TYPE_11BE:
++ rx_status->rate_idx = rate_mcs;
++
++ if (rate_mcs > ATH12K_EHT_MCS_MAX) {
++ ath12k_warn(ar->ab,
++ "Received with invalid mcs in EHT mode %d\n",
++ rate_mcs);
++ break;
++ }
++
++ rx_status->encoding = RX_ENC_EHT;
++ rx_status->nss = nss;
++ rx_status->eht.gi = ath12k_mac_eht_gi_to_nl80211_eht_gi(sgi);
++ rx_status->bw = ath12k_mac_bw_to_mac80211_bw(bw);
++ break;
++ default:
++ break;
+ }
+ }
+
+@@ -2486,7 +2503,7 @@ static void ath12k_dp_rx_deliver_msdu(struct ath12k *ar, struct napi_struct *nap
+ spin_unlock_bh(&ab->base_lock);
+
+ ath12k_dbg(ab, ATH12K_DBG_DATA,
+- "rx skb %p len %u peer %pM %d %s sn %u %s%s%s%s%s%s%s%s%s rate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n",
++ "rx skb %p len %u peer %pM %d %s sn %u %s%s%s%s%s%s%s%s%s%s rate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n",
+ msdu,
+ msdu->len,
+ peer ? peer->addr : NULL,
+@@ -2497,6 +2514,7 @@ static void ath12k_dp_rx_deliver_msdu(struct ath12k *ar, struct napi_struct *nap
+ (status->encoding == RX_ENC_HT) ? "ht" : "",
+ (status->encoding == RX_ENC_VHT) ? "vht" : "",
+ (status->encoding == RX_ENC_HE) ? "he" : "",
++ (status->encoding == RX_ENC_EHT) ? "eht" : "",
+ (status->bw == RATE_INFO_BW_40) ? "40" : "",
+ (status->bw == RATE_INFO_BW_80) ? "80" : "",
+ (status->bw == RATE_INFO_BW_160) ? "160" : "",
+diff --git a/drivers/net/wireless/ath/ath12k/rx_desc.h b/drivers/net/wireless/ath/ath12k/rx_desc.h
+index 10366bbe99999..fc1eceb2d99bb 100644
+--- a/drivers/net/wireless/ath/ath12k/rx_desc.h
++++ b/drivers/net/wireless/ath/ath12k/rx_desc.h
+@@ -637,6 +637,8 @@ enum rx_msdu_start_pkt_type {
+ RX_MSDU_START_PKT_TYPE_11N,
+ RX_MSDU_START_PKT_TYPE_11AC,
+ RX_MSDU_START_PKT_TYPE_11AX,
++ RX_MSDU_START_PKT_TYPE_11BA,
++ RX_MSDU_START_PKT_TYPE_11BE,
+ };
+
+ enum rx_msdu_start_sgi {
+--
+2.39.5
+
--- /dev/null
+From 3f401c76ca6891897ff4ad67df9d4cd1bd3119bc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 15 Jan 2025 14:35:35 +0800
+Subject: wifi: ath12k: report station mode transmit rate
+
+From: Lingbo Kong <quic_lingbok@quicinc.com>
+
+[ Upstream commit 8a9c06b40882ebea45563059ddc5d57acdec9dda ]
+
+Currently, the transmit rate of "iw dev xxx station dump" command
+always show an invalid value.
+
+To address this issue, ath12k parse the info of transmit complete
+report from firmware and indicate the transmit rate to mac80211.
+
+This patch affects the station mode of WCN7850 and QCN9274.
+
+After that, "iw dev xxx station dump" show the correct transmit rate.
+Such as:
+
+Station 00:03:7f:12:03:03 (on wlo1)
+ inactive time: 872 ms
+ rx bytes: 219111
+ rx packets: 1133
+ tx bytes: 53767
+ tx packets: 462
+ tx retries: 51
+ tx failed: 0
+ beacon loss: 0
+ beacon rx: 403
+ rx drop misc: 74
+ signal: -95 dBm
+ beacon signal avg: -18 dBm
+ tx bitrate: 1441.1 MBit/s 80MHz EHT-MCS 13 EHT-NSS 2 EHT-GI 0
+
+Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3
+Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00214-QCAHKSWPL_SILICONZ-1
+
+Signed-off-by: Lingbo Kong <quic_lingbok@quicinc.com>
+Closes: https://bugzilla.kernel.org/show_bug.cgi?id=219715
+Link: https://patch.msgid.link/20250115063537.35797-2-quic_lingbok@quicinc.com
+Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ath/ath12k/core.h | 2 +
+ drivers/net/wireless/ath/ath12k/dp_rx.h | 5 +-
+ drivers/net/wireless/ath/ath12k/dp_tx.c | 139 +++++++++++++++++++++-
+ drivers/net/wireless/ath/ath12k/hal_rx.h | 5 +-
+ drivers/net/wireless/ath/ath12k/hal_tx.h | 10 +-
+ drivers/net/wireless/ath/ath12k/mac.c | 79 ++++++++++++
+ drivers/net/wireless/ath/ath12k/mac.h | 5 +-
+ drivers/net/wireless/ath/ath12k/rx_desc.h | 3 +-
+ 8 files changed, 238 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
+index 2699c383fc4c9..96b2830e891bd 100644
+--- a/drivers/net/wireless/ath/ath12k/core.h
++++ b/drivers/net/wireless/ath/ath12k/core.h
+@@ -87,6 +87,7 @@ enum wme_ac {
+ #define ATH12K_HT_MCS_MAX 7
+ #define ATH12K_VHT_MCS_MAX 9
+ #define ATH12K_HE_MCS_MAX 11
++#define ATH12K_EHT_MCS_MAX 15
+
+ enum ath12k_crypt_mode {
+ /* Only use hardware crypto engine */
+@@ -501,6 +502,7 @@ struct ath12k_link_sta {
+ struct ath12k_rx_peer_stats *rx_stats;
+ struct ath12k_wbm_tx_stats *wbm_tx_stats;
+ u32 bw_prev;
++ u32 peer_nss;
+
+ /* For now the assoc link will be considered primary */
+ bool is_assoc_link;
+diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.h b/drivers/net/wireless/ath/ath12k/dp_rx.h
+index 1ce82088c9540..c0aa965f47e77 100644
+--- a/drivers/net/wireless/ath/ath12k/dp_rx.h
++++ b/drivers/net/wireless/ath/ath12k/dp_rx.h
+@@ -1,7 +1,7 @@
+ /* SPDX-License-Identifier: BSD-3-Clause-Clear */
+ /*
+ * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
+- * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
++ * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+ #ifndef ATH12K_DP_RX_H
+ #define ATH12K_DP_RX_H
+@@ -79,6 +79,9 @@ static inline u32 ath12k_he_gi_to_nl80211_he_gi(u8 sgi)
+ case RX_MSDU_START_SGI_3_2_US:
+ ret = NL80211_RATE_INFO_HE_GI_3_2;
+ break;
++ default:
++ ret = NL80211_RATE_INFO_HE_GI_0_8;
++ break;
+ }
+
+ return ret;
+diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c
+index a39bfb959797a..7dc3576287850 100644
+--- a/drivers/net/wireless/ath/ath12k/dp_tx.c
++++ b/drivers/net/wireless/ath/ath12k/dp_tx.c
+@@ -8,6 +8,8 @@
+ #include "dp_tx.h"
+ #include "debug.h"
+ #include "hw.h"
++#include "peer.h"
++#include "mac.h"
+
+ static enum hal_tcl_encap_type
+ ath12k_dp_tx_get_encap_type(struct ath12k_link_vif *arvif, struct sk_buff *skb)
+@@ -582,6 +584,124 @@ ath12k_dp_tx_process_htt_tx_complete(struct ath12k_base *ab,
+ }
+ }
+
++static void ath12k_dp_tx_update_txcompl(struct ath12k *ar, struct hal_tx_status *ts)
++{
++ struct ath12k_base *ab = ar->ab;
++ struct ath12k_peer *peer;
++ struct ieee80211_sta *sta;
++ struct ath12k_sta *ahsta;
++ struct ath12k_link_sta *arsta;
++ struct rate_info txrate = {0};
++ u16 rate, ru_tones;
++ u8 rate_idx = 0;
++ int ret;
++
++ spin_lock_bh(&ab->base_lock);
++ peer = ath12k_peer_find_by_id(ab, ts->peer_id);
++ if (!peer || !peer->sta) {
++ ath12k_dbg(ab, ATH12K_DBG_DP_TX,
++ "failed to find the peer by id %u\n", ts->peer_id);
++ spin_unlock_bh(&ab->base_lock);
++ return;
++ }
++ sta = peer->sta;
++ ahsta = ath12k_sta_to_ahsta(sta);
++ arsta = &ahsta->deflink;
++
++ /* This is to prefer choose the real NSS value arsta->last_txrate.nss,
++ * if it is invalid, then choose the NSS value while assoc.
++ */
++ if (arsta->last_txrate.nss)
++ txrate.nss = arsta->last_txrate.nss;
++ else
++ txrate.nss = arsta->peer_nss;
++ spin_unlock_bh(&ab->base_lock);
++
++ switch (ts->pkt_type) {
++ case HAL_TX_RATE_STATS_PKT_TYPE_11A:
++ case HAL_TX_RATE_STATS_PKT_TYPE_11B:
++ ret = ath12k_mac_hw_ratecode_to_legacy_rate(ts->mcs,
++ ts->pkt_type,
++ &rate_idx,
++ &rate);
++ if (ret < 0) {
++ ath12k_warn(ab, "Invalid tx legacy rate %d\n", ret);
++ return;
++ }
++
++ txrate.legacy = rate;
++ break;
++ case HAL_TX_RATE_STATS_PKT_TYPE_11N:
++ if (ts->mcs > ATH12K_HT_MCS_MAX) {
++ ath12k_warn(ab, "Invalid HT mcs index %d\n", ts->mcs);
++ return;
++ }
++
++ if (txrate.nss != 0)
++ txrate.mcs = ts->mcs + 8 * (txrate.nss - 1);
++
++ txrate.flags = RATE_INFO_FLAGS_MCS;
++
++ if (ts->sgi)
++ txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
++ break;
++ case HAL_TX_RATE_STATS_PKT_TYPE_11AC:
++ if (ts->mcs > ATH12K_VHT_MCS_MAX) {
++ ath12k_warn(ab, "Invalid VHT mcs index %d\n", ts->mcs);
++ return;
++ }
++
++ txrate.mcs = ts->mcs;
++ txrate.flags = RATE_INFO_FLAGS_VHT_MCS;
++
++ if (ts->sgi)
++ txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
++ break;
++ case HAL_TX_RATE_STATS_PKT_TYPE_11AX:
++ if (ts->mcs > ATH12K_HE_MCS_MAX) {
++ ath12k_warn(ab, "Invalid HE mcs index %d\n", ts->mcs);
++ return;
++ }
++
++ txrate.mcs = ts->mcs;
++ txrate.flags = RATE_INFO_FLAGS_HE_MCS;
++ txrate.he_gi = ath12k_he_gi_to_nl80211_he_gi(ts->sgi);
++ break;
++ case HAL_TX_RATE_STATS_PKT_TYPE_11BE:
++ if (ts->mcs > ATH12K_EHT_MCS_MAX) {
++ ath12k_warn(ab, "Invalid EHT mcs index %d\n", ts->mcs);
++ return;
++ }
++
++ txrate.mcs = ts->mcs;
++ txrate.flags = RATE_INFO_FLAGS_EHT_MCS;
++ txrate.eht_gi = ath12k_mac_eht_gi_to_nl80211_eht_gi(ts->sgi);
++ break;
++ default:
++ ath12k_warn(ab, "Invalid tx pkt type: %d\n", ts->pkt_type);
++ return;
++ }
++
++ txrate.bw = ath12k_mac_bw_to_mac80211_bw(ts->bw);
++
++ if (ts->ofdma && ts->pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AX) {
++ txrate.bw = RATE_INFO_BW_HE_RU;
++ ru_tones = ath12k_mac_he_convert_tones_to_ru_tones(ts->tones);
++ txrate.he_ru_alloc =
++ ath12k_he_ru_tones_to_nl80211_he_ru_alloc(ru_tones);
++ }
++
++ if (ts->ofdma && ts->pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11BE) {
++ txrate.bw = RATE_INFO_BW_EHT_RU;
++ txrate.eht_ru_alloc =
++ ath12k_mac_eht_ru_tones_to_nl80211_eht_ru_alloc(ts->tones);
++ }
++
++ spin_lock_bh(&ab->base_lock);
++ arsta->txrate = txrate;
++ spin_unlock_bh(&ab->base_lock);
++}
++
+ static void ath12k_dp_tx_complete_msdu(struct ath12k *ar,
+ struct sk_buff *msdu,
+ struct hal_tx_status *ts)
+@@ -660,6 +780,8 @@ static void ath12k_dp_tx_complete_msdu(struct ath12k *ar,
+ * Might end up reporting it out-of-band from HTT stats.
+ */
+
++ ath12k_dp_tx_update_txcompl(ar, ts);
++
+ ieee80211_tx_status_skb(ath12k_ar_to_hw(ar), msdu);
+
+ exit:
+@@ -670,6 +792,8 @@ static void ath12k_dp_tx_status_parse(struct ath12k_base *ab,
+ struct hal_wbm_completion_ring_tx *desc,
+ struct hal_tx_status *ts)
+ {
++ u32 info0 = le32_to_cpu(desc->rate_stats.info0);
++
+ ts->buf_rel_source =
+ le32_get_bits(desc->info0, HAL_WBM_COMPL_TX_INFO0_REL_SRC_MODULE);
+ if (ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_FW &&
+@@ -684,10 +808,17 @@ static void ath12k_dp_tx_status_parse(struct ath12k_base *ab,
+
+ ts->ppdu_id = le32_get_bits(desc->info1,
+ HAL_WBM_COMPL_TX_INFO1_TQM_STATUS_NUMBER);
+- if (le32_to_cpu(desc->rate_stats.info0) & HAL_TX_RATE_STATS_INFO0_VALID)
+- ts->rate_stats = le32_to_cpu(desc->rate_stats.info0);
+- else
+- ts->rate_stats = 0;
++
++ ts->peer_id = le32_get_bits(desc->info3, HAL_WBM_COMPL_TX_INFO3_PEER_ID);
++
++ if (info0 & HAL_TX_RATE_STATS_INFO0_VALID) {
++ ts->pkt_type = u32_get_bits(info0, HAL_TX_RATE_STATS_INFO0_PKT_TYPE);
++ ts->mcs = u32_get_bits(info0, HAL_TX_RATE_STATS_INFO0_MCS);
++ ts->sgi = u32_get_bits(info0, HAL_TX_RATE_STATS_INFO0_SGI);
++ ts->bw = u32_get_bits(info0, HAL_TX_RATE_STATS_INFO0_BW);
++ ts->tones = u32_get_bits(info0, HAL_TX_RATE_STATS_INFO0_TONES_IN_RU);
++ ts->ofdma = u32_get_bits(info0, HAL_TX_RATE_STATS_INFO0_OFDMA_TX);
++ }
+ }
+
+ void ath12k_dp_tx_completion_handler(struct ath12k_base *ab, int ring_id)
+diff --git a/drivers/net/wireless/ath/ath12k/hal_rx.h b/drivers/net/wireless/ath/ath12k/hal_rx.h
+index 55b2dd5b76f6b..ac3b3f17ec2c8 100644
+--- a/drivers/net/wireless/ath/ath12k/hal_rx.h
++++ b/drivers/net/wireless/ath/ath12k/hal_rx.h
+@@ -1,7 +1,7 @@
+ /* SPDX-License-Identifier: BSD-3-Clause-Clear */
+ /*
+ * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
+- * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
++ * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+ #ifndef ATH12K_HAL_RX_H
+@@ -666,6 +666,9 @@ enum nl80211_he_ru_alloc ath12k_he_ru_tones_to_nl80211_he_ru_alloc(u16 ru_tones)
+ case RU_996:
+ ret = NL80211_RATE_INFO_HE_RU_ALLOC_996;
+ break;
++ case RU_2X996:
++ ret = NL80211_RATE_INFO_HE_RU_ALLOC_2x996;
++ break;
+ case RU_26:
+ fallthrough;
+ default:
+diff --git a/drivers/net/wireless/ath/ath12k/hal_tx.h b/drivers/net/wireless/ath/ath12k/hal_tx.h
+index 3cf5973771d78..eb065a79f6c64 100644
+--- a/drivers/net/wireless/ath/ath12k/hal_tx.h
++++ b/drivers/net/wireless/ath/ath12k/hal_tx.h
+@@ -1,7 +1,8 @@
+ /* SPDX-License-Identifier: BSD-3-Clause-Clear */
+ /*
+ * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
+- * Copyright (c) 2021-2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved.
++ * Copyright (c) 2021-2022, 2024-2025 Qualcomm Innovation Center, Inc.
++ * All rights reserved.
+ */
+
+ #ifndef ATH12K_HAL_TX_H
+@@ -63,7 +64,12 @@ struct hal_tx_status {
+ u8 try_cnt;
+ u8 tid;
+ u16 peer_id;
+- u32 rate_stats;
++ enum hal_tx_rate_stats_pkt_type pkt_type;
++ enum hal_tx_rate_stats_sgi sgi;
++ enum ath12k_supported_bw bw;
++ u8 mcs;
++ u16 tones;
++ u8 ofdma;
+ };
+
+ #define HAL_TX_PHY_DESC_INFO0_BF_TYPE GENMASK(17, 16)
+diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
+index 95ad9fefbdfcd..5f6d9896ef613 100644
+--- a/drivers/net/wireless/ath/ath12k/mac.c
++++ b/drivers/net/wireless/ath/ath12k/mac.c
+@@ -337,6 +337,82 @@ static const char *ath12k_mac_phymode_str(enum wmi_phy_mode mode)
+ return "<unknown>";
+ }
+
++u16 ath12k_mac_he_convert_tones_to_ru_tones(u16 tones)
++{
++ switch (tones) {
++ case 26:
++ return RU_26;
++ case 52:
++ return RU_52;
++ case 106:
++ return RU_106;
++ case 242:
++ return RU_242;
++ case 484:
++ return RU_484;
++ case 996:
++ return RU_996;
++ case (996 * 2):
++ return RU_2X996;
++ default:
++ return RU_26;
++ }
++}
++
++enum nl80211_eht_gi ath12k_mac_eht_gi_to_nl80211_eht_gi(u8 sgi)
++{
++ switch (sgi) {
++ case RX_MSDU_START_SGI_0_8_US:
++ return NL80211_RATE_INFO_EHT_GI_0_8;
++ case RX_MSDU_START_SGI_1_6_US:
++ return NL80211_RATE_INFO_EHT_GI_1_6;
++ case RX_MSDU_START_SGI_3_2_US:
++ return NL80211_RATE_INFO_EHT_GI_3_2;
++ default:
++ return NL80211_RATE_INFO_EHT_GI_0_8;
++ }
++}
++
++enum nl80211_eht_ru_alloc ath12k_mac_eht_ru_tones_to_nl80211_eht_ru_alloc(u16 ru_tones)
++{
++ switch (ru_tones) {
++ case 26:
++ return NL80211_RATE_INFO_EHT_RU_ALLOC_26;
++ case 52:
++ return NL80211_RATE_INFO_EHT_RU_ALLOC_52;
++ case (52 + 26):
++ return NL80211_RATE_INFO_EHT_RU_ALLOC_52P26;
++ case 106:
++ return NL80211_RATE_INFO_EHT_RU_ALLOC_106;
++ case (106 + 26):
++ return NL80211_RATE_INFO_EHT_RU_ALLOC_106P26;
++ case 242:
++ return NL80211_RATE_INFO_EHT_RU_ALLOC_242;
++ case 484:
++ return NL80211_RATE_INFO_EHT_RU_ALLOC_484;
++ case (484 + 242):
++ return NL80211_RATE_INFO_EHT_RU_ALLOC_484P242;
++ case 996:
++ return NL80211_RATE_INFO_EHT_RU_ALLOC_996;
++ case (996 + 484):
++ return NL80211_RATE_INFO_EHT_RU_ALLOC_996P484;
++ case (996 + 484 + 242):
++ return NL80211_RATE_INFO_EHT_RU_ALLOC_996P484P242;
++ case (2 * 996):
++ return NL80211_RATE_INFO_EHT_RU_ALLOC_2x996;
++ case (2 * 996 + 484):
++ return NL80211_RATE_INFO_EHT_RU_ALLOC_2x996P484;
++ case (3 * 996):
++ return NL80211_RATE_INFO_EHT_RU_ALLOC_3x996;
++ case (3 * 996 + 484):
++ return NL80211_RATE_INFO_EHT_RU_ALLOC_3x996P484;
++ case (4 * 996):
++ return NL80211_RATE_INFO_EHT_RU_ALLOC_4x996;
++ default:
++ return NL80211_RATE_INFO_EHT_RU_ALLOC_26;
++ }
++}
++
+ enum rate_info_bw
+ ath12k_mac_bw_to_mac80211_bw(enum ath12k_supported_bw bw)
+ {
+@@ -3116,6 +3192,7 @@ static void ath12k_peer_assoc_prepare(struct ath12k *ar,
+ ath12k_peer_assoc_h_smps(arsta, arg);
+ ath12k_peer_assoc_h_mlo(arsta, arg);
+
++ arsta->peer_nss = arg->peer_nss;
+ /* TODO: amsdu_disable req? */
+ }
+
+@@ -10042,6 +10119,8 @@ static void ath12k_mac_op_sta_statistics(struct ieee80211_hw *hw,
+ sinfo->txrate.he_gi = arsta->txrate.he_gi;
+ sinfo->txrate.he_dcm = arsta->txrate.he_dcm;
+ sinfo->txrate.he_ru_alloc = arsta->txrate.he_ru_alloc;
++ sinfo->txrate.eht_gi = arsta->txrate.eht_gi;
++ sinfo->txrate.eht_ru_alloc = arsta->txrate.eht_ru_alloc;
+ }
+ sinfo->txrate.flags = arsta->txrate.flags;
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
+diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h
+index 3594729b63974..1acaf3f68292c 100644
+--- a/drivers/net/wireless/ath/ath12k/mac.h
++++ b/drivers/net/wireless/ath/ath12k/mac.h
+@@ -1,7 +1,7 @@
+ /* SPDX-License-Identifier: BSD-3-Clause-Clear */
+ /*
+ * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
+- * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
++ * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+ #ifndef ATH12K_MAC_H
+@@ -108,5 +108,8 @@ int ath12k_mac_vdev_stop(struct ath12k_link_vif *arvif);
+ void ath12k_mac_get_any_chanctx_conf_iter(struct ieee80211_hw *hw,
+ struct ieee80211_chanctx_conf *conf,
+ void *data);
++u16 ath12k_mac_he_convert_tones_to_ru_tones(u16 tones);
++enum nl80211_eht_ru_alloc ath12k_mac_eht_ru_tones_to_nl80211_eht_ru_alloc(u16 ru_tones);
++enum nl80211_eht_gi ath12k_mac_eht_gi_to_nl80211_eht_gi(u8 sgi);
+
+ #endif
+diff --git a/drivers/net/wireless/ath/ath12k/rx_desc.h b/drivers/net/wireless/ath/ath12k/rx_desc.h
+index fc1eceb2d99bb..7367935ee68b3 100644
+--- a/drivers/net/wireless/ath/ath12k/rx_desc.h
++++ b/drivers/net/wireless/ath/ath12k/rx_desc.h
+@@ -1,7 +1,7 @@
+ /* SPDX-License-Identifier: BSD-3-Clause-Clear */
+ /*
+ * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
+- * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
++ * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+ #ifndef ATH12K_RX_DESC_H
+ #define ATH12K_RX_DESC_H
+@@ -1548,5 +1548,6 @@ struct hal_rx_desc {
+ #define RU_242 9
+ #define RU_484 18
+ #define RU_996 37
++#define RU_2X996 74
+
+ #endif /* ATH12K_RX_DESC_H */
+--
+2.39.5
+
--- /dev/null
+From 6f8d7ec1e8e6e2b55cc5cc3b40841e380dbd401f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Feb 2025 07:08:50 +0530
+Subject: wifi: ath12k: Update the peer id in PPDU end user stats TLV
+
+From: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
+
+[ Upstream commit 0cded0e413468183a3b2dd445ab3bdc4d4375967 ]
+
+Currently, peer id get reported in the PPDU end user TLV tag. But the
+monitor status handler is inherited from ath11k, but it was not updated
+to incorporate the changes made to ath12k 802.11be hardware architecture.
+Therefore, update the peer id from the PPDU end user TLV data to get latest
+peer id update, it helps to populate accurate peer information on the
+statistics data.
+
+Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1
+Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3
+
+Co-developed-by: P Praneesh <quic_ppranees@quicinc.com>
+Signed-off-by: P Praneesh <quic_ppranees@quicinc.com>
+Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
+Signed-off-by: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
+Link: https://patch.msgid.link/20250206013854.174765-6-quic_periyasa@quicinc.com
+Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ath/ath12k/dp_mon.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c
+index f23fee7055abc..8737dc8fea354 100644
+--- a/drivers/net/wireless/ath/ath12k/dp_mon.c
++++ b/drivers/net/wireless/ath/ath12k/dp_mon.c
+@@ -638,6 +638,9 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab,
+ ppdu_info->num_mpdu_fcs_err =
+ u32_get_bits(info[0],
+ HAL_RX_PPDU_END_USER_STATS_INFO0_MPDU_CNT_FCS_ERR);
++ ppdu_info->peer_id =
++ u32_get_bits(info[0], HAL_RX_PPDU_END_USER_STATS_INFO0_PEER_ID);
++
+ switch (ppdu_info->preamble_type) {
+ case HAL_RX_PREAMBLE_11N:
+ ppdu_info->ht_flags = 1;
+--
+2.39.5
+
--- /dev/null
+From 4052e2258bb75371a736c03b044eade3673006e1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Feb 2025 22:35:11 +0530
+Subject: wifi: ath12k: use arvif instead of link_conf in ath12k_mac_set_key()
+
+From: Aditya Kumar Singh <aditya.kumar.singh@oss.qualcomm.com>
+
+[ Upstream commit 00e4dc11695d48322780812b503314682659e98b ]
+
+Currently, in ath12k_mac_set_key(), if sta is not present, the address is
+retrieved from link_conf's bssid or addr member, depending on the interface
+type.
+
+When operating as an ML station and during shutdown, link_conf will not be
+available. This can result in the following error:
+
+ath12k_pci 0004:01:00.0: unable to access bss link conf in set key for vif AA:BB:CC:DD:EE:FF link 1
+
+The primary purpose of accessing link_conf is to obtain the address for
+finding the peer. However, since arvif is always valid in this call, it can
+be used instead.
+
+Add change to use arvif instead of link_conf.
+
+A subsequent change will expose this issue but since tear down will give
+error, this is included first.
+
+Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1
+Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00130-QCAHKSWPL_SILICONZ-1.97421.5 # Nicolas Escande
+
+Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
+Signed-off-by: Aditya Kumar Singh <aditya.kumar.singh@oss.qualcomm.com>
+Tested-by: Nicolas Escande <nico.escande@gmail.com>
+Link: https://patch.msgid.link/20250204-unlink_link_arvif_from_chanctx-v2-5-764fb5973c1a@oss.qualcomm.com
+Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ath/ath12k/mac.c | 14 +-------------
+ 1 file changed, 1 insertion(+), 13 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
+index 9123ffab55b52..95ad9fefbdfcd 100644
+--- a/drivers/net/wireless/ath/ath12k/mac.c
++++ b/drivers/net/wireless/ath/ath12k/mac.c
+@@ -4534,9 +4534,6 @@ static int ath12k_mac_set_key(struct ath12k *ar, enum set_key_cmd cmd,
+ struct ath12k_link_sta *arsta,
+ struct ieee80211_key_conf *key)
+ {
+- struct ath12k_vif *ahvif = arvif->ahvif;
+- struct ieee80211_vif *vif = ath12k_ahvif_to_vif(ahvif);
+- struct ieee80211_bss_conf *link_conf;
+ struct ieee80211_sta *sta = NULL;
+ struct ath12k_base *ab = ar->ab;
+ struct ath12k_peer *peer;
+@@ -4553,19 +4550,10 @@ static int ath12k_mac_set_key(struct ath12k *ar, enum set_key_cmd cmd,
+ if (test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ab->dev_flags))
+ return 1;
+
+- link_conf = ath12k_mac_get_link_bss_conf(arvif);
+- if (!link_conf) {
+- ath12k_warn(ab, "unable to access bss link conf in set key for vif %pM link %u\n",
+- vif->addr, arvif->link_id);
+- return -ENOLINK;
+- }
+-
+ if (sta)
+ peer_addr = arsta->addr;
+- else if (ahvif->vdev_type == WMI_VDEV_TYPE_STA)
+- peer_addr = link_conf->bssid;
+ else
+- peer_addr = link_conf->addr;
++ peer_addr = arvif->bssid;
+
+ key->hw_key_idx = key->keyidx;
+
+--
+2.39.5
+
--- /dev/null
+From c4a233db1593e40856ca3076724341a0857a6d9b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 5 Nov 2024 14:23:26 -0800
+Subject: wifi: ath9k: return by of_get_mac_address
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Rosen Penev <rosenp@gmail.com>
+
+[ Upstream commit dfffb317519f88534bb82797f055f0a2fd867e7b ]
+
+When using nvmem, ath9k could potentially be loaded before nvmem, which
+loads after mtd. This is an issue if DT contains an nvmem mac address.
+
+If nvmem is not ready in time for ath9k, -EPROBE_DEFER is returned. Pass
+it to _probe so that ath9k can properly grab a potentially present MAC
+address.
+
+Signed-off-by: Rosen Penev <rosenp@gmail.com>
+Acked-by: Toke Høiland-Jørgensen <toke@toke.dk>
+Link: https://patch.msgid.link/20241105222326.194417-1-rosenp@gmail.com
+Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ath/ath9k/init.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
+index f9e77c4624d99..01e0dffbf57ed 100644
+--- a/drivers/net/wireless/ath/ath9k/init.c
++++ b/drivers/net/wireless/ath/ath9k/init.c
+@@ -647,7 +647,9 @@ static int ath9k_of_init(struct ath_softc *sc)
+ ah->ah_flags |= AH_NO_EEP_SWAP;
+ }
+
+- of_get_mac_address(np, common->macaddr);
++ ret = of_get_mac_address(np, common->macaddr);
++ if (ret == -EPROBE_DEFER)
++ return ret;
+
+ return 0;
+ }
+--
+2.39.5
+
--- /dev/null
+From f55a70556ff3dd4b6d98c3d9dba9fc3fd28bdc2b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 8 Mar 2025 23:03:30 +0200
+Subject: wifi: cfg80211: allow IR in 20 MHz configurations
+
+From: Anjaneyulu <pagadala.yesu.anjaneyulu@intel.com>
+
+[ Upstream commit cf4bd1608882792d4742e27a819493312904a680 ]
+
+Some regulatory bodies doesn't allow IR (initiate radioation) on a
+specific subband, but allows it for channels with a bandwidth of 20 MHz.
+Add a channel flag that indicates that, and consider it in
+cfg80211_reg_check_beaconing.
+
+While on it, fix the kernel doc of enum nl80211_reg_rule_flags and
+change it to use BIT().
+
+Signed-off-by: Anjaneyulu <pagadala.yesu.anjaneyulu@intel.com>
+Co-developed-by: Somashekhar Puttagangaiah <somashekhar.puttagangaiah@intel.com>
+Signed-off-by: Somashekhar Puttagangaiah <somashekhar.puttagangaiah@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20250308225541.d3ab352a73ff.I8a8f79e1c9eb74936929463960ee2a324712fe51@changeid
+[fix typo]
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/cfg80211.h | 3 +++
+ include/uapi/linux/nl80211.h | 52 ++++++++++++++++++++----------------
+ net/wireless/chan.c | 8 +++++-
+ net/wireless/nl80211.c | 4 +++
+ net/wireless/reg.c | 4 ++-
+ 5 files changed, 46 insertions(+), 25 deletions(-)
+
+diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
+index c168b0e89b79d..b000f6a59a030 100644
+--- a/include/net/cfg80211.h
++++ b/include/net/cfg80211.h
+@@ -127,6 +127,8 @@ struct wiphy;
+ * even if it is otherwise disabled.
+ * @IEEE80211_CHAN_ALLOW_6GHZ_VLP_AP: Allow using this channel for AP operation
+ * with very low power (VLP), even if otherwise set to NO_IR.
++ * @IEEE80211_CHAN_ALLOW_20MHZ_ACTIVITY: Allow activity on a 20 MHz channel,
++ * even if otherwise set to NO_IR.
+ */
+ enum ieee80211_channel_flags {
+ IEEE80211_CHAN_DISABLED = BIT(0),
+@@ -155,6 +157,7 @@ enum ieee80211_channel_flags {
+ IEEE80211_CHAN_NO_6GHZ_AFC_CLIENT = BIT(23),
+ IEEE80211_CHAN_CAN_MONITOR = BIT(24),
+ IEEE80211_CHAN_ALLOW_6GHZ_VLP_AP = BIT(25),
++ IEEE80211_CHAN_ALLOW_20MHZ_ACTIVITY = BIT(26),
+ };
+
+ #define IEEE80211_CHAN_NO_HT40 \
+diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
+index f6c1b181c886d..ea30fa455a098 100644
+--- a/include/uapi/linux/nl80211.h
++++ b/include/uapi/linux/nl80211.h
+@@ -4327,6 +4327,8 @@ enum nl80211_wmm_rule {
+ * otherwise completely disabled.
+ * @NL80211_FREQUENCY_ATTR_ALLOW_6GHZ_VLP_AP: This channel can be used for a
+ * very low power (VLP) AP, despite being NO_IR.
++ * @NL80211_FREQUENCY_ATTR_ALLOW_20MHZ_ACTIVITY: This channel can be active in
++ * 20 MHz bandwidth, despite being NO_IR.
+ * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
+ * currently defined
+ * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
+@@ -4371,6 +4373,7 @@ enum nl80211_frequency_attr {
+ NL80211_FREQUENCY_ATTR_NO_6GHZ_AFC_CLIENT,
+ NL80211_FREQUENCY_ATTR_CAN_MONITOR,
+ NL80211_FREQUENCY_ATTR_ALLOW_6GHZ_VLP_AP,
++ NL80211_FREQUENCY_ATTR_ALLOW_20MHZ_ACTIVITY,
+
+ /* keep last */
+ __NL80211_FREQUENCY_ATTR_AFTER_LAST,
+@@ -4582,31 +4585,34 @@ enum nl80211_sched_scan_match_attr {
+ * @NL80211_RRF_NO_6GHZ_AFC_CLIENT: Client connection to AFC AP not allowed
+ * @NL80211_RRF_ALLOW_6GHZ_VLP_AP: Very low power (VLP) AP can be permitted
+ * despite NO_IR configuration.
++ * @NL80211_RRF_ALLOW_20MHZ_ACTIVITY: Allow activity in 20 MHz bandwidth,
++ * despite NO_IR configuration.
+ */
+ enum nl80211_reg_rule_flags {
+- NL80211_RRF_NO_OFDM = 1<<0,
+- NL80211_RRF_NO_CCK = 1<<1,
+- NL80211_RRF_NO_INDOOR = 1<<2,
+- NL80211_RRF_NO_OUTDOOR = 1<<3,
+- NL80211_RRF_DFS = 1<<4,
+- NL80211_RRF_PTP_ONLY = 1<<5,
+- NL80211_RRF_PTMP_ONLY = 1<<6,
+- NL80211_RRF_NO_IR = 1<<7,
+- __NL80211_RRF_NO_IBSS = 1<<8,
+- NL80211_RRF_AUTO_BW = 1<<11,
+- NL80211_RRF_IR_CONCURRENT = 1<<12,
+- NL80211_RRF_NO_HT40MINUS = 1<<13,
+- NL80211_RRF_NO_HT40PLUS = 1<<14,
+- NL80211_RRF_NO_80MHZ = 1<<15,
+- NL80211_RRF_NO_160MHZ = 1<<16,
+- NL80211_RRF_NO_HE = 1<<17,
+- NL80211_RRF_NO_320MHZ = 1<<18,
+- NL80211_RRF_NO_EHT = 1<<19,
+- NL80211_RRF_PSD = 1<<20,
+- NL80211_RRF_DFS_CONCURRENT = 1<<21,
+- NL80211_RRF_NO_6GHZ_VLP_CLIENT = 1<<22,
+- NL80211_RRF_NO_6GHZ_AFC_CLIENT = 1<<23,
+- NL80211_RRF_ALLOW_6GHZ_VLP_AP = 1<<24,
++ NL80211_RRF_NO_OFDM = 1 << 0,
++ NL80211_RRF_NO_CCK = 1 << 1,
++ NL80211_RRF_NO_INDOOR = 1 << 2,
++ NL80211_RRF_NO_OUTDOOR = 1 << 3,
++ NL80211_RRF_DFS = 1 << 4,
++ NL80211_RRF_PTP_ONLY = 1 << 5,
++ NL80211_RRF_PTMP_ONLY = 1 << 6,
++ NL80211_RRF_NO_IR = 1 << 7,
++ __NL80211_RRF_NO_IBSS = 1 << 8,
++ NL80211_RRF_AUTO_BW = 1 << 11,
++ NL80211_RRF_IR_CONCURRENT = 1 << 12,
++ NL80211_RRF_NO_HT40MINUS = 1 << 13,
++ NL80211_RRF_NO_HT40PLUS = 1 << 14,
++ NL80211_RRF_NO_80MHZ = 1 << 15,
++ NL80211_RRF_NO_160MHZ = 1 << 16,
++ NL80211_RRF_NO_HE = 1 << 17,
++ NL80211_RRF_NO_320MHZ = 1 << 18,
++ NL80211_RRF_NO_EHT = 1 << 19,
++ NL80211_RRF_PSD = 1 << 20,
++ NL80211_RRF_DFS_CONCURRENT = 1 << 21,
++ NL80211_RRF_NO_6GHZ_VLP_CLIENT = 1 << 22,
++ NL80211_RRF_NO_6GHZ_AFC_CLIENT = 1 << 23,
++ NL80211_RRF_ALLOW_6GHZ_VLP_AP = 1 << 24,
++ NL80211_RRF_ALLOW_20MHZ_ACTIVITY = 1 << 25,
+ };
+
+ #define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR
+diff --git a/net/wireless/chan.c b/net/wireless/chan.c
+index 9f918b77b40e2..4cdb74a3f38c6 100644
+--- a/net/wireless/chan.c
++++ b/net/wireless/chan.c
+@@ -6,7 +6,7 @@
+ *
+ * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2013-2014 Intel Mobile Communications GmbH
+- * Copyright 2018-2024 Intel Corporation
++ * Copyright 2018-2025 Intel Corporation
+ */
+
+ #include <linux/export.h>
+@@ -1497,6 +1497,12 @@ bool cfg80211_reg_check_beaconing(struct wiphy *wiphy,
+ if (cfg->reg_power == IEEE80211_REG_VLP_AP)
+ permitting_flags |= IEEE80211_CHAN_ALLOW_6GHZ_VLP_AP;
+
++ if ((cfg->iftype == NL80211_IFTYPE_P2P_GO ||
++ cfg->iftype == NL80211_IFTYPE_AP) &&
++ (chandef->width == NL80211_CHAN_WIDTH_20_NOHT ||
++ chandef->width == NL80211_CHAN_WIDTH_20))
++ permitting_flags |= IEEE80211_CHAN_ALLOW_20MHZ_ACTIVITY;
++
+ return _cfg80211_reg_can_beacon(wiphy, chandef, cfg->iftype,
+ check_no_ir ? IEEE80211_CHAN_NO_IR : 0,
+ permitting_flags);
+diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
+index b457fe78672b7..370b668678da0 100644
+--- a/net/wireless/nl80211.c
++++ b/net/wireless/nl80211.c
+@@ -1234,6 +1234,10 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, struct wiphy *wiphy,
+ if ((chan->flags & IEEE80211_CHAN_ALLOW_6GHZ_VLP_AP) &&
+ nla_put_flag(msg, NL80211_FREQUENCY_ATTR_ALLOW_6GHZ_VLP_AP))
+ goto nla_put_failure;
++ if ((chan->flags & IEEE80211_CHAN_ALLOW_20MHZ_ACTIVITY) &&
++ nla_put_flag(msg,
++ NL80211_FREQUENCY_ATTR_ALLOW_20MHZ_ACTIVITY))
++ goto nla_put_failure;
+ }
+
+ if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
+diff --git a/net/wireless/reg.c b/net/wireless/reg.c
+index 212e9561aae77..c1752b31734fa 100644
+--- a/net/wireless/reg.c
++++ b/net/wireless/reg.c
+@@ -5,7 +5,7 @@
+ * Copyright 2008-2011 Luis R. Rodriguez <mcgrof@qca.qualcomm.com>
+ * Copyright 2013-2014 Intel Mobile Communications GmbH
+ * Copyright 2017 Intel Deutschland GmbH
+- * Copyright (C) 2018 - 2024 Intel Corporation
++ * Copyright (C) 2018 - 2025 Intel Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+@@ -1603,6 +1603,8 @@ static u32 map_regdom_flags(u32 rd_flags)
+ channel_flags |= IEEE80211_CHAN_PSD;
+ if (rd_flags & NL80211_RRF_ALLOW_6GHZ_VLP_AP)
+ channel_flags |= IEEE80211_CHAN_ALLOW_6GHZ_VLP_AP;
++ if (rd_flags & NL80211_RRF_ALLOW_20MHZ_ACTIVITY)
++ channel_flags |= IEEE80211_CHAN_ALLOW_20MHZ_ACTIVITY;
+ return channel_flags;
+ }
+
+--
+2.39.5
+
--- /dev/null
+From 2b0883f069eb335a775aa7f4f0763d0c84974aeb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 8 Mar 2025 23:03:37 +0200
+Subject: wifi: cfg80211: Update the link address when a link is added
+
+From: Ilan Peer <ilan.peer@intel.com>
+
+[ Upstream commit e16caea70610ed4226034dfcdaa5c43b36ff9e0a ]
+
+When links are added, update the wireless device link addresses based
+on the information provided by the driver.
+
+Signed-off-by: Ilan Peer <ilan.peer@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20250308225541.d694a9125aba.I79b010ea9aab47893e4f22c266362fde30b7f9ac@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/cfg80211.h | 1 +
+ net/wireless/mlme.c | 4 ++++
+ 2 files changed, 5 insertions(+)
+
+diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
+index 363d7dd2255aa..c168b0e89b79d 100644
+--- a/include/net/cfg80211.h
++++ b/include/net/cfg80211.h
+@@ -9750,6 +9750,7 @@ struct cfg80211_mlo_reconf_done_data {
+ u16 added_links;
+ struct {
+ struct cfg80211_bss *bss;
++ u8 *addr;
+ } links[IEEE80211_MLD_MAX_NUM_LINKS];
+ };
+
+diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
+index e10f2b3b4b7f6..c1b71179601db 100644
+--- a/net/wireless/mlme.c
++++ b/net/wireless/mlme.c
+@@ -1361,6 +1361,10 @@ void cfg80211_mlo_reconf_add_done(struct net_device *dev,
+ if (data->added_links & BIT(link_id)) {
+ wdev->links[link_id].client.current_bss =
+ bss_from_pub(bss);
++
++ memcpy(wdev->links[link_id].addr,
++ data->links[link_id].addr,
++ ETH_ALEN);
+ } else {
+ cfg80211_unhold_bss(bss_from_pub(bss));
+ cfg80211_put_bss(wiphy, bss);
+--
+2.39.5
+
--- /dev/null
+From 5c6fd9d34ebdf09702b8aa2893e5b90e43a83f13 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 6 May 2025 21:42:59 +0200
+Subject: wifi: iwlwifi: add support for Killer on MTL
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+[ Upstream commit ebedf8b7f05b9c886d68d63025db8d1b12343157 ]
+
+For now, we need another entry for these devices, this
+will be changed completely for 6.16.
+
+Closes: https://bugzilla.kernel.org/show_bug.cgi?id=219926
+Link: https://patch.msgid.link/20250506214258.2efbdc9e9a82.I31915ec252bd1c74bd53b89a0e214e42a74b6f2e@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
+index d4c1bc20971fb..69cf46c79b4b3 100644
+--- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
++++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
+@@ -587,6 +587,8 @@ VISIBLE_IF_IWLWIFI_KUNIT const struct iwl_dev_info iwl_dev_info_table[] = {
+ IWL_DEV_INFO(0x7A70, 0x1692, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690i_name),
+ IWL_DEV_INFO(0x7AF0, 0x1691, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690s_name),
+ IWL_DEV_INFO(0x7AF0, 0x1692, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690i_name),
++ IWL_DEV_INFO(0x7F70, 0x1691, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690s_name),
++ IWL_DEV_INFO(0x7F70, 0x1692, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690i_name),
+
+ IWL_DEV_INFO(0x271C, 0x0214, iwl9260_2ac_cfg, iwl9260_1_name),
+ IWL_DEV_INFO(0x7E40, 0x1691, iwl_cfg_ma, iwl_ax411_killer_1690s_name),
+--
+2.39.5
+
--- /dev/null
+From ae088e428fdeeba11bd7621b6207e8f8eb869dcb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Feb 2025 14:55:35 +0200
+Subject: wifi: iwlwifi: don't warn during reprobe
+
+From: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+
+[ Upstream commit 696cca64308dc641d0bbe4aa2c09dd9752aa288d ]
+
+During reprobe, the sw state is being destroyd, and so is the
+connection. When the peer STA is being removed, the opmode sends a
+command to flush the TXQs of the STA and uses iwl_trans_wait_txq_empty.
+
+This one warns if the FW is not alive, but it really shouldn't if
+there is a FW error - and return silently instead, just like we do when
+sending a hcmd.
+
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Reviewed-by: Johannes Berg <johannes.berg@intel.com>
+Link: https://patch.msgid.link/20250205145347.76425b10e5a0.I3bf0de2eb090a8b94c4e36d93dd91df61fadb808@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/intel/iwlwifi/iwl-trans.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c
+index eb631080c4563..75571f8693ee3 100644
+--- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c
++++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c
+@@ -690,6 +690,9 @@ IWL_EXPORT_SYMBOL(iwl_trans_txq_enable_cfg);
+
+ int iwl_trans_wait_txq_empty(struct iwl_trans *trans, int queue)
+ {
++ if (unlikely(test_bit(STATUS_FW_ERROR, &trans->status)))
++ return -EIO;
++
+ if (WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE,
+ "bad state = %d\n", trans->state))
+ return -EIO;
+--
+2.39.5
+
--- /dev/null
+From afa59c570ed3157a9dc1526d4d2b194db67ea0aa Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 8 Mar 2025 23:19:23 +0200
+Subject: wifi: iwlwifi: don't warn when if there is a FW error
+
+From: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+
+[ Upstream commit c7f50d0433a016d43681592836a3d484817bfb34 ]
+
+iwl_trans_reclaim is warning if it is called when the FW is not alive.
+But if it is called when there is a pending restart, i.e. after a FW
+error, there is no need to warn, instead - return silently.
+
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20250308231427.ba3d90b22c25.I9332506af1997faefcf0bdb51d98d5e874051722@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/intel/iwlwifi/iwl-trans.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c
+index ced8261c725f8..eb631080c4563 100644
+--- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c
++++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c
+@@ -2,7 +2,7 @@
+ /*
+ * Copyright (C) 2015 Intel Mobile Communications GmbH
+ * Copyright (C) 2016-2017 Intel Deutschland GmbH
+- * Copyright (C) 2019-2021, 2023-2024 Intel Corporation
++ * Copyright (C) 2019-2021, 2023-2025 Intel Corporation
+ */
+ #include <linux/kernel.h>
+ #include <linux/bsearch.h>
+@@ -655,6 +655,9 @@ IWL_EXPORT_SYMBOL(iwl_trans_tx);
+ void iwl_trans_reclaim(struct iwl_trans *trans, int queue, int ssn,
+ struct sk_buff_head *skbs, bool is_flush)
+ {
++ if (unlikely(test_bit(STATUS_FW_ERROR, &trans->status)))
++ return;
++
+ if (WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE,
+ "bad state = %d\n", trans->state))
+ return;
+--
+2.39.5
+
--- /dev/null
+From f2c411e63725d361221b876394c1d865768a5a78 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 8 Mar 2025 23:19:18 +0200
+Subject: wifi: iwlwifi: fix debug actions order
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+[ Upstream commit eb29b4ffafb20281624dcd2cbb768d6f30edf600 ]
+
+The order of actions taken for debug was implemented incorrectly.
+Now we implemented the dump split and do the FW reset only in the
+middle of the dump (rather than the FW killing itself on error.)
+As a result, some of the actions taken when applying the config
+will now crash the device, so we need to fix the order.
+
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20250308231427.6de7fa8e63ed.I40632c48e2a67a8aca05def572a934b88ce7934b@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c
+index 08d990ba8a794..ce787326aa69d 100644
+--- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c
++++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c
+@@ -1,6 +1,6 @@
+ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+ /*
+- * Copyright (C) 2018-2024 Intel Corporation
++ * Copyright (C) 2018-2025 Intel Corporation
+ */
+ #include <linux/firmware.h>
+ #include "iwl-drv.h"
+@@ -1372,15 +1372,15 @@ void _iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt,
+ switch (tp_id) {
+ case IWL_FW_INI_TIME_POINT_EARLY:
+ iwl_dbg_tlv_init_cfg(fwrt);
+- iwl_dbg_tlv_apply_config(fwrt, conf_list);
+ iwl_dbg_tlv_update_drams(fwrt);
+ iwl_dbg_tlv_tp_trigger(fwrt, sync, trig_list, tp_data, NULL);
++ iwl_dbg_tlv_apply_config(fwrt, conf_list);
+ break;
+ case IWL_FW_INI_TIME_POINT_AFTER_ALIVE:
+ iwl_dbg_tlv_apply_buffers(fwrt);
+ iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list);
+- iwl_dbg_tlv_apply_config(fwrt, conf_list);
+ iwl_dbg_tlv_tp_trigger(fwrt, sync, trig_list, tp_data, NULL);
++ iwl_dbg_tlv_apply_config(fwrt, conf_list);
+ break;
+ case IWL_FW_INI_TIME_POINT_PERIODIC:
+ iwl_dbg_tlv_set_periodic_trigs(fwrt);
+@@ -1390,14 +1390,14 @@ void _iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt,
+ case IWL_FW_INI_TIME_POINT_MISSED_BEACONS:
+ case IWL_FW_INI_TIME_POINT_FW_DHC_NOTIFICATION:
+ iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list);
+- iwl_dbg_tlv_apply_config(fwrt, conf_list);
+ iwl_dbg_tlv_tp_trigger(fwrt, sync, trig_list, tp_data,
+ iwl_dbg_tlv_check_fw_pkt);
++ iwl_dbg_tlv_apply_config(fwrt, conf_list);
+ break;
+ default:
+ iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list);
+- iwl_dbg_tlv_apply_config(fwrt, conf_list);
+ iwl_dbg_tlv_tp_trigger(fwrt, sync, trig_list, tp_data, NULL);
++ iwl_dbg_tlv_apply_config(fwrt, conf_list);
+ break;
+ }
+ }
+--
+2.39.5
+
--- /dev/null
+From 12a6938497f0e178131889eaba16c7ddf51cc95a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 8 Mar 2025 23:19:13 +0200
+Subject: wifi: iwlwifi: fix the ECKV UEFI variable name
+
+From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+
+[ Upstream commit 3ea2970b0578011ab8402ad0cff39712255f63df ]
+
+This UEFI variable name was badly named. Fix its name and also use the
+right GUID to find it: we need to use the BT_WIFI (a.k.a. Common) GUID.
+
+Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20250308231426.78c998d0fa71.I2bc9d72c1dc2c4d7028f0265634a940c2fadbbb5@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 8 +++++---
+ drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 4 ++--
+ 2 files changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
+index 434eed4130b90..91bcff499311d 100644
+--- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
++++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
+@@ -1,6 +1,6 @@
+ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+ /*
+- * Copyright(c) 2021-2024 Intel Corporation
++ * Copyright(c) 2021-2025 Intel Corporation
+ */
+
+ #include "iwl-drv.h"
+@@ -678,8 +678,10 @@ int iwl_uefi_get_eckv(struct iwl_fw_runtime *fwrt, u32 *extl_clk)
+ struct uefi_cnv_var_eckv *data;
+ int ret = 0;
+
+- data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_ECKV_NAME,
+- "ECKV", sizeof(*data), NULL);
++ data = iwl_uefi_get_verified_variable_guid(fwrt->trans,
++ &IWL_EFI_WIFI_BT_GUID,
++ IWL_UEFI_ECKV_NAME,
++ "ECKV", sizeof(*data), NULL);
+ if (IS_ERR(data))
+ return -EINVAL;
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
+index 0c8943a8bd011..eb3c05417da37 100644
+--- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
++++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
+@@ -1,6 +1,6 @@
+ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+ /*
+- * Copyright(c) 2021-2024 Intel Corporation
++ * Copyright(c) 2021-2025 Intel Corporation
+ */
+ #ifndef __iwl_fw_uefi__
+ #define __iwl_fw_uefi__
+@@ -19,7 +19,7 @@
+ #define IWL_UEFI_WTAS_NAME L"UefiCnvWlanWTAS"
+ #define IWL_UEFI_SPLC_NAME L"UefiCnvWlanSPLC"
+ #define IWL_UEFI_WRDD_NAME L"UefiCnvWlanWRDD"
+-#define IWL_UEFI_ECKV_NAME L"UefiCnvWlanECKV"
++#define IWL_UEFI_ECKV_NAME L"UefiCnvCommonECKV"
+ #define IWL_UEFI_DSM_NAME L"UefiCnvWlanGeneralCfg"
+ #define IWL_UEFI_WBEM_NAME L"UefiCnvWlanWBEM"
+ #define IWL_UEFI_PUNCTURING_NAME L"UefiCnvWlanPuncturing"
+--
+2.39.5
+
--- /dev/null
+From f53c569e8446158d54a2a4f68efc4d29e3decb9b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 8 Mar 2025 23:19:17 +0200
+Subject: wifi: iwlwifi: mark Br device not integrated
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+[ Upstream commit 5f0ab2f35a43773a0dfe1297129a8dbff906b932 ]
+
+This is a discrete device, don't mark it as integrated.
+This also means we cannot set the LTR delay.
+
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20250308231427.9bb69393fcc9.I197129383e5441c8139cbb0e810ae0b71198a37c@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/intel/iwlwifi/cfg/dr.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/dr.c b/drivers/net/wireless/intel/iwlwifi/cfg/dr.c
+index ab7c0f8d54f42..d3542af0f625e 100644
+--- a/drivers/net/wireless/intel/iwlwifi/cfg/dr.c
++++ b/drivers/net/wireless/intel/iwlwifi/cfg/dr.c
+@@ -148,11 +148,9 @@ const struct iwl_cfg_trans_params iwl_br_trans_cfg = {
+ .mq_rx_supported = true,
+ .rf_id = true,
+ .gen2 = true,
+- .integrated = true,
+ .umac_prph_offset = 0x300000,
+ .xtal_latency = 12000,
+ .low_latency_xtal = true,
+- .ltr_delay = IWL_CFG_TRANS_LTR_DELAY_2500US,
+ };
+
+ const char iwl_br_name[] = "Intel(R) TBD Br device";
+--
+2.39.5
+
--- /dev/null
+From e5bae2b178c32aac5e48f71994adaa6c5379918e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 8 Mar 2025 23:19:25 +0200
+Subject: wifi: iwlwifi: mvm: fix setting the TK when associated
+
+From: Avraham Stern <avraham.stern@intel.com>
+
+[ Upstream commit 3ad61970ac9e164be1b09b46c01aa942e8966132 ]
+
+When running secured ranging and the initiator is associated with
+the responder, the TK was not set in the range request command.
+Fix it.
+
+Signed-off-by: Avraham Stern <avraham.stern@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20250308231427.603dc31579d9.Icd19d797e56483c08dd22c55b96fee481c4d2f3d@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c
+index b26141c30c61c..0a96c26e741b8 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c
++++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c
+@@ -773,7 +773,11 @@ iwl_mvm_ftm_set_secured_ranging(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+
+ target.bssid = bssid;
+ target.cipher = cipher;
++ target.tk = NULL;
+ ieee80211_iter_keys(mvm->hw, vif, iter, &target);
++
++ if (!WARN_ON(!target.tk))
++ memcpy(tk, target.tk, TK_11AZ_LEN);
+ } else {
+ memcpy(tk, entry->tk, sizeof(entry->tk));
+ }
+--
+2.39.5
+
--- /dev/null
+From 7a2d38a4c76d4c727339d2012b02024adf85515f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Feb 2025 14:55:46 +0200
+Subject: wifi: iwlwifi: use correct IMR dump variable
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+[ Upstream commit 21e4d29ac0def546d57bacebe4a51cbed1209b03 ]
+
+We shouldn't dump the reg_data here which dumps the last
+entry again, it should use the imr_reg_data.
+
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20250205145347.3313b18667d1.Iaa9ab66b1d397912a573525e060d39ea01b29d19@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c
+index 6594216f873c4..cd284767ff4ba 100644
+--- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c
++++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c
+@@ -1,6 +1,6 @@
+ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+ /*
+- * Copyright (C) 2005-2014, 2018-2024 Intel Corporation
++ * Copyright (C) 2005-2014, 2018-2025 Intel Corporation
+ * Copyright (C) 2013-2015 Intel Mobile Communications GmbH
+ * Copyright (C) 2015-2017 Intel Deutschland GmbH
+ */
+@@ -2691,7 +2691,7 @@ static u32 iwl_dump_ini_trigger(struct iwl_fw_runtime *fwrt,
+ }
+ /* collect DRAM_IMR region in the last */
+ if (imr_reg_data.reg_tlv)
+- size += iwl_dump_ini_mem(fwrt, list, ®_data,
++ size += iwl_dump_ini_mem(fwrt, list, &imr_reg_data,
+ &iwl_dump_ini_region_ops[IWL_FW_INI_REGION_DRAM_IMR]);
+
+ if (size) {
+--
+2.39.5
+
--- /dev/null
+From 3a276fdab3978a150a29db725d062bfac0b0324d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 8 Mar 2025 23:19:19 +0200
+Subject: wifi: iwlwifi: w/a FW SMPS mode selection
+
+From: Daniel Gabay <daniel.gabay@intel.com>
+
+[ Upstream commit b2e709805ce955f80803b7cab3421813c79e1df4 ]
+
+The FW is now responsible of determining the SMPS mode.
+If the user disabled power save in a certain vif, we send the vif-level
+power command to clear out the POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK bit
+for that vif.
+But erroneously, the FW checks DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK in
+the device-level command to determine the SMPS mode.
+
+To W/A this, send also the device-level command when the power save of a
+vif changes, and disable power save if there is any vif that has power
+save disabled.
+
+Signed-off-by: Daniel Gabay <daniel.gabay@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20250308231427.7bf205efa027.I2c793ff1fc2a6779a95faaee1ded348100fd97f1@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 15 +++++++++++++++
+ .../net/wireless/intel/iwlwifi/mvm/mld-mac80211.c | 3 ++-
+ drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 3 +++
+ 3 files changed, 20 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+index af6644b7e95fb..e17ad647da48c 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
++++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+@@ -4099,6 +4099,20 @@ iwl_mvm_sta_state_authorized_to_assoc(struct iwl_mvm *mvm,
+ return 0;
+ }
+
++void iwl_mvm_smps_workaround(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
++ bool update)
++{
++ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
++
++ if (!iwl_mvm_has_rlc_offload(mvm))
++ return;
++
++ mvmvif->ps_disabled = !vif->cfg.ps;
++
++ if (update)
++ iwl_mvm_power_update_mac(mvm);
++}
++
+ /* Common part for MLD and non-MLD modes */
+ int iwl_mvm_mac_sta_state_common(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+@@ -4191,6 +4205,7 @@ int iwl_mvm_mac_sta_state_common(struct ieee80211_hw *hw,
+ new_state == IEEE80211_STA_AUTHORIZED) {
+ ret = iwl_mvm_sta_state_assoc_to_authorized(mvm, vif, sta,
+ callbacks);
++ iwl_mvm_smps_workaround(mvm, vif, true);
+ } else if (old_state == IEEE80211_STA_AUTHORIZED &&
+ new_state == IEEE80211_STA_ASSOC) {
+ ret = iwl_mvm_sta_state_authorized_to_assoc(mvm, vif, sta,
+diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
+index 341a2a7a49ec9..78d7153a0cfca 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
++++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
+@@ -1,6 +1,6 @@
+ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+ /*
+- * Copyright (C) 2022-2024 Intel Corporation
++ * Copyright (C) 2022-2025 Intel Corporation
+ */
+ #include "mvm.h"
+
+@@ -887,6 +887,7 @@ static void iwl_mvm_mld_vif_cfg_changed_station(struct iwl_mvm *mvm,
+ }
+
+ if (changes & BSS_CHANGED_PS) {
++ iwl_mvm_smps_workaround(mvm, vif, false);
+ ret = iwl_mvm_power_update_mac(mvm);
+ if (ret)
+ IWL_ERR(mvm, "failed to update power mode\n");
+diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+index ee769da72e68c..211f542ec8557 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
++++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+@@ -3043,4 +3043,7 @@ iwl_mvm_send_ap_tx_power_constraint_cmd(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *bss_conf,
+ bool is_ap);
++
++void iwl_mvm_smps_workaround(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
++ bool update);
+ #endif /* __IWL_MVM_H__ */
+--
+2.39.5
+
--- /dev/null
+From 93769ff11c58cbe95a841d753c54c80992ef3803 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 20 Feb 2025 10:41:39 +0100
+Subject: wifi: mac80211: Add counter for all monitor interfaces
+
+From: Alexander Wetzel <Alexander@wetzel-home.de>
+
+[ Upstream commit 129860044c611008be37f49d04cf41874e3659e6 ]
+
+Count open monitor interfaces regardless of the monitor interface type.
+The new counter virt_monitors takes over counting interfaces depending
+on the virtual monitor interface while monitors is used for all active
+monitor interfaces.
+
+This fixes monitor packet mirroring when using MONITOR_FLAG_ACTIVE or
+NO_VIRTUAL_MONITOR interfaces.
+
+Fixes: 286e69677065 ("wifi: mac80211: Drop cooked monitor support")
+Reported-by: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
+Closes: https://lore.kernel.org/r/cc715114-4e3b-619a-49dc-a4878075e1dc@quicinc.com
+Signed-off-by: Alexander Wetzel <Alexander@wetzel-home.de>
+Tested-by: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
+Link: https://patch.msgid.link/20250220094139.61459-1-Alexander@wetzel-home.de
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/mac80211/cfg.c | 5 ++---
+ net/mac80211/ethtool.c | 2 +-
+ net/mac80211/ieee80211_i.h | 2 +-
+ net/mac80211/iface.c | 22 +++++++++++++---------
+ net/mac80211/util.c | 3 ++-
+ 5 files changed, 19 insertions(+), 15 deletions(-)
+
+diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
+index 1ec246133d244..a7aeb37254bbf 100644
+--- a/net/mac80211/cfg.c
++++ b/net/mac80211/cfg.c
+@@ -4370,9 +4370,8 @@ static int ieee80211_cfg_get_channel(struct wiphy *wiphy,
+ if (chanctx_conf) {
+ *chandef = link->conf->chanreq.oper;
+ ret = 0;
+- } else if (!ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR) &&
+- local->open_count > 0 &&
+- local->open_count == local->monitors &&
++ } else if (local->open_count > 0 &&
++ local->open_count == local->virt_monitors &&
+ sdata->vif.type == NL80211_IFTYPE_MONITOR) {
+ *chandef = local->monitor_chanreq.oper;
+ ret = 0;
+diff --git a/net/mac80211/ethtool.c b/net/mac80211/ethtool.c
+index 42f7ee142ce3f..0397755a3bd1c 100644
+--- a/net/mac80211/ethtool.c
++++ b/net/mac80211/ethtool.c
+@@ -158,7 +158,7 @@ static void ieee80211_get_stats(struct net_device *dev,
+ if (chanctx_conf)
+ channel = chanctx_conf->def.chan;
+ else if (local->open_count > 0 &&
+- local->open_count == local->monitors &&
++ local->open_count == local->virt_monitors &&
+ sdata->vif.type == NL80211_IFTYPE_MONITOR)
+ channel = local->monitor_chanreq.oper.chan;
+ else
+diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
+index afc6fda6b606b..3d7304ce23e23 100644
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -1378,7 +1378,7 @@ struct ieee80211_local {
+ spinlock_t queue_stop_reason_lock;
+
+ int open_count;
+- int monitors, tx_mntrs;
++ int monitors, virt_monitors, tx_mntrs;
+ /* number of interfaces with corresponding FIF_ flags */
+ int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll,
+ fif_probe_req;
+diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
+index 5616c0adbe093..768d774d7d1f9 100644
+--- a/net/mac80211/iface.c
++++ b/net/mac80211/iface.c
+@@ -582,11 +582,13 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
+ /* no need to tell driver */
+ break;
+ case NL80211_IFTYPE_MONITOR:
++ local->monitors--;
++
+ if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) &&
+ !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
+
+- local->monitors--;
+- if (local->monitors == 0) {
++ local->virt_monitors--;
++ if (local->virt_monitors == 0) {
+ local->hw.conf.flags &= ~IEEE80211_CONF_MONITOR;
+ hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
+ }
+@@ -686,7 +688,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
+ case NL80211_IFTYPE_AP_VLAN:
+ break;
+ case NL80211_IFTYPE_MONITOR:
+- if (local->monitors == 0)
++ if (local->virt_monitors == 0)
+ ieee80211_del_virtual_monitor(local);
+
+ ieee80211_recalc_idle(local);
+@@ -723,7 +725,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
+ ieee80211_configure_filter(local);
+ ieee80211_hw_config(local, hw_reconf_flags);
+
+- if (local->monitors == local->open_count)
++ if (local->virt_monitors == local->open_count)
+ ieee80211_add_virtual_monitor(local);
+ }
+
+@@ -982,7 +984,7 @@ static bool ieee80211_set_sdata_offload_flags(struct ieee80211_sub_if_data *sdat
+ local->hw.wiphy->frag_threshold != (u32)-1)
+ flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
+
+- if (local->monitors)
++ if (local->virt_monitors)
+ flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
+ } else {
+ flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
+@@ -992,7 +994,7 @@ static bool ieee80211_set_sdata_offload_flags(struct ieee80211_sub_if_data *sdat
+ ieee80211_iftype_supports_hdr_offload(sdata->vif.type)) {
+ flags |= IEEE80211_OFFLOAD_DECAP_ENABLED;
+
+- if (local->monitors &&
++ if (local->virt_monitors &&
+ !ieee80211_hw_check(&local->hw, SUPPORTS_CONC_MON_RX_DECAP))
+ flags &= ~IEEE80211_OFFLOAD_DECAP_ENABLED;
+ } else {
+@@ -1336,20 +1338,22 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
+ if (res)
+ goto err_stop;
+ } else {
+- if (local->monitors == 0 && local->open_count == 0) {
++ if (local->virt_monitors == 0 && local->open_count == 0) {
+ res = ieee80211_add_virtual_monitor(local);
+ if (res)
+ goto err_stop;
+ }
+- local->monitors++;
++ local->virt_monitors++;
+
+ /* must be before the call to ieee80211_configure_filter */
+- if (local->monitors == 1) {
++ if (local->virt_monitors == 1) {
+ local->hw.conf.flags |= IEEE80211_CONF_MONITOR;
+ hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
+ }
+ }
+
++ local->monitors++;
++
+ ieee80211_adjust_monitor_flags(sdata, 1);
+ ieee80211_configure_filter(local);
+ ieee80211_recalc_offload(local);
+diff --git a/net/mac80211/util.c b/net/mac80211/util.c
+index fdda14c08e2b1..dec6e16b8c7d2 100644
+--- a/net/mac80211/util.c
++++ b/net/mac80211/util.c
+@@ -2156,7 +2156,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
+
+ wake_up:
+
+- if (local->monitors == local->open_count && local->monitors > 0)
++ if (local->virt_monitors > 0 &&
++ local->virt_monitors == local->open_count)
+ ieee80211_add_virtual_monitor(local);
+
+ /*
+--
+2.39.5
+
--- /dev/null
+From 8a4cec99816cdc03febb90e205ffafaf6c2802b5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Feb 2025 11:39:18 +0200
+Subject: wifi: mac80211: add HT and VHT basic set verification
+
+From: Benjamin Berg <benjamin.berg@intel.com>
+
+[ Upstream commit 574faa0e936d12718e2cadad11ce1e184d9e5a32 ]
+
+So far we did not verify the HT and VHT basic MCS set. However, in
+P802.11REVme/D7.0 (6.5.4.2.4) says that the MLME-JOIN.request shall
+return an error if the VHT and HT basic set requirements are not met.
+
+Given broken APs, apply VHT basic MCS/NSS set checks only in
+strict mode.
+
+Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
+Reviewed-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20250205110958.e2d8d4095f6b.I66bcf6c2de3b9d3325e4ffd9f573f4cd26ce5685@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/mac80211/mlme.c | 129 ++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 129 insertions(+)
+
+diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
+index 8235400b7e5d8..ef65ae5137dcd 100644
+--- a/net/mac80211/mlme.c
++++ b/net/mac80211/mlme.c
+@@ -345,6 +345,115 @@ ieee80211_determine_ap_chan(struct ieee80211_sub_if_data *sdata,
+ return IEEE80211_CONN_MODE_EHT;
+ }
+
++static bool
++ieee80211_verify_sta_ht_mcs_support(struct ieee80211_sub_if_data *sdata,
++ struct ieee80211_supported_band *sband,
++ const struct ieee80211_ht_operation *ht_op)
++{
++ struct ieee80211_sta_ht_cap sta_ht_cap;
++ int i;
++
++ if (sband->band == NL80211_BAND_6GHZ)
++ return true;
++
++ if (!ht_op)
++ return false;
++
++ memcpy(&sta_ht_cap, &sband->ht_cap, sizeof(sta_ht_cap));
++ ieee80211_apply_htcap_overrides(sdata, &sta_ht_cap);
++
++ /*
++ * P802.11REVme/D7.0 - 6.5.4.2.4
++ * ...
++ * If the MLME of an HT STA receives an MLME-JOIN.request primitive
++ * with the SelectedBSS parameter containing a Basic HT-MCS Set field
++ * in the HT Operation parameter that contains any unsupported MCSs,
++ * the MLME response in the resulting MLME-JOIN.confirm primitive shall
++ * contain a ResultCode parameter that is not set to the value SUCCESS.
++ * ...
++ */
++
++ /* Simply check that all basic rates are in the STA RX mask */
++ for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
++ if ((ht_op->basic_set[i] & sta_ht_cap.mcs.rx_mask[i]) !=
++ ht_op->basic_set[i])
++ return false;
++ }
++
++ return true;
++}
++
++static bool
++ieee80211_verify_sta_vht_mcs_support(struct ieee80211_sub_if_data *sdata,
++ int link_id,
++ struct ieee80211_supported_band *sband,
++ const struct ieee80211_vht_operation *vht_op)
++{
++ struct ieee80211_sta_vht_cap sta_vht_cap;
++ u16 ap_min_req_set, sta_rx_mcs_map, sta_tx_mcs_map;
++ int nss;
++
++ if (sband->band != NL80211_BAND_5GHZ)
++ return true;
++
++ if (!vht_op)
++ return false;
++
++ memcpy(&sta_vht_cap, &sband->vht_cap, sizeof(sta_vht_cap));
++ ieee80211_apply_vhtcap_overrides(sdata, &sta_vht_cap);
++
++ ap_min_req_set = le16_to_cpu(vht_op->basic_mcs_set);
++ sta_rx_mcs_map = le16_to_cpu(sta_vht_cap.vht_mcs.rx_mcs_map);
++ sta_tx_mcs_map = le16_to_cpu(sta_vht_cap.vht_mcs.tx_mcs_map);
++
++ /*
++ * Many APs are incorrectly advertising an all-zero value here,
++ * which really means MCS 0-7 are required for 1-8 streams, but
++ * they don't really mean it that way.
++ * Some other APs are incorrectly advertising 3 spatial streams
++ * with MCS 0-7 are required, but don't really mean it that way
++ * and we'll connect only with HT, rather than even HE.
++ * As a result, unfortunately the VHT basic MCS/NSS set cannot
++ * be used at all, so check it only in strict mode.
++ */
++ if (!ieee80211_hw_check(&sdata->local->hw, STRICT))
++ return true;
++
++ /*
++ * P802.11REVme/D7.0 - 6.5.4.2.4
++ * ...
++ * If the MLME of a VHT STA receives an MLME-JOIN.request primitive
++ * with a SelectedBSS parameter containing a Basic VHT-MCS And NSS Set
++ * field in the VHT Operation parameter that contains any unsupported
++ * <VHT-MCS, NSS> tuple, the MLME response in the resulting
++ * MLME-JOIN.confirm primitive shall contain a ResultCode parameter
++ * that is not set to the value SUCCESS.
++ * ...
++ */
++ for (nss = 8; nss > 0; nss--) {
++ u8 ap_op_val = (ap_min_req_set >> (2 * (nss - 1))) & 3;
++ u8 sta_rx_val;
++ u8 sta_tx_val;
++
++ if (ap_op_val == IEEE80211_HE_MCS_NOT_SUPPORTED)
++ continue;
++
++ sta_rx_val = (sta_rx_mcs_map >> (2 * (nss - 1))) & 3;
++ sta_tx_val = (sta_tx_mcs_map >> (2 * (nss - 1))) & 3;
++
++ if (sta_rx_val == IEEE80211_HE_MCS_NOT_SUPPORTED ||
++ sta_tx_val == IEEE80211_HE_MCS_NOT_SUPPORTED ||
++ sta_rx_val < ap_op_val || sta_tx_val < ap_op_val) {
++ link_id_info(sdata, link_id,
++ "Missing mandatory rates for %d Nss, rx %d, tx %d oper %d, disable VHT\n",
++ nss, sta_rx_val, sta_tx_val, ap_op_val);
++ return false;
++ }
++ }
++
++ return true;
++}
++
+ static bool
+ ieee80211_verify_peer_he_mcs_support(struct ieee80211_sub_if_data *sdata,
+ int link_id,
+@@ -1042,6 +1151,26 @@ ieee80211_determine_chan_mode(struct ieee80211_sub_if_data *sdata,
+ link_id_info(sdata, link_id,
+ "regulatory prevented using AP config, downgraded\n");
+
++ if (conn->mode >= IEEE80211_CONN_MODE_HT &&
++ !ieee80211_verify_sta_ht_mcs_support(sdata, sband,
++ elems->ht_operation)) {
++ conn->mode = IEEE80211_CONN_MODE_LEGACY;
++ conn->bw_limit = IEEE80211_CONN_BW_LIMIT_20;
++ link_id_info(sdata, link_id,
++ "required MCSes not supported, disabling HT\n");
++ }
++
++ if (conn->mode >= IEEE80211_CONN_MODE_VHT &&
++ !ieee80211_verify_sta_vht_mcs_support(sdata, link_id, sband,
++ elems->vht_operation)) {
++ conn->mode = IEEE80211_CONN_MODE_HT;
++ conn->bw_limit = min_t(enum ieee80211_conn_bw_limit,
++ conn->bw_limit,
++ IEEE80211_CONN_BW_LIMIT_40);
++ link_id_info(sdata, link_id,
++ "required MCSes not supported, disabling VHT\n");
++ }
++
+ if (conn->mode >= IEEE80211_CONN_MODE_HE &&
+ (!ieee80211_verify_peer_he_mcs_support(sdata, link_id,
+ (void *)elems->he_cap,
+--
+2.39.5
+
--- /dev/null
+From 4e4c413916479a35a1fb290e2bb772d7ce1a5786 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Feb 2025 11:39:23 +0200
+Subject: wifi: mac80211: always send max agg subframe num in strict mode
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+[ Upstream commit 3fca951123b68df8d1b47bbf90409f8a3671362b ]
+
+Instead of only sending the correct number for EHT and up,
+always send the correct number as it should be in strict
+mode.
+
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20250205110958.5910263db6da.Icd1f93fabc9705e4e760d834095c29b60b934d9e@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/mac80211/agg-tx.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
+index 61f2cac37728c..92120f9051499 100644
+--- a/net/mac80211/agg-tx.c
++++ b/net/mac80211/agg-tx.c
+@@ -9,7 +9,7 @@
+ * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2007-2010, Intel Corporation
+ * Copyright(c) 2015-2017 Intel Deutschland GmbH
+- * Copyright (C) 2018 - 2023 Intel Corporation
++ * Copyright (C) 2018 - 2024 Intel Corporation
+ */
+
+ #include <linux/ieee80211.h>
+@@ -464,7 +464,8 @@ static void ieee80211_send_addba_with_timeout(struct sta_info *sta,
+ sta->ampdu_mlme.addba_req_num[tid]++;
+ spin_unlock_bh(&sta->lock);
+
+- if (sta->sta.deflink.eht_cap.has_eht) {
++ if (sta->sta.deflink.eht_cap.has_eht ||
++ ieee80211_hw_check(&local->hw, STRICT)) {
+ buf_size = local->hw.max_tx_aggregation_subframes;
+ } else if (sta->sta.deflink.he_cap.has_he) {
+ buf_size = min_t(u16, local->hw.max_tx_aggregation_subframes,
+--
+2.39.5
+
--- /dev/null
+From 82c431c4e231c2dcc3760184e663561873bcea22 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 8 Mar 2025 23:03:40 +0200
+Subject: wifi: mac80211: don't include MLE in ML reconf per-STA profile
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+[ Upstream commit c3171bed65ec323803b6b73f74017f7d0fd7aa6c ]
+
+In the multi-link reconfiguration frame, the per-STA profile for
+added links shouldn't include the multi-link element. Set the
+association ID to an invalid value, so it doesn't erroneously
+match the link ID if that happens to be zero.
+
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Reviewed-by: Ilan Peer <ilan.peer@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20250308225541.8e5be244c70f.I3472cd5c347814ee3600869a88488997bcd43224@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/mac80211/ieee80211_i.h | 2 +-
+ net/mac80211/mlme.c | 2 ++
+ 2 files changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
+index e7dc3f0cfc9a9..8f5f7797f0b6b 100644
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -462,7 +462,7 @@ struct ieee80211_mgd_assoc_data {
+ bool s1g;
+ bool spp_amsdu;
+
+- unsigned int assoc_link_id;
++ s8 assoc_link_id;
+
+ u8 fils_nonces[2 * FILS_NONCE_LEN];
+ u8 fils_kek[FILS_MAX_KEK_LEN];
+diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
+index e3deb89674b23..676274519cdfb 100644
+--- a/net/mac80211/mlme.c
++++ b/net/mac80211/mlme.c
+@@ -10156,6 +10156,8 @@ int ieee80211_mgd_assoc_ml_reconf(struct ieee80211_sub_if_data *sdata,
+ if (!data)
+ return -ENOMEM;
+
++ data->assoc_link_id = -1;
++
+ uapsd_supported = true;
+ ieee80211_ml_reconf_selectors(userspace_selectors);
+ for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS;
+--
+2.39.5
+
--- /dev/null
+From c087d84d0774ec665c223aa3d6b9120a8fea0e87 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Feb 2025 11:39:22 +0200
+Subject: wifi: mac80211: don't unconditionally call drv_mgd_complete_tx()
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+[ Upstream commit 1798271b3604b902d45033ec569f2bf77e94ecc2 ]
+
+We might not have called drv_mgd_prepare_tx(), so only call
+drv_mgd_complete_tx() under the same conditions.
+
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20250205110958.e091fc39a351.Ie6a3cdca070612a0aa4b3c6914ab9ed602d1f456@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/mac80211/mlme.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
+index f92cbbc32a9e5..3bd1c4eeae52f 100644
+--- a/net/mac80211/mlme.c
++++ b/net/mac80211/mlme.c
+@@ -3832,7 +3832,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
+ if (tx)
+ ieee80211_flush_queues(local, sdata, false);
+
+- drv_mgd_complete_tx(sdata->local, sdata, &info);
++ if (tx || frame_buf)
++ drv_mgd_complete_tx(sdata->local, sdata, &info);
+
+ /* clear AP addr only after building the needed mgmt frames */
+ eth_zero_addr(sdata->deflink.u.mgd.bssid);
+--
+2.39.5
+
--- /dev/null
+From eb337a626244cb506ec2095837f3ebb0803321d2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Feb 2025 12:13:52 +0100
+Subject: wifi: mac80211: Drop cooked monitor support
+
+From: Alexander Wetzel <Alexander@wetzel-home.de>
+
+[ Upstream commit 286e696770654d79b34bd15953e7101a1c4784c7 ]
+
+Hostapd switched from cooked monitor interfaces to nl80211 Dec 2011.
+Drop support for the outdated cooked monitor interfaces and fix
+creating the virtual monitor interfaces in the following cases:
+
+ 1) We have one non-monitor and one monitor interface with
+ %MONITOR_FLAG_ACTIVE enabled and then delete the non-monitor
+ interface.
+
+ 2) We only have monitor interfaces enabled on resume while at least one
+ has %MONITOR_FLAG_ACTIVE set.
+
+Signed-off-by: Alexander Wetzel <Alexander@wetzel-home.de>
+Link: https://patch.msgid.link/20250204111352.7004-2-Alexander@wetzel-home.de
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/dropreason.h | 6 --
+ net/mac80211/cfg.c | 9 +-
+ net/mac80211/drop.h | 21 ++--
+ net/mac80211/ieee80211_i.h | 11 +--
+ net/mac80211/iface.c | 50 ++++------
+ net/mac80211/main.c | 16 +--
+ net/mac80211/rx.c | 194 ++++++++++---------------------------
+ net/mac80211/status.c | 34 +------
+ net/mac80211/tx.c | 2 +-
+ 9 files changed, 94 insertions(+), 249 deletions(-)
+
+diff --git a/include/net/dropreason.h b/include/net/dropreason.h
+index 56cb7be92244c..7d3b1a2a6feca 100644
+--- a/include/net/dropreason.h
++++ b/include/net/dropreason.h
+@@ -17,12 +17,6 @@ enum skb_drop_reason_subsys {
+ */
+ SKB_DROP_REASON_SUBSYS_MAC80211_UNUSABLE,
+
+- /**
+- * @SKB_DROP_REASON_SUBSYS_MAC80211_MONITOR: mac80211 drop reasons
+- * for frames still going to monitor, see net/mac80211/drop.h
+- */
+- SKB_DROP_REASON_SUBSYS_MAC80211_MONITOR,
+-
+ /**
+ * @SKB_DROP_REASON_SUBSYS_OPENVSWITCH: openvswitch drop reasons,
+ * see net/openvswitch/drop.h
+diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
+index b766472703b12..1ec246133d244 100644
+--- a/net/mac80211/cfg.c
++++ b/net/mac80211/cfg.c
+@@ -89,15 +89,14 @@ static int ieee80211_set_mon_options(struct ieee80211_sub_if_data *sdata,
+
+ /* check flags first */
+ if (params->flags && ieee80211_sdata_running(sdata)) {
+- u32 mask = MONITOR_FLAG_COOK_FRAMES | MONITOR_FLAG_ACTIVE;
++ u32 mask = MONITOR_FLAG_ACTIVE;
+
+ /*
+- * Prohibit MONITOR_FLAG_COOK_FRAMES and
+- * MONITOR_FLAG_ACTIVE to be changed while the
+- * interface is up.
++ * Prohibit MONITOR_FLAG_ACTIVE to be changed
++ * while the interface is up.
+ * Else we would need to add a lot of cruft
+ * to update everything:
+- * cooked_mntrs, monitor and all fif_* counters
++ * monitor and all fif_* counters
+ * reconfigure hardware
+ */
+ if ((params->flags & mask) != (sdata->u.mntr.flags & mask))
+diff --git a/net/mac80211/drop.h b/net/mac80211/drop.h
+index 59e3ec4dc9607..eb9ab310f91ca 100644
+--- a/net/mac80211/drop.h
++++ b/net/mac80211/drop.h
+@@ -11,12 +11,6 @@
+
+ typedef unsigned int __bitwise ieee80211_rx_result;
+
+-#define MAC80211_DROP_REASONS_MONITOR(R) \
+- R(RX_DROP_M_UNEXPECTED_4ADDR_FRAME) \
+- R(RX_DROP_M_BAD_BCN_KEYIDX) \
+- R(RX_DROP_M_BAD_MGMT_KEYIDX) \
+-/* this line for the trailing \ - add before this */
+-
+ #define MAC80211_DROP_REASONS_UNUSABLE(R) \
+ /* 0x00 == ___RX_DROP_UNUSABLE */ \
+ R(RX_DROP_U_MIC_FAIL) \
+@@ -66,6 +60,10 @@ typedef unsigned int __bitwise ieee80211_rx_result;
+ R(RX_DROP_U_UNEXPECTED_STA_4ADDR) \
+ R(RX_DROP_U_UNEXPECTED_VLAN_MCAST) \
+ R(RX_DROP_U_NOT_PORT_CONTROL) \
++ R(RX_DROP_U_UNEXPECTED_4ADDR_FRAME) \
++ R(RX_DROP_U_BAD_BCN_KEYIDX) \
++ /* 0x30 */ \
++ R(RX_DROP_U_BAD_MGMT_KEYIDX) \
+ R(RX_DROP_U_UNKNOWN_ACTION_REJECTED) \
+ /* this line for the trailing \ - add before this */
+
+@@ -78,10 +76,6 @@ enum ___mac80211_drop_reason {
+ ___RX_QUEUED = SKB_NOT_DROPPED_YET,
+
+ #define ENUM(x) ___ ## x,
+- ___RX_DROP_MONITOR = SKB_DROP_REASON_SUBSYS_MAC80211_MONITOR <<
+- SKB_DROP_REASON_SUBSYS_SHIFT,
+- MAC80211_DROP_REASONS_MONITOR(ENUM)
+-
+ ___RX_DROP_UNUSABLE = SKB_DROP_REASON_SUBSYS_MAC80211_UNUSABLE <<
+ SKB_DROP_REASON_SUBSYS_SHIFT,
+ MAC80211_DROP_REASONS_UNUSABLE(ENUM)
+@@ -89,11 +83,10 @@ enum ___mac80211_drop_reason {
+ };
+
+ enum mac80211_drop_reason {
+- RX_CONTINUE = (__force ieee80211_rx_result)___RX_CONTINUE,
+- RX_QUEUED = (__force ieee80211_rx_result)___RX_QUEUED,
+- RX_DROP_MONITOR = (__force ieee80211_rx_result)___RX_DROP_MONITOR,
++ RX_CONTINUE = (__force ieee80211_rx_result)___RX_CONTINUE,
++ RX_QUEUED = (__force ieee80211_rx_result)___RX_QUEUED,
++ RX_DROP = (__force ieee80211_rx_result)___RX_DROP_UNUSABLE,
+ #define DEF(x) x = (__force ieee80211_rx_result)___ ## x,
+- MAC80211_DROP_REASONS_MONITOR(DEF)
+ MAC80211_DROP_REASONS_UNUSABLE(DEF)
+ #undef DEF
+ };
+diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
+index 8f5f7797f0b6b..afc6fda6b606b 100644
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -200,7 +200,6 @@ enum ieee80211_packet_rx_flags {
+ /**
+ * enum ieee80211_rx_flags - RX data flags
+ *
+- * @IEEE80211_RX_CMNTR: received on cooked monitor already
+ * @IEEE80211_RX_BEACON_REPORTED: This frame was already reported
+ * to cfg80211_report_obss_beacon().
+ *
+@@ -208,8 +207,7 @@ enum ieee80211_packet_rx_flags {
+ * for a single frame.
+ */
+ enum ieee80211_rx_flags {
+- IEEE80211_RX_CMNTR = BIT(0),
+- IEEE80211_RX_BEACON_REPORTED = BIT(1),
++ IEEE80211_RX_BEACON_REPORTED = BIT(0),
+ };
+
+ struct ieee80211_rx_data {
+@@ -1380,7 +1378,7 @@ struct ieee80211_local {
+ spinlock_t queue_stop_reason_lock;
+
+ int open_count;
+- int monitors, cooked_mntrs, tx_mntrs;
++ int monitors, tx_mntrs;
+ /* number of interfaces with corresponding FIF_ flags */
+ int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll,
+ fif_probe_req;
+@@ -1492,7 +1490,7 @@ struct ieee80211_local {
+
+ /* see iface.c */
+ struct list_head interfaces;
+- struct list_head mon_list; /* only that are IFF_UP && !cooked */
++ struct list_head mon_list; /* only that are IFF_UP */
+ struct mutex iflist_mtx;
+
+ /* Scanning and BSS list */
+@@ -2090,8 +2088,7 @@ struct sk_buff *
+ ieee80211_build_data_template(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb, u32 info_flags);
+ void ieee80211_tx_monitor(struct ieee80211_local *local, struct sk_buff *skb,
+- int retry_count, bool send_to_cooked,
+- struct ieee80211_tx_status *status);
++ int retry_count, struct ieee80211_tx_status *status);
+
+ void ieee80211_check_fast_xmit(struct sta_info *sta);
+ void ieee80211_check_fast_xmit_all(struct ieee80211_local *local);
+diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
+index d299bdbca6b3b..5616c0adbe093 100644
+--- a/net/mac80211/iface.c
++++ b/net/mac80211/iface.c
+@@ -483,8 +483,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
+ ieee80211_ibss_stop(sdata);
+ break;
+ case NL80211_IFTYPE_MONITOR:
+- if (sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES)
+- break;
+ list_del_rcu(&sdata->u.mntr.list);
+ break;
+ default:
+@@ -584,18 +582,17 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
+ /* no need to tell driver */
+ break;
+ case NL80211_IFTYPE_MONITOR:
+- if (sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES) {
+- local->cooked_mntrs--;
+- break;
+- }
++ if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) &&
++ !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
+
+- local->monitors--;
+- if (local->monitors == 0) {
+- local->hw.conf.flags &= ~IEEE80211_CONF_MONITOR;
+- hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
+- }
++ local->monitors--;
++ if (local->monitors == 0) {
++ local->hw.conf.flags &= ~IEEE80211_CONF_MONITOR;
++ hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
++ }
+
+- ieee80211_adjust_monitor_flags(sdata, -1);
++ ieee80211_adjust_monitor_flags(sdata, -1);
++ }
+ break;
+ case NL80211_IFTYPE_NAN:
+ /* clean all the functions */
+@@ -1333,27 +1330,24 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
+ }
+ break;
+ case NL80211_IFTYPE_MONITOR:
+- if (sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES) {
+- local->cooked_mntrs++;
+- break;
+- }
+-
+ if ((sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) ||
+ ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
+ res = drv_add_interface(local, sdata);
+ if (res)
+ goto err_stop;
+- } else if (local->monitors == 0 && local->open_count == 0) {
+- res = ieee80211_add_virtual_monitor(local);
+- if (res)
+- goto err_stop;
+- }
++ } else {
++ if (local->monitors == 0 && local->open_count == 0) {
++ res = ieee80211_add_virtual_monitor(local);
++ if (res)
++ goto err_stop;
++ }
++ local->monitors++;
+
+- /* must be before the call to ieee80211_configure_filter */
+- local->monitors++;
+- if (local->monitors == 1) {
+- local->hw.conf.flags |= IEEE80211_CONF_MONITOR;
+- hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
++ /* must be before the call to ieee80211_configure_filter */
++ if (local->monitors == 1) {
++ local->hw.conf.flags |= IEEE80211_CONF_MONITOR;
++ hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
++ }
+ }
+
+ ieee80211_adjust_monitor_flags(sdata, 1);
+@@ -1430,8 +1424,6 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
+ rcu_assign_pointer(local->p2p_sdata, sdata);
+ break;
+ case NL80211_IFTYPE_MONITOR:
+- if (sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES)
+- break;
+ list_add_tail_rcu(&sdata->u.mntr.list, &local->mon_list);
+ break;
+ default:
+diff --git a/net/mac80211/main.c b/net/mac80211/main.c
+index 2b6249d75a5d4..6b6de43d9420a 100644
+--- a/net/mac80211/main.c
++++ b/net/mac80211/main.c
+@@ -1746,18 +1746,7 @@ void ieee80211_free_hw(struct ieee80211_hw *hw)
+ wiphy_free(local->hw.wiphy);
+ }
+ EXPORT_SYMBOL(ieee80211_free_hw);
+-
+-static const char * const drop_reasons_monitor[] = {
+-#define V(x) #x,
+- [0] = "RX_DROP_MONITOR",
+- MAC80211_DROP_REASONS_MONITOR(V)
+-};
+-
+-static struct drop_reason_list drop_reason_list_monitor = {
+- .reasons = drop_reasons_monitor,
+- .n_reasons = ARRAY_SIZE(drop_reasons_monitor),
+-};
+-
++#define V(x) #x,
+ static const char * const drop_reasons_unusable[] = {
+ [0] = "RX_DROP_UNUSABLE",
+ MAC80211_DROP_REASONS_UNUSABLE(V)
+@@ -1786,8 +1775,6 @@ static int __init ieee80211_init(void)
+ if (ret)
+ goto err_netdev;
+
+- drop_reasons_register_subsys(SKB_DROP_REASON_SUBSYS_MAC80211_MONITOR,
+- &drop_reason_list_monitor);
+ drop_reasons_register_subsys(SKB_DROP_REASON_SUBSYS_MAC80211_UNUSABLE,
+ &drop_reason_list_unusable);
+
+@@ -1806,7 +1793,6 @@ static void __exit ieee80211_exit(void)
+
+ ieee80211_iface_exit();
+
+- drop_reasons_unregister_subsys(SKB_DROP_REASON_SUBSYS_MAC80211_MONITOR);
+ drop_reasons_unregister_subsys(SKB_DROP_REASON_SUBSYS_MAC80211_UNUSABLE);
+
+ rcu_barrier();
+diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
+index 0659ec892ec6c..ad019a50b6b33 100644
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -1045,14 +1045,14 @@ static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
+ if (is_multicast_ether_addr(hdr->addr1)) {
+ if (ieee80211_has_tods(hdr->frame_control) ||
+ !ieee80211_has_fromds(hdr->frame_control))
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+ if (ether_addr_equal(hdr->addr3, dev_addr))
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+ } else {
+ if (!ieee80211_has_a4(hdr->frame_control))
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+ if (ether_addr_equal(hdr->addr4, dev_addr))
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+ }
+ }
+
+@@ -1064,20 +1064,20 @@ static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
+ struct ieee80211_mgmt *mgmt;
+
+ if (!ieee80211_is_mgmt(hdr->frame_control))
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+
+ if (ieee80211_is_action(hdr->frame_control)) {
+ u8 category;
+
+ /* make sure category field is present */
+ if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE)
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+
+ mgmt = (struct ieee80211_mgmt *)hdr;
+ category = mgmt->u.action.category;
+ if (category != WLAN_CATEGORY_MESH_ACTION &&
+ category != WLAN_CATEGORY_SELF_PROTECTED)
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+ return RX_CONTINUE;
+ }
+
+@@ -1087,7 +1087,7 @@ static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
+ ieee80211_is_auth(hdr->frame_control))
+ return RX_CONTINUE;
+
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+ }
+
+ return RX_CONTINUE;
+@@ -1513,7 +1513,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
+ hdrlen = ieee80211_hdrlen(hdr->frame_control);
+
+ if (rx->skb->len < hdrlen + 8)
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+
+ skb_copy_bits(rx->skb, hdrlen + 6, ðertype, 2);
+ if (ethertype == rx->sdata->control_port_protocol)
+@@ -1526,7 +1526,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
+ GFP_ATOMIC))
+ return RX_DROP_U_SPURIOUS;
+
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+ }
+
+ return RX_CONTINUE;
+@@ -1862,7 +1862,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
+ cfg80211_rx_unexpected_4addr_frame(
+ rx->sdata->dev, sta->sta.addr,
+ GFP_ATOMIC);
+- return RX_DROP_M_UNEXPECTED_4ADDR_FRAME;
++ return RX_DROP_U_UNEXPECTED_4ADDR_FRAME;
+ }
+ /*
+ * Update counter and free packet here to avoid
+@@ -1997,7 +1997,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
+ cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
+ skb->data,
+ skb->len);
+- return RX_DROP_M_BAD_BCN_KEYIDX;
++ return RX_DROP_U_BAD_BCN_KEYIDX;
+ }
+
+ rx->key = ieee80211_rx_get_bigtk(rx, mmie_keyidx);
+@@ -2011,11 +2011,11 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
+
+ if (mmie_keyidx < NUM_DEFAULT_KEYS ||
+ mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)
+- return RX_DROP_M_BAD_MGMT_KEYIDX; /* unexpected BIP keyidx */
++ return RX_DROP_U_BAD_MGMT_KEYIDX; /* unexpected BIP keyidx */
+ if (rx->link_sta) {
+ if (ieee80211_is_group_privacy_action(skb) &&
+ test_sta_flag(rx->sta, WLAN_STA_MFP))
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+
+ rx->key = rcu_dereference(rx->link_sta->gtk[mmie_keyidx]);
+ }
+@@ -2100,11 +2100,11 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
+
+ if (rx->key) {
+ if (unlikely(rx->key->flags & KEY_FLAG_TAINTED))
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+
+ /* TODO: add threshold stuff again */
+ } else {
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+ }
+
+ switch (rx->key->conf.cipher) {
+@@ -2278,7 +2278,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
+ goto out;
+
+ if (is_multicast_ether_addr(hdr->addr1))
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+
+ I802_DEBUG_INC(rx->local->rx_handlers_fragments);
+
+@@ -2333,7 +2333,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
+ rx->seqno_idx, hdr);
+ if (!entry) {
+ I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+ }
+
+ /* "The receiver shall discard MSDUs and MMPDUs whose constituent
+@@ -2855,25 +2855,25 @@ ieee80211_rx_mesh_data(struct ieee80211_sub_if_data *sdata, struct sta_info *sta
+ return RX_CONTINUE;
+
+ if (!pskb_may_pull(skb, sizeof(*eth) + 6))
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+
+ mesh_hdr = (struct ieee80211s_hdr *)(skb->data + sizeof(*eth));
+ mesh_hdrlen = ieee80211_get_mesh_hdrlen(mesh_hdr);
+
+ if (!pskb_may_pull(skb, sizeof(*eth) + mesh_hdrlen))
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+
+ eth = (struct ethhdr *)skb->data;
+ multicast = is_multicast_ether_addr(eth->h_dest);
+
+ mesh_hdr = (struct ieee80211s_hdr *)(eth + 1);
+ if (!mesh_hdr->ttl)
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+
+ /* frame is in RMC, don't forward */
+ if (is_multicast_ether_addr(eth->h_dest) &&
+ mesh_rmc_check(sdata, eth->h_source, mesh_hdr))
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+
+ /* forward packet */
+ if (sdata->crypto_tx_tailroom_needed_cnt)
+@@ -2890,7 +2890,7 @@ ieee80211_rx_mesh_data(struct ieee80211_sub_if_data *sdata, struct sta_info *sta
+ /* has_a4 already checked in ieee80211_rx_mesh_check */
+ proxied_addr = mesh_hdr->eaddr2;
+ else
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+
+ rcu_read_lock();
+ mppath = mpp_path_lookup(sdata, proxied_addr);
+@@ -2922,14 +2922,14 @@ ieee80211_rx_mesh_data(struct ieee80211_sub_if_data *sdata, struct sta_info *sta
+ goto rx_accept;
+
+ IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_ttl);
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+ }
+
+ if (!ifmsh->mshcfg.dot11MeshForwarding) {
+ if (is_multicast_ether_addr(eth->h_dest))
+ goto rx_accept;
+
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+ }
+
+ skb_set_queue_mapping(skb, ieee802_1d_to_ac[skb->priority]);
+@@ -3122,7 +3122,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
+ return RX_CONTINUE;
+
+ if (unlikely(!ieee80211_is_data_present(fc)))
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+
+ if (unlikely(ieee80211_has_a4(hdr->frame_control))) {
+ switch (rx->sdata->vif.type) {
+@@ -3179,19 +3179,16 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
+ return RX_CONTINUE;
+
+ if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+
+- /*
+- * Send unexpected-4addr-frame event to hostapd. For older versions,
+- * also drop the frame to cooked monitor interfaces.
+- */
++ /* Send unexpected-4addr-frame event to hostapd */
+ if (ieee80211_has_a4(hdr->frame_control) &&
+ sdata->vif.type == NL80211_IFTYPE_AP) {
+ if (rx->sta &&
+ !test_and_set_sta_flag(rx->sta, WLAN_STA_4ADDR_EVENT))
+ cfg80211_rx_unexpected_4addr_frame(
+ rx->sdata->dev, rx->sta->sta.addr, GFP_ATOMIC);
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+ }
+
+ res = __ieee80211_data_to_8023(rx, &port_control);
+@@ -3203,7 +3200,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
+ return res;
+
+ if (!ieee80211_frame_allowed(rx, fc))
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+
+ /* directly handle TDLS channel switch requests/responses */
+ if (unlikely(((struct ethhdr *)rx->skb->data)->h_proto ==
+@@ -3268,11 +3265,11 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
+ };
+
+ if (!rx->sta)
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+
+ if (skb_copy_bits(skb, offsetof(struct ieee80211_bar, control),
+ &bar_data, sizeof(bar_data)))
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+
+ tid = le16_to_cpu(bar_data.control) >> 12;
+
+@@ -3284,7 +3281,7 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
+
+ tid_agg_rx = rcu_dereference(rx->sta->ampdu_mlme.tid_rx[tid]);
+ if (!tid_agg_rx)
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+
+ start_seq_num = le16_to_cpu(bar_data.start_seq_num) >> 4;
+ event.u.ba.tid = tid;
+@@ -3308,12 +3305,7 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
+ return RX_QUEUED;
+ }
+
+- /*
+- * After this point, we only want management frames,
+- * so we can drop all remaining control frames to
+- * cooked monitor interfaces.
+- */
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+ }
+
+ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,
+@@ -3422,10 +3414,10 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
+ * and unknown (reserved) frames are useless.
+ */
+ if (rx->skb->len < 24)
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+
+ if (!ieee80211_is_mgmt(mgmt->frame_control))
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+
+ /* drop too small action frames */
+ if (ieee80211_is_action(mgmt->frame_control) &&
+@@ -3951,17 +3943,16 @@ ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx)
+ * ones. For all other modes we will return them to the sender,
+ * setting the 0x80 bit in the action category, as required by
+ * 802.11-2012 9.24.4.
+- * Newer versions of hostapd shall also use the management frame
+- * registration mechanisms, but older ones still use cooked
+- * monitor interfaces so push all frames there.
++ * Newer versions of hostapd use the management frame registration
++ * mechanisms and old cooked monitor interface is no longer supported.
+ */
+ if (!(status->rx_flags & IEEE80211_RX_MALFORMED_ACTION_FRM) &&
+ (sdata->vif.type == NL80211_IFTYPE_AP ||
+ sdata->vif.type == NL80211_IFTYPE_AP_VLAN))
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+
+ if (is_multicast_ether_addr(mgmt->da))
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+
+ /* do not return rejected action frames */
+ if (mgmt->u.action.category & 0x80)
+@@ -4006,7 +3997,7 @@ ieee80211_rx_h_ext(struct ieee80211_rx_data *rx)
+ return RX_CONTINUE;
+
+ if (sdata->vif.type != NL80211_IFTYPE_STATION)
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+
+ /* for now only beacons are ext, so queue them */
+ ieee80211_queue_skb_to_iface(sdata, rx->link_id, rx->sta, rx->skb);
+@@ -4027,7 +4018,7 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
+ sdata->vif.type != NL80211_IFTYPE_ADHOC &&
+ sdata->vif.type != NL80211_IFTYPE_OCB &&
+ sdata->vif.type != NL80211_IFTYPE_STATION)
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+
+ switch (stype) {
+ case cpu_to_le16(IEEE80211_STYPE_AUTH):
+@@ -4038,32 +4029,32 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
+ case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
+ if (is_multicast_ether_addr(mgmt->da) &&
+ !is_broadcast_ether_addr(mgmt->da))
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+
+ /* process only for station/IBSS */
+ if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+ sdata->vif.type != NL80211_IFTYPE_ADHOC)
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP):
+ case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP):
+ case cpu_to_le16(IEEE80211_STYPE_DISASSOC):
+ if (is_multicast_ether_addr(mgmt->da) &&
+ !is_broadcast_ether_addr(mgmt->da))
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+
+ /* process only for station */
+ if (sdata->vif.type != NL80211_IFTYPE_STATION)
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ):
+ /* process only for ibss and mesh */
+ if (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
+ sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+ break;
+ default:
+- return RX_DROP_MONITOR;
++ return RX_DROP;
+ }
+
+ ieee80211_queue_skb_to_iface(sdata, rx->link_id, rx->sta, rx->skb);
+@@ -4071,82 +4062,9 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
+ return RX_QUEUED;
+ }
+
+-static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
+- struct ieee80211_rate *rate,
+- ieee80211_rx_result reason)
+-{
+- struct ieee80211_sub_if_data *sdata;
+- struct ieee80211_local *local = rx->local;
+- struct sk_buff *skb = rx->skb, *skb2;
+- struct net_device *prev_dev = NULL;
+- struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+- int needed_headroom;
+-
+- /*
+- * If cooked monitor has been processed already, then
+- * don't do it again. If not, set the flag.
+- */
+- if (rx->flags & IEEE80211_RX_CMNTR)
+- goto out_free_skb;
+- rx->flags |= IEEE80211_RX_CMNTR;
+-
+- /* If there are no cooked monitor interfaces, just free the SKB */
+- if (!local->cooked_mntrs)
+- goto out_free_skb;
+-
+- /* room for the radiotap header based on driver features */
+- needed_headroom = ieee80211_rx_radiotap_hdrlen(local, status, skb);
+-
+- if (skb_headroom(skb) < needed_headroom &&
+- pskb_expand_head(skb, needed_headroom, 0, GFP_ATOMIC))
+- goto out_free_skb;
+-
+- /* prepend radiotap information */
+- ieee80211_add_rx_radiotap_header(local, skb, rate, needed_headroom,
+- false);
+-
+- skb_reset_mac_header(skb);
+- skb->ip_summed = CHECKSUM_UNNECESSARY;
+- skb->pkt_type = PACKET_OTHERHOST;
+- skb->protocol = htons(ETH_P_802_2);
+-
+- list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+- if (!ieee80211_sdata_running(sdata))
+- continue;
+-
+- if (sdata->vif.type != NL80211_IFTYPE_MONITOR ||
+- !(sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES))
+- continue;
+-
+- if (prev_dev) {
+- skb2 = skb_clone(skb, GFP_ATOMIC);
+- if (skb2) {
+- skb2->dev = prev_dev;
+- netif_receive_skb(skb2);
+- }
+- }
+-
+- prev_dev = sdata->dev;
+- dev_sw_netstats_rx_add(sdata->dev, skb->len);
+- }
+-
+- if (prev_dev) {
+- skb->dev = prev_dev;
+- netif_receive_skb(skb);
+- return;
+- }
+-
+- out_free_skb:
+- kfree_skb_reason(skb, (__force u32)reason);
+-}
+-
+ static void ieee80211_rx_handlers_result(struct ieee80211_rx_data *rx,
+ ieee80211_rx_result res)
+ {
+- struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
+- struct ieee80211_supported_band *sband;
+- struct ieee80211_rate *rate = NULL;
+-
+ if (res == RX_QUEUED) {
+ I802_DEBUG_INC(rx->sdata->local->rx_handlers_queued);
+ return;
+@@ -4158,23 +4076,13 @@ static void ieee80211_rx_handlers_result(struct ieee80211_rx_data *rx,
+ rx->link_sta->rx_stats.dropped++;
+ }
+
+- if (u32_get_bits((__force u32)res, SKB_DROP_REASON_SUBSYS_MASK) ==
+- SKB_DROP_REASON_SUBSYS_MAC80211_UNUSABLE) {
+- kfree_skb_reason(rx->skb, (__force u32)res);
+- return;
+- }
+-
+- sband = rx->local->hw.wiphy->bands[status->band];
+- if (status->encoding == RX_ENC_LEGACY)
+- rate = &sband->bitrates[status->rate_idx];
+-
+- ieee80211_rx_cooked_monitor(rx, rate, res);
++ kfree_skb_reason(rx->skb, (__force u32)res);
+ }
+
+ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx,
+ struct sk_buff_head *frames)
+ {
+- ieee80211_rx_result res = RX_DROP_MONITOR;
++ ieee80211_rx_result res = RX_DROP;
+ struct sk_buff *skb;
+
+ #define CALL_RXH(rxh) \
+@@ -4238,7 +4146,7 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx,
+ static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx)
+ {
+ struct sk_buff_head reorder_release;
+- ieee80211_rx_result res = RX_DROP_MONITOR;
++ ieee80211_rx_result res = RX_DROP;
+
+ __skb_queue_head_init(&reorder_release);
+
+diff --git a/net/mac80211/status.c b/net/mac80211/status.c
+index 5f28f3633fa0a..b17b3cc7fb903 100644
+--- a/net/mac80211/status.c
++++ b/net/mac80211/status.c
+@@ -895,8 +895,7 @@ static int ieee80211_tx_get_rates(struct ieee80211_hw *hw,
+ }
+
+ void ieee80211_tx_monitor(struct ieee80211_local *local, struct sk_buff *skb,
+- int retry_count, bool send_to_cooked,
+- struct ieee80211_tx_status *status)
++ int retry_count, struct ieee80211_tx_status *status)
+ {
+ struct sk_buff *skb2;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+@@ -930,10 +929,6 @@ void ieee80211_tx_monitor(struct ieee80211_local *local, struct sk_buff *skb,
+ if (sdata->u.mntr.flags & MONITOR_FLAG_SKIP_TX)
+ continue;
+
+- if ((sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES) &&
+- !send_to_cooked)
+- continue;
+-
+ if (prev_dev) {
+ skb2 = skb_clone(skb, GFP_ATOMIC);
+ if (skb2) {
+@@ -964,7 +959,6 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw,
+ struct ieee80211_tx_info *info = status->info;
+ struct sta_info *sta;
+ __le16 fc;
+- bool send_to_cooked;
+ bool acked;
+ bool noack_success;
+ struct ieee80211_bar *bar;
+@@ -1091,28 +1085,10 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw,
+
+ ieee80211_report_used_skb(local, skb, false, status->ack_hwtstamp);
+
+- /* this was a transmitted frame, but now we want to reuse it */
+- skb_orphan(skb);
+-
+- /* Need to make a copy before skb->cb gets cleared */
+- send_to_cooked = !!(info->flags & IEEE80211_TX_CTL_INJECTED) ||
+- !(ieee80211_is_data(fc));
+-
+- /*
+- * This is a bit racy but we can avoid a lot of work
+- * with this test...
+- */
+- if (!local->tx_mntrs && (!send_to_cooked || !local->cooked_mntrs)) {
+- if (status->free_list)
+- list_add_tail(&skb->list, status->free_list);
+- else
+- dev_kfree_skb(skb);
+- return;
+- }
+-
+- /* send to monitor interfaces */
+- ieee80211_tx_monitor(local, skb, retry_count,
+- send_to_cooked, status);
++ if (status->free_list)
++ list_add_tail(&skb->list, status->free_list);
++ else
++ dev_kfree_skb(skb);
+ }
+
+ void ieee80211_tx_status_skb(struct ieee80211_hw *hw, struct sk_buff *skb)
+diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
+index a24636bda6793..1289df373795e 100644
+--- a/net/mac80211/tx.c
++++ b/net/mac80211/tx.c
+@@ -5617,7 +5617,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
+ if (!copy)
+ return bcn;
+
+- ieee80211_tx_monitor(hw_to_local(hw), copy, 1, false, NULL);
++ ieee80211_tx_monitor(hw_to_local(hw), copy, 1, NULL);
+
+ return bcn;
+ }
+--
+2.39.5
+
--- /dev/null
+From d1ea5fc22b36ef0fadc474c4f851becb7c20c12d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 8 Mar 2025 23:03:31 +0200
+Subject: wifi: mac80211: fix U-APSD check in ML reconfiguration
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+[ Upstream commit 7a6a740be17e049a2742c76bb1dadb3d78c930d9 ]
+
+If U-APSD isn't enabled by us, then IEEE80211_STA_UAPSD_ENABLED
+won't be set, but the AP can still support it in that case. Only
+require U-APSD from the AP if we enabled it, don't require it to
+be disabled on the AP if we didn't.
+
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Reviewed-by: Ilan Peer <ilan.peer@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20250308225541.b4674be12a38.I01959e448c6a2a3e8bc5d561bbae9e8d2cca616a@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/mac80211/mlme.c | 9 ++++-----
+ 1 file changed, 4 insertions(+), 5 deletions(-)
+
+diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
+index 3f30c4c1f78bb..f92cbbc32a9e5 100644
+--- a/net/mac80211/mlme.c
++++ b/net/mac80211/mlme.c
+@@ -10216,12 +10216,11 @@ int ieee80211_mgd_assoc_ml_reconf(struct ieee80211_sub_if_data *sdata,
+ }
+ }
+
+- /* Require U-APSD support to be similar to the current valid
+- * links
+- */
+- if (uapsd_supported !=
+- !!(sdata->u.mgd.flags & IEEE80211_STA_UAPSD_ENABLED)) {
++ /* Require U-APSD support if we enabled it */
++ if (sdata->u.mgd.flags & IEEE80211_STA_UAPSD_ENABLED &&
++ !uapsd_supported) {
+ err = -EINVAL;
++ sdata_info(sdata, "U-APSD on but not available on (all) new links\n");
+ goto err_free;
+ }
+
+--
+2.39.5
+
--- /dev/null
+From 306d996b401997c39664c279c1a4eb6ea76ad79f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 8 Mar 2025 23:03:36 +0200
+Subject: wifi: mac80211: fix warning on disconnect during failed ML reconf
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+[ Upstream commit 0e104aa3676d020f6c442cd7fbaeb72adaaab6fc ]
+
+If multi-link reconfiguration fails, we can disconnect with a local link
+already allocated but the BSS entry not assigned yet, which leads to a
+warning in cfg80211. Add a check to avoid the warning.
+
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Reviewed-by: Ilan Peer <ilan.peer@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20250308225541.699bd9cbabe5.I599d5ff69092a65e916e2acd25137ae9df8debe8@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/mac80211/mlme.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
+index 676274519cdfb..3f30c4c1f78bb 100644
+--- a/net/mac80211/mlme.c
++++ b/net/mac80211/mlme.c
+@@ -4298,7 +4298,7 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata)
+ struct ieee80211_link_data *link;
+
+ link = sdata_dereference(sdata->link[link_id], sdata);
+- if (!link)
++ if (!link || !link->conf->bss)
+ continue;
+ cfg80211_unlink_bss(local->hw.wiphy, link->conf->bss);
+ link->conf->bss = NULL;
+--
+2.39.5
+
--- /dev/null
+From dea3488aa4b02a45c4a2dd825126ea93bda8e770 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Feb 2025 11:39:21 +0200
+Subject: wifi: mac80211: remove misplaced drv_mgd_complete_tx() call
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+[ Upstream commit f4995cdc4d02d0abc8e9fcccad5c71ce676c1e3f ]
+
+In the original commit 15fae3410f1d ("mac80211: notify driver on
+mgd TX completion") I evidently made a mistake and placed the
+call in the "associated" if, rather than the "assoc_data". Later
+I noticed the missing call and placed it in commit c042600c17d8
+("wifi: mac80211: adding missing drv_mgd_complete_tx() call"),
+but didn't remove the wrong one. Remove it now.
+
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20250205110958.6ed954179bbf.Id8ef8835b7e6da3bf913c76f77d201017dc8a3c9@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/mac80211/mlme.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
+index 3bd1c4eeae52f..ca247609f11bf 100644
+--- a/net/mac80211/mlme.c
++++ b/net/mac80211/mlme.c
+@@ -9508,7 +9508,6 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
+ ieee80211_report_disconnect(sdata, frame_buf,
+ sizeof(frame_buf), true,
+ req->reason_code, false);
+- drv_mgd_complete_tx(sdata->local, sdata, &info);
+ return 0;
+ }
+
+--
+2.39.5
+
--- /dev/null
+From bda67e991199e80abc8418b3024d7e3a718e759d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Feb 2025 11:39:20 +0200
+Subject: wifi: mac80211: set ieee80211_prep_tx_info::link_id upon Auth Rx
+
+From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+
+[ Upstream commit 8c60179b64434894eac1ffab7396bac131bc8b6e ]
+
+This will be used by the low level driver.
+Note that link_id will be 0 in case of a non-MLO authentication.
+Also fix a call-site of mgd_prepare_tx() where the link_id was not
+populated.
+
+Update the documentation to reflect the current state
+ieee80211_prep_tx_info::link_id is also available in mgd_complete_tx().
+
+Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20250205110958.6a590f189ce5.I1fc5c0da26b143f5b07191eb592f01f7083d55ae@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/mac80211.h | 4 ++--
+ net/mac80211/driver-ops.h | 3 ++-
+ net/mac80211/mlme.c | 4 +++-
+ 3 files changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/include/net/mac80211.h b/include/net/mac80211.h
+index dcbb2e54746c7..b421526aae851 100644
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -7,7 +7,7 @@
+ * Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2013-2014 Intel Mobile Communications GmbH
+ * Copyright (C) 2015 - 2017 Intel Deutschland GmbH
+- * Copyright (C) 2018 - 2024 Intel Corporation
++ * Copyright (C) 2018 - 2025 Intel Corporation
+ */
+
+ #ifndef MAC80211_H
+@@ -3829,7 +3829,7 @@ enum ieee80211_reconfig_type {
+ * @was_assoc: set if this call is due to deauth/disassoc
+ * while just having been associated
+ * @link_id: the link id on which the frame will be TX'ed.
+- * Only used with the mgd_prepare_tx() method.
++ * 0 for a non-MLO connection.
+ */
+ struct ieee80211_prep_tx_info {
+ u16 duration;
+diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
+index 5acecc7bd4a99..307587c8a0037 100644
+--- a/net/mac80211/driver-ops.h
++++ b/net/mac80211/driver-ops.h
+@@ -2,7 +2,7 @@
+ /*
+ * Portions of this file
+ * Copyright(c) 2016 Intel Deutschland GmbH
+-* Copyright (C) 2018-2019, 2021-2024 Intel Corporation
++* Copyright (C) 2018-2019, 2021-2025 Intel Corporation
+ */
+
+ #ifndef __MAC80211_DRIVER_OPS
+@@ -955,6 +955,7 @@ static inline void drv_mgd_complete_tx(struct ieee80211_local *local,
+ return;
+ WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION);
+
++ info->link_id = info->link_id < 0 ? 0 : info->link_id;
+ trace_drv_mgd_complete_tx(local, sdata, info->duration,
+ info->subtype, info->success);
+ if (local->ops->mgd_complete_tx)
+diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
+index ca247609f11bf..8235400b7e5d8 100644
+--- a/net/mac80211/mlme.c
++++ b/net/mac80211/mlme.c
+@@ -8,7 +8,7 @@
+ * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2013-2014 Intel Mobile Communications GmbH
+ * Copyright (C) 2015 - 2017 Intel Deutschland GmbH
+- * Copyright (C) 2018 - 2024 Intel Corporation
++ * Copyright (C) 2018 - 2025 Intel Corporation
+ */
+
+ #include <linux/delay.h>
+@@ -4579,6 +4579,8 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
+ auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
+ status_code = le16_to_cpu(mgmt->u.auth.status_code);
+
++ info.link_id = ifmgd->auth_data->link_id;
++
+ if (auth_alg != ifmgd->auth_data->algorithm ||
+ (auth_alg != WLAN_AUTH_SAE &&
+ auth_transaction != ifmgd->auth_data->expected_transaction) ||
+--
+2.39.5
+
--- /dev/null
+From 5b154d22631e8ffa85470a4e12712dc9474f99a8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 8 Mar 2025 23:03:34 +0200
+Subject: wifi: mac80211_hwsim: Fix MLD address translation
+
+From: Ilan Peer <ilan.peer@intel.com>
+
+[ Upstream commit 65bff0be9b154621b617fc2e4bd89f1e18e97cdb ]
+
+Do address translations only between shared links. It is
+possible that while an non-AP MLD station and an AP MLD
+station have shared links, the frame is intended to be sent
+on a link which is not shared (for example when sending a
+probe response).
+
+Signed-off-by: Ilan Peer <ilan.peer@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20250308225541.1aa461270bb6.Ic21592e1b1634653f02b80628cb2152f6e9de367@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/virtual/mac80211_hwsim.c | 14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c
+index cf6a331d40427..a68530344d205 100644
+--- a/drivers/net/wireless/virtual/mac80211_hwsim.c
++++ b/drivers/net/wireless/virtual/mac80211_hwsim.c
+@@ -4,7 +4,7 @@
+ * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2011, Javier Lopez <jlopex@gmail.com>
+ * Copyright (c) 2016 - 2017 Intel Deutschland GmbH
+- * Copyright (C) 2018 - 2024 Intel Corporation
++ * Copyright (C) 2018 - 2025 Intel Corporation
+ */
+
+ /*
+@@ -1983,11 +1983,13 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
+ return;
+ }
+
+- if (sta && sta->mlo) {
+- if (WARN_ON(!link_sta)) {
+- ieee80211_free_txskb(hw, skb);
+- return;
+- }
++ /* Do address translations only between shared links. It is
++ * possible that while an non-AP MLD station and an AP MLD
++ * station have shared links, the frame is intended to be sent
++ * on a link which is not shared (for example when sending a
++ * probe response).
++ */
++ if (sta && sta->mlo && link_sta) {
+ /* address translation to link addresses on TX */
+ ether_addr_copy(hdr->addr1, link_sta->addr);
+ ether_addr_copy(hdr->addr2, bss_conf->addr);
+--
+2.39.5
+
--- /dev/null
+From 3a754e58dda56cde2d97cecedeb36c91a7fc610e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Mar 2025 18:45:09 +0100
+Subject: wifi: mt76: Check link_conf pointer in
+ mt76_connac_mcu_sta_basic_tlv()
+
+From: Shayne Chen <shayne.chen@mediatek.com>
+
+[ Upstream commit 9890624c1b3948c1c7f1d0e19ef0bb7680b8c80d ]
+
+This is a preliminary patch to introduce MLO support for MT7996 driver.
+
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+Link: https://patch.msgid.link/20250311-mt7996-mlo-v2-10-31df6972519b@kernel.org
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
+index d0e49d68c5dbf..bafcf5a279e23 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
++++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
+@@ -391,7 +391,7 @@ void mt76_connac_mcu_sta_basic_tlv(struct mt76_dev *dev, struct sk_buff *skb,
+ basic->conn_type = cpu_to_le32(CONNECTION_INFRA_BC);
+
+ if (vif->type == NL80211_IFTYPE_STATION &&
+- !is_zero_ether_addr(link_conf->bssid)) {
++ link_conf && !is_zero_ether_addr(link_conf->bssid)) {
+ memcpy(basic->peer_addr, link_conf->bssid, ETH_ALEN);
+ basic->aid = cpu_to_le16(vif->cfg.aid);
+ } else {
+--
+2.39.5
+
--- /dev/null
+From d22e21bf0540da69c996f1d057c4a4a145083cca Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 14 Jan 2025 13:06:22 +0800
+Subject: wifi: mt76: mt7925: fix fails to enter low power mode in suspend
+ state
+
+From: Quan Zhou <quan.zhou@mediatek.com>
+
+[ Upstream commit 2d5630b0c9466ac6549495828aa7dce7424a272a ]
+
+The mt7925 sometimes fails to enter low power mode during suspend.
+This is caused by the chip firmware sending an additional ACK event
+to the host after processing the suspend command. Due to timing issues,
+this event may not reach the host, causing the chip to get stuck.
+To resolve this, the ACK flag in the suspend command is removed,
+as it is not needed in the MT7925 architecture. This prevents the
+firmware from sending the additional ACK event, ensuring the device
+can reliably enter low power mode during suspend.
+
+Signed-off-by: Quan Zhou <quan.zhou@mediatek.com>
+Link: https://patch.msgid.link/d056938144a3a0336c3a4e3cec6f271899f32bf7.1736775666.git.quan.zhou@mediatek.com
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+index 87b3a88038e3c..59fa812b30d35 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+@@ -3294,6 +3294,9 @@ int mt7925_mcu_fill_message(struct mt76_dev *mdev, struct sk_buff *skb,
+ else
+ uni_txd->option = MCU_CMD_UNI_EXT_ACK;
+
++ if (cmd == MCU_UNI_CMD(HIF_CTRL))
++ uni_txd->option &= ~MCU_CMD_ACK;
++
+ goto exit;
+ }
+
+--
+2.39.5
+
--- /dev/null
+From 8f86db495561a6dc28a543fec1c0c8e2f6f4fd03 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Mar 2025 19:36:44 +0800
+Subject: wifi: mt76: mt7925: load the appropriate CLC data based on hardware
+ type
+
+From: Ming Yen Hsieh <mingyen.hsieh@mediatek.com>
+
+[ Upstream commit f2027ef3f733d3f0bb7f27fa3343784058f946ab ]
+
+Read the EEPROM to determine the hardware type and uses this to load the
+correct CLC data.
+
+Signed-off-by: Ming Yen Hsieh <mingyen.hsieh@mediatek.com>
+Link: https://patch.msgid.link/20250304113649.867387-1-mingyen.hsieh@mediatek.com
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../net/wireless/mediatek/mt76/mt7925/mcu.c | 61 ++++++++++++++++++-
+ .../wireless/mediatek/mt76/mt7925/mt7925.h | 3 +
+ 2 files changed, 63 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+index f8d45d43f7807..775ccd667dd3f 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+@@ -631,6 +631,54 @@ int mt7925_mcu_uni_rx_ba(struct mt792x_dev *dev,
+ enable, false);
+ }
+
++static int mt7925_mcu_read_eeprom(struct mt792x_dev *dev, u32 offset, u8 *val)
++{
++ struct {
++ u8 rsv[4];
++
++ __le16 tag;
++ __le16 len;
++
++ __le32 addr;
++ __le32 valid;
++ u8 data[MT7925_EEPROM_BLOCK_SIZE];
++ } __packed req = {
++ .tag = cpu_to_le16(1),
++ .len = cpu_to_le16(sizeof(req) - 4),
++ .addr = cpu_to_le32(round_down(offset,
++ MT7925_EEPROM_BLOCK_SIZE)),
++ };
++ struct evt {
++ u8 rsv[4];
++
++ __le16 tag;
++ __le16 len;
++
++ __le32 ver;
++ __le32 addr;
++ __le32 valid;
++ __le32 size;
++ __le32 magic_num;
++ __le32 type;
++ __le32 rsv1[4];
++ u8 data[32];
++ } __packed *res;
++ struct sk_buff *skb;
++ int ret;
++
++ ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_WM_UNI_CMD_QUERY(EFUSE_CTRL),
++ &req, sizeof(req), true, &skb);
++ if (ret)
++ return ret;
++
++ res = (struct evt *)skb->data;
++ *val = res->data[offset % MT7925_EEPROM_BLOCK_SIZE];
++
++ dev_kfree_skb(skb);
++
++ return 0;
++}
++
+ static int mt7925_load_clc(struct mt792x_dev *dev, const char *fw_name)
+ {
+ const struct mt76_connac2_fw_trailer *hdr;
+@@ -639,13 +687,20 @@ static int mt7925_load_clc(struct mt792x_dev *dev, const char *fw_name)
+ struct mt76_dev *mdev = &dev->mt76;
+ struct mt792x_phy *phy = &dev->phy;
+ const struct firmware *fw;
++ u8 *clc_base = NULL, hw_encap = 0;
+ int ret, i, len, offset = 0;
+- u8 *clc_base = NULL;
+
+ if (mt7925_disable_clc ||
+ mt76_is_usb(&dev->mt76))
+ return 0;
+
++ if (mt76_is_mmio(&dev->mt76)) {
++ ret = mt7925_mcu_read_eeprom(dev, MT_EE_HW_TYPE, &hw_encap);
++ if (ret)
++ return ret;
++ hw_encap = u8_get_bits(hw_encap, MT_EE_HW_TYPE_ENCAP);
++ }
++
+ ret = request_firmware(&fw, fw_name, mdev->dev);
+ if (ret)
+ return ret;
+@@ -690,6 +745,10 @@ static int mt7925_load_clc(struct mt792x_dev *dev, const char *fw_name)
+ if (phy->clc[clc->idx])
+ continue;
+
++ /* header content sanity */
++ if (u8_get_bits(clc->type, MT_EE_HW_TYPE_ENCAP) != hw_encap)
++ continue;
++
+ phy->clc[clc->idx] = devm_kmemdup(mdev->dev, clc,
+ le32_to_cpu(clc->len),
+ GFP_KERNEL);
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
+index cb7b1a49fbd14..073e433069e0e 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
++++ b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
+@@ -167,9 +167,12 @@ enum mt7925_eeprom_field {
+ MT_EE_CHIP_ID = 0x000,
+ MT_EE_VERSION = 0x002,
+ MT_EE_MAC_ADDR = 0x004,
++ MT_EE_HW_TYPE = 0xa71,
+ __MT_EE_MAX = 0x9ff
+ };
+
++#define MT_EE_HW_TYPE_ENCAP GENMASK(1, 0)
++
+ enum {
+ TXPWR_USER,
+ TXPWR_EEPROM,
+--
+2.39.5
+
--- /dev/null
+From b1a1156dd8e1e1792df6dbfb9e4e409b4492af12 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 24 Feb 2025 21:05:14 +0800
+Subject: wifi: mt76: mt7925: Simplify HIF suspend handling to avoid suspend
+ fail
+
+From: Quan Zhou <quan.zhou@mediatek.com>
+
+[ Upstream commit bf39813599b0375a3eebbbc6837f728554b3883a ]
+
+System suspend failures may occur due to inappropriate
+handling of traffic not idle event by the WiFi driver.
+The WiFi firmware's traffic not idle indication does
+not need to be tied to suspend. Fix the flow to ensuring
+the system can suspend properly.
+
+Signed-off-by: Quan Zhou <quan.zhou@mediatek.com>
+Link: https://patch.msgid.link/34208c7280325f57a651363d339399eb1744d3b7.1740400998.git.quan.zhou@mediatek.com
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 12 ++++--------
+ 1 file changed, 4 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+index 775ccd667dd3f..87b3a88038e3c 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+@@ -348,14 +348,10 @@ mt7925_mcu_handle_hif_ctrl_basic(struct mt792x_dev *dev, struct tlv *tlv)
+ basic = (struct mt7925_mcu_hif_ctrl_basic_tlv *)tlv;
+
+ if (basic->hifsuspend) {
+- if (basic->hif_tx_traffic_status == HIF_TRAFFIC_IDLE &&
+- basic->hif_rx_traffic_status == HIF_TRAFFIC_IDLE)
+- /* success */
+- dev->hif_idle = true;
+- else
+- /* busy */
+- /* invalid */
+- dev->hif_idle = false;
++ dev->hif_idle = true;
++ if (!(basic->hif_tx_traffic_status == HIF_TRAFFIC_IDLE &&
++ basic->hif_rx_traffic_status == HIF_TRAFFIC_IDLE))
++ dev_info(dev->mt76.dev, "Hif traffic not idle.\n");
+ } else {
+ dev->hif_resumed = true;
+ }
+--
+2.39.5
+
--- /dev/null
+From 3498bf5cd305661fa36d9f7298bf4dc62af0bf1c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Mar 2025 11:36:39 +0100
+Subject: wifi: mt76: mt7996: fix SER reset trigger on WED reset
+
+From: Rex Lu <rex.lu@mediatek.com>
+
+[ Upstream commit 8d38abdf6c182225c5c0a81451fa51b7b36a635d ]
+
+The firmware needs a specific trigger when WED is being reset due to an
+ethernet reset condition. This helps prevent further L1 SER failure.
+
+Signed-off-by: Rex Lu <rex.lu@mediatek.com>
+Link: https://patch.msgid.link/20250311103646.43346-2-nbd@nbd.name
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/mediatek/mt76/mt7996/mcu.h | 3 ++-
+ drivers/net/wireless/mediatek/mt76/mt7996/mmio.c | 2 +-
+ 2 files changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
+index 43468bcaffc6d..a75e1c9435bb0 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
+@@ -908,7 +908,8 @@ enum {
+ UNI_CMD_SER_SET_RECOVER_L3_TX_DISABLE,
+ UNI_CMD_SER_SET_RECOVER_L3_BF,
+ UNI_CMD_SER_SET_RECOVER_L4_MDP,
+- UNI_CMD_SER_SET_RECOVER_FULL,
++ UNI_CMD_SER_SET_RECOVER_FROM_ETH,
++ UNI_CMD_SER_SET_RECOVER_FULL = 8,
+ UNI_CMD_SER_SET_SYSTEM_ASSERT,
+ /* action */
+ UNI_CMD_SER_ENABLE = 1,
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c
+index 7a8ee6c75cf2b..9d37f82387464 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c
+@@ -281,7 +281,7 @@ static int mt7996_mmio_wed_reset(struct mtk_wed_device *wed)
+ if (test_and_set_bit(MT76_STATE_WED_RESET, &mphy->state))
+ return -EBUSY;
+
+- ret = mt7996_mcu_set_ser(dev, UNI_CMD_SER_TRIGGER, UNI_CMD_SER_SET_RECOVER_L1,
++ ret = mt7996_mcu_set_ser(dev, UNI_CMD_SER_TRIGGER, UNI_CMD_SER_SET_RECOVER_FROM_ETH,
+ mphy->band_idx);
+ if (ret)
+ goto out;
+--
+2.39.5
+
--- /dev/null
+From b02016da89ed93c7adcfb2c31c2deb134a872778 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Mar 2025 11:36:44 +0100
+Subject: wifi: mt76: mt7996: implement driver specific get_txpower function
+
+From: Felix Fietkau <nbd@nbd.name>
+
+[ Upstream commit 86db2c5d4ed390b97a5b455a97e2cd9c4f3eff2b ]
+
+Fixes reporting tx power for vifs that don't have a channel context
+assigned. Report the tx power of a phy that is covered by the vif's
+radio mask.
+
+Link: https://patch.msgid.link/20250311103646.43346-7-nbd@nbd.name
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../net/wireless/mediatek/mt76/mt7996/main.c | 29 ++++++++++++++++++-
+ 1 file changed, 28 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
+index 69dd565d83190..980a059b3b38f 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
+@@ -601,6 +601,33 @@ static void mt7996_configure_filter(struct ieee80211_hw *hw,
+ mutex_unlock(&dev->mt76.mutex);
+ }
+
++static int
++mt7996_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
++ unsigned int link_id, int *dbm)
++{
++ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
++ struct mt7996_phy *phy = mt7996_vif_link_phy(&mvif->deflink);
++ struct mt7996_dev *dev = mt7996_hw_dev(hw);
++ struct wireless_dev *wdev;
++ int n_chains, delta, i;
++
++ if (!phy) {
++ wdev = ieee80211_vif_to_wdev(vif);
++ for (i = 0; i < hw->wiphy->n_radio; i++)
++ if (wdev->radio_mask & BIT(i))
++ phy = dev->radio_phy[i];
++
++ if (!phy)
++ return -EINVAL;
++ }
++
++ n_chains = hweight16(phy->mt76->chainmask);
++ delta = mt76_tx_power_nss_delta(n_chains);
++ *dbm = DIV_ROUND_UP(phy->mt76->txpower_cur + delta, 2);
++
++ return 0;
++}
++
+ static u8
+ mt7996_get_rates_table(struct mt7996_phy *phy, struct ieee80211_bss_conf *conf,
+ bool beacon, bool mcast)
+@@ -1650,7 +1677,7 @@ const struct ieee80211_ops mt7996_ops = {
+ .remain_on_channel = mt76_remain_on_channel,
+ .cancel_remain_on_channel = mt76_cancel_remain_on_channel,
+ .release_buffered_frames = mt76_release_buffered_frames,
+- .get_txpower = mt76_get_txpower,
++ .get_txpower = mt7996_get_txpower,
+ .channel_switch_beacon = mt7996_channel_switch_beacon,
+ .get_stats = mt7996_get_stats,
+ .get_et_sset_count = mt7996_get_et_sset_count,
+--
+2.39.5
+
--- /dev/null
+From 099e34a43c61780a04e81978b1df58db50919a99 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Mar 2025 11:36:38 +0100
+Subject: wifi: mt76: mt7996: revise TXS size
+
+From: Benjamin Lin <benjamin-jw.lin@mediatek.com>
+
+[ Upstream commit 593c829b4326f7b3b15a69e97c9044ecbad3c319 ]
+
+Size of MPDU/PPDU TXS is 12 DWs.
+In mt7996/mt7992, last 4 DWs are reserved, so TXS size was mistakenly
+considered to be 8 DWs. However, in mt7990, 9th DW of TXS starts to be used.
+
+Signed-off-by: Benjamin Lin <benjamin-jw.lin@mediatek.com>
+Link: https://patch.msgid.link/20250311103646.43346-1-nbd@nbd.name
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h | 3 +++
+ drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 4 ++--
+ 2 files changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h
+index db0c29e65185c..487ad716f872a 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h
++++ b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h
+@@ -314,6 +314,9 @@ enum tx_frag_idx {
+ #define MT_TXFREE_INFO_COUNT GENMASK(27, 24)
+ #define MT_TXFREE_INFO_STAT GENMASK(29, 28)
+
++#define MT_TXS_HDR_SIZE 4 /* Unit: DW */
++#define MT_TXS_SIZE 12 /* Unit: DW */
++
+ #define MT_TXS0_BW GENMASK(31, 29)
+ #define MT_TXS0_TID GENMASK(28, 26)
+ #define MT_TXS0_AMPDU BIT(25)
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
+index 88f9d9059d5f2..c7e8336027334 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
+@@ -1413,7 +1413,7 @@ bool mt7996_rx_check(struct mt76_dev *mdev, void *data, int len)
+ mt7996_mac_tx_free(dev, data, len);
+ return false;
+ case PKT_TYPE_TXS:
+- for (rxd += 4; rxd + 8 <= end; rxd += 8)
++ for (rxd += MT_TXS_HDR_SIZE; rxd + MT_TXS_SIZE <= end; rxd += MT_TXS_SIZE)
+ mt7996_mac_add_txs(dev, rxd);
+ return false;
+ case PKT_TYPE_RX_FW_MONITOR:
+@@ -1456,7 +1456,7 @@ void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
+ mt7996_mcu_rx_event(dev, skb);
+ break;
+ case PKT_TYPE_TXS:
+- for (rxd += 4; rxd + 8 <= end; rxd += 8)
++ for (rxd += MT_TXS_HDR_SIZE; rxd + MT_TXS_SIZE <= end; rxd += MT_TXS_SIZE)
+ mt7996_mac_add_txs(dev, rxd);
+ dev_kfree_skb(skb);
+ break;
+--
+2.39.5
+
--- /dev/null
+From c10cbc1ce1d39894ba4a550d8dc441882c2a0ea7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Mar 2025 11:36:42 +0100
+Subject: wifi: mt76: mt7996: use the correct vif link for scanning/roc
+
+From: Felix Fietkau <nbd@nbd.name>
+
+[ Upstream commit 13b4c81083cc4b59fb639a511c0a9a7c38efde7e ]
+
+Use the newly added offchannel_link pointer in vif data
+
+Link: https://patch.msgid.link/20250311103646.43346-5-nbd@nbd.name
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../net/wireless/mediatek/mt76/mt7996/mac.c | 40 +++++++++++++------
+ .../net/wireless/mediatek/mt76/mt7996/main.c | 1 +
+ 2 files changed, 28 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
+index 019c925ae600e..88f9d9059d5f2 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
+@@ -832,7 +832,8 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
+ u8 band_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2;
+ u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
+ bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
+- struct mt76_vif_link *mvif;
++ struct mt76_vif_link *mlink = NULL;
++ struct mt7996_vif *mvif;
+ u16 tx_count = 15;
+ u32 val;
+ bool inband_disc = !!(changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |
+@@ -840,11 +841,18 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
+ bool beacon = !!(changed & (BSS_CHANGED_BEACON |
+ BSS_CHANGED_BEACON_ENABLED)) && (!inband_disc);
+
+- mvif = vif ? (struct mt76_vif_link *)vif->drv_priv : NULL;
+- if (mvif) {
+- omac_idx = mvif->omac_idx;
+- wmm_idx = mvif->wmm_idx;
+- band_idx = mvif->band_idx;
++ if (vif) {
++ mvif = (struct mt7996_vif *)vif->drv_priv;
++ if (wcid->offchannel)
++ mlink = rcu_dereference(mvif->mt76.offchannel_link);
++ if (!mlink)
++ mlink = &mvif->deflink.mt76;
++ }
++
++ if (mlink) {
++ omac_idx = mlink->omac_idx;
++ wmm_idx = mlink->wmm_idx;
++ band_idx = mlink->band_idx;
+ }
+
+ if (inband_disc) {
+@@ -910,13 +918,13 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
+ is_multicast_ether_addr(hdr->addr1);
+ u8 idx = MT7996_BASIC_RATES_TBL;
+
+- if (mvif) {
+- if (mcast && mvif->mcast_rates_idx)
+- idx = mvif->mcast_rates_idx;
+- else if (beacon && mvif->beacon_rates_idx)
+- idx = mvif->beacon_rates_idx;
++ if (mlink) {
++ if (mcast && mlink->mcast_rates_idx)
++ idx = mlink->mcast_rates_idx;
++ else if (beacon && mlink->beacon_rates_idx)
++ idx = mlink->beacon_rates_idx;
+ else
+- idx = mvif->basic_rates_idx;
++ idx = mlink->basic_rates_idx;
+ }
+
+ val = FIELD_PREP(MT_TXD6_TX_RATE, idx) | MT_TXD6_FIXED_BW;
+@@ -984,8 +992,14 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
+
+ if (vif) {
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
++ struct mt76_vif_link *mlink = NULL;
++
++ if (wcid->offchannel)
++ mlink = rcu_dereference(mvif->mt76.offchannel_link);
++ if (!mlink)
++ mlink = &mvif->deflink.mt76;
+
+- txp->fw.bss_idx = mvif->deflink.mt76.idx;
++ txp->fw.bss_idx = mlink->idx;
+ }
+
+ txp->fw.token = cpu_to_le16(id);
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
+index 980a059b3b38f..b01cc7ef47999 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
+@@ -249,6 +249,7 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif,
+ mlink->band_idx = band_idx;
+ mlink->wmm_idx = vif->type == NL80211_IFTYPE_AP ? 0 : 3;
+ mlink->wcid = &link->sta.wcid;
++ mlink->wcid->offchannel = mlink->offchannel;
+
+ ret = mt7996_mcu_add_dev_info(phy, vif, link_conf, mlink, true);
+ if (ret)
+--
+2.39.5
+
--- /dev/null
+From 9442374e73b8bf9ee5bb6755ca564fddc5c6d973 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Mar 2025 11:36:43 +0100
+Subject: wifi: mt76: only mark tx-status-failed frames as ACKed on mt76x0/2
+
+From: Felix Fietkau <nbd@nbd.name>
+
+[ Upstream commit 0c5a89ceddc1728a40cb3313948401dd70e3c649 ]
+
+The interrupt status polling is unreliable, which can cause status events
+to get lost. On all newer chips, txs-timeout is an indication that the
+packet was either never sent, or never acked.
+Fixes issues with inactivity polling.
+
+Link: https://patch.msgid.link/20250311103646.43346-6-nbd@nbd.name
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/mediatek/mt76/mt76.h | 1 +
+ drivers/net/wireless/mediatek/mt76/mt76x0/pci.c | 3 ++-
+ drivers/net/wireless/mediatek/mt76/mt76x0/usb.c | 3 ++-
+ drivers/net/wireless/mediatek/mt76/mt76x2/pci.c | 3 ++-
+ drivers/net/wireless/mediatek/mt76/mt76x2/usb.c | 3 ++-
+ drivers/net/wireless/mediatek/mt76/tx.c | 3 ++-
+ 6 files changed, 11 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
+index 05651efb549ec..8714418f3906c 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt76.h
++++ b/drivers/net/wireless/mediatek/mt76/mt76.h
+@@ -491,6 +491,7 @@ struct mt76_hw_cap {
+ #define MT_DRV_RX_DMA_HDR BIT(3)
+ #define MT_DRV_HW_MGMT_TXQ BIT(4)
+ #define MT_DRV_AMSDU_OFFLOAD BIT(5)
++#define MT_DRV_IGNORE_TXS_FAILED BIT(6)
+
+ struct mt76_driver_ops {
+ u32 drv_flags;
+diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c
+index b456ccd00d581..11c16d1fc70fc 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c
++++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c
+@@ -156,7 +156,8 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+ static const struct mt76_driver_ops drv_ops = {
+ .txwi_size = sizeof(struct mt76x02_txwi),
+ .drv_flags = MT_DRV_TX_ALIGNED4_SKBS |
+- MT_DRV_SW_RX_AIRTIME,
++ MT_DRV_SW_RX_AIRTIME |
++ MT_DRV_IGNORE_TXS_FAILED,
+ .survey_flags = SURVEY_INFO_TIME_TX,
+ .update_survey = mt76x02_update_channel,
+ .set_channel = mt76x0_set_channel,
+diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
+index b031c500b7415..90e5666c0857d 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
++++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
+@@ -214,7 +214,8 @@ static int mt76x0u_probe(struct usb_interface *usb_intf,
+ const struct usb_device_id *id)
+ {
+ static const struct mt76_driver_ops drv_ops = {
+- .drv_flags = MT_DRV_SW_RX_AIRTIME,
++ .drv_flags = MT_DRV_SW_RX_AIRTIME |
++ MT_DRV_IGNORE_TXS_FAILED,
+ .survey_flags = SURVEY_INFO_TIME_TX,
+ .update_survey = mt76x02_update_channel,
+ .set_channel = mt76x0_set_channel,
+diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c
+index 727bfdd00b400..2303019670e2c 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c
++++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c
+@@ -22,7 +22,8 @@ mt76x2e_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+ static const struct mt76_driver_ops drv_ops = {
+ .txwi_size = sizeof(struct mt76x02_txwi),
+ .drv_flags = MT_DRV_TX_ALIGNED4_SKBS |
+- MT_DRV_SW_RX_AIRTIME,
++ MT_DRV_SW_RX_AIRTIME |
++ MT_DRV_IGNORE_TXS_FAILED,
+ .survey_flags = SURVEY_INFO_TIME_TX,
+ .update_survey = mt76x02_update_channel,
+ .set_channel = mt76x2e_set_channel,
+diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c
+index a4f4d12f904e7..84ef80ab4afbf 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c
++++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c
+@@ -30,7 +30,8 @@ static int mt76x2u_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+ {
+ static const struct mt76_driver_ops drv_ops = {
+- .drv_flags = MT_DRV_SW_RX_AIRTIME,
++ .drv_flags = MT_DRV_SW_RX_AIRTIME |
++ MT_DRV_IGNORE_TXS_FAILED,
+ .survey_flags = SURVEY_INFO_TIME_TX,
+ .update_survey = mt76x02_update_channel,
+ .set_channel = mt76x2u_set_channel,
+diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c
+index af0c50c983ec1..513916469ca2f 100644
+--- a/drivers/net/wireless/mediatek/mt76/tx.c
++++ b/drivers/net/wireless/mediatek/mt76/tx.c
+@@ -100,7 +100,8 @@ __mt76_tx_status_skb_done(struct mt76_dev *dev, struct sk_buff *skb, u8 flags,
+ return;
+
+ /* Tx status can be unreliable. if it fails, mark the frame as ACKed */
+- if (flags & MT_TX_CB_TXS_FAILED) {
++ if (flags & MT_TX_CB_TXS_FAILED &&
++ (dev->drv->drv_flags & MT_DRV_IGNORE_TXS_FAILED)) {
+ info->status.rates[0].count = 0;
+ info->status.rates[0].idx = -1;
+ info->flags |= IEEE80211_TX_STAT_ACK;
+--
+2.39.5
+
--- /dev/null
+From c90044c4daacf819ca458ecee6795950faf356cb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Mar 2025 11:36:45 +0100
+Subject: wifi: mt76: scan: fix setting tx_info fields
+
+From: Felix Fietkau <nbd@nbd.name>
+
+[ Upstream commit 5b5f1ca9ce73ab6c35e5cd3348f8432ba190d7f4 ]
+
+ieee80211_tx_prepare_skb initializes the skb cb, so fields need to be set
+afterwards.
+
+Link: https://patch.msgid.link/20250311103646.43346-8-nbd@nbd.name
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/mediatek/mt76/scan.c | 21 +++++++++++++--------
+ 1 file changed, 13 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/net/wireless/mediatek/mt76/scan.c b/drivers/net/wireless/mediatek/mt76/scan.c
+index 1c4f9deaaada5..9b20ccbeb8cf1 100644
+--- a/drivers/net/wireless/mediatek/mt76/scan.c
++++ b/drivers/net/wireless/mediatek/mt76/scan.c
+@@ -52,11 +52,6 @@ mt76_scan_send_probe(struct mt76_dev *dev, struct cfg80211_ssid *ssid)
+ ether_addr_copy(hdr->addr3, req->bssid);
+ }
+
+- info = IEEE80211_SKB_CB(skb);
+- if (req->no_cck)
+- info->flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
+- info->control.flags |= IEEE80211_TX_CTRL_DONT_USE_RATE_MASK;
+-
+ if (req->ie_len)
+ skb_put_data(skb, req->ie, req->ie_len);
+
+@@ -64,10 +59,20 @@ mt76_scan_send_probe(struct mt76_dev *dev, struct cfg80211_ssid *ssid)
+ skb_set_queue_mapping(skb, IEEE80211_AC_VO);
+
+ rcu_read_lock();
+- if (ieee80211_tx_prepare_skb(phy->hw, vif, skb, band, NULL))
+- mt76_tx(phy, NULL, mvif->wcid, skb);
+- else
++
++ if (!ieee80211_tx_prepare_skb(phy->hw, vif, skb, band, NULL)) {
+ ieee80211_free_txskb(phy->hw, skb);
++ goto out;
++ }
++
++ info = IEEE80211_SKB_CB(skb);
++ if (req->no_cck)
++ info->flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
++ info->control.flags |= IEEE80211_TX_CTRL_DONT_USE_RATE_MASK;
++
++ mt76_tx(phy, NULL, mvif->wcid, skb);
++
++out:
+ rcu_read_unlock();
+ }
+
+--
+2.39.5
+
--- /dev/null
+From ff7359618d15d367f16391050eace589235a5c08 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Mar 2025 11:36:41 +0100
+Subject: wifi: mt76: scan: set vif offchannel link for scanning/roc
+
+From: Felix Fietkau <nbd@nbd.name>
+
+[ Upstream commit 3ba20af886d1f604dceeb4d4c8ff872e2c4e885e ]
+
+The driver needs to know what vif link to use
+
+Link: https://patch.msgid.link/20250311103646.43346-4-nbd@nbd.name
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/mediatek/mt76/channel.c | 3 +++
+ drivers/net/wireless/mediatek/mt76/mt76.h | 2 ++
+ 2 files changed, 5 insertions(+)
+
+diff --git a/drivers/net/wireless/mediatek/mt76/channel.c b/drivers/net/wireless/mediatek/mt76/channel.c
+index 6a35c6ebd823e..e7b839e742903 100644
+--- a/drivers/net/wireless/mediatek/mt76/channel.c
++++ b/drivers/net/wireless/mediatek/mt76/channel.c
+@@ -293,6 +293,7 @@ struct mt76_vif_link *mt76_get_vif_phy_link(struct mt76_phy *phy,
+ kfree(mlink);
+ return ERR_PTR(ret);
+ }
++ rcu_assign_pointer(mvif->offchannel_link, mlink);
+
+ return mlink;
+ }
+@@ -301,10 +302,12 @@ void mt76_put_vif_phy_link(struct mt76_phy *phy, struct ieee80211_vif *vif,
+ struct mt76_vif_link *mlink)
+ {
+ struct mt76_dev *dev = phy->dev;
++ struct mt76_vif_data *mvif = mlink->mvif;
+
+ if (IS_ERR_OR_NULL(mlink) || !mlink->offchannel)
+ return;
+
++ rcu_assign_pointer(mvif->offchannel_link, NULL);
+ dev->drv->vif_link_remove(phy, vif, &vif->bss_conf, mlink);
+ kfree(mlink);
+ }
+diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
+index 8714418f3906c..e4ecd9cde36dc 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt76.h
++++ b/drivers/net/wireless/mediatek/mt76/mt76.h
+@@ -351,6 +351,7 @@ struct mt76_wcid {
+ u8 hw_key_idx;
+ u8 hw_key_idx2;
+
++ u8 offchannel:1;
+ u8 sta:1;
+ u8 sta_disabled:1;
+ u8 amsdu:1;
+@@ -788,6 +789,7 @@ struct mt76_vif_link {
+
+ struct mt76_vif_data {
+ struct mt76_vif_link __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS];
++ struct mt76_vif_link __rcu *offchannel_link;
+
+ struct mt76_phy *roc_phy;
+ u16 valid_links;
+--
+2.39.5
+
--- /dev/null
+From 2f33f5362fcd6504d5520f0df42994255ecab9a0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 14 Mar 2025 17:42:38 +0800
+Subject: wifi: mwifiex: Fix HT40 bandwidth issue.
+
+From: Jeff Chen <jeff.chen_1@nxp.com>
+
+[ Upstream commit 4fcfcbe457349267fe048524078e8970807c1a5b ]
+
+This patch addresses an issue where, despite the AP supporting 40MHz
+bandwidth, the connection was limited to 20MHz. Without this fix,
+even if the access point supports 40MHz, the bandwidth after
+connection remains at 20MHz. This issue is not a regression.
+
+Signed-off-by: Jeff Chen <jeff.chen_1@nxp.com>
+Reviewed-by: Francesco Dolcini <francesco.dolcini@toradex.com>
+Link: https://patch.msgid.link/20250314094238.2097341-1-jeff.chen_1@nxp.com
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/marvell/mwifiex/11n.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/wireless/marvell/mwifiex/11n.c b/drivers/net/wireless/marvell/mwifiex/11n.c
+index 66f0f5377ac18..738bafc3749b0 100644
+--- a/drivers/net/wireless/marvell/mwifiex/11n.c
++++ b/drivers/net/wireless/marvell/mwifiex/11n.c
+@@ -403,12 +403,14 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
+
+ if (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 &&
+ bss_desc->bcn_ht_oper->ht_param &
+- IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)
++ IEEE80211_HT_PARAM_CHAN_WIDTH_ANY) {
++ chan_list->chan_scan_param[0].radio_type |=
++ CHAN_BW_40MHZ << 2;
+ SET_SECONDARYCHAN(chan_list->chan_scan_param[0].
+ radio_type,
+ (bss_desc->bcn_ht_oper->ht_param &
+ IEEE80211_HT_PARAM_CHA_SEC_OFFSET));
+-
++ }
+ *buffer += struct_size(chan_list, chan_scan_param, 1);
+ ret_len += struct_size(chan_list, chan_scan_param, 1);
+ }
+--
+2.39.5
+
--- /dev/null
+From 716608dbfef5f999bdbcd0d7e0e1df04db17e2ac Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jan 2025 20:48:28 +0100
+Subject: wifi: rtl8xxxu: retry firmware download on error
+
+From: Soeren Moch <smoch@web.de>
+
+[ Upstream commit 3d3e28feca7ac8c6cf2a390dbbe1f97e3feb7f36 ]
+
+Occasionally there is an EPROTO error during firmware download.
+This error is converted to EAGAIN in the download function.
+But nobody tries again and so device probe fails.
+
+Implement download retry to fix this.
+
+This error was observed (and fix tested) on a tbs2910 board [1]
+with an embedded RTL8188EU (0bda:8179) device behind a USB hub.
+
+[1] arch/arm/boot/dts/nxp/imx/imx6q-tbs2910.dts
+
+Signed-off-by: Soeren Moch <smoch@web.de>
+Acked-by: Ping-Ke Shih <pkshih@realtek.com>
+Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
+Link: https://patch.msgid.link/20250127194828.599379-1-smoch@web.de
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/realtek/rtl8xxxu/core.c | 17 ++++++++++++-----
+ 1 file changed, 12 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/wireless/realtek/rtl8xxxu/core.c b/drivers/net/wireless/realtek/rtl8xxxu/core.c
+index 4ce0c05c51291..569856ca677f6 100644
+--- a/drivers/net/wireless/realtek/rtl8xxxu/core.c
++++ b/drivers/net/wireless/realtek/rtl8xxxu/core.c
+@@ -860,9 +860,10 @@ rtl8xxxu_writeN(struct rtl8xxxu_priv *priv, u16 addr, u8 *buf, u16 len)
+ return len;
+
+ write_error:
+- dev_info(&udev->dev,
+- "%s: Failed to write block at addr: %04x size: %04x\n",
+- __func__, addr, blocksize);
++ if (rtl8xxxu_debug & RTL8XXXU_DEBUG_REG_WRITE)
++ dev_info(&udev->dev,
++ "%s: Failed to write block at addr: %04x size: %04x\n",
++ __func__, addr, blocksize);
+ return -EAGAIN;
+ }
+
+@@ -4064,8 +4065,14 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw)
+ */
+ rtl8xxxu_write16(priv, REG_TRXFF_BNDY + 2, fops->trxff_boundary);
+
+- ret = rtl8xxxu_download_firmware(priv);
+- dev_dbg(dev, "%s: download_firmware %i\n", __func__, ret);
++ for (int retry = 5; retry >= 0 ; retry--) {
++ ret = rtl8xxxu_download_firmware(priv);
++ dev_dbg(dev, "%s: download_firmware %i\n", __func__, ret);
++ if (ret != -EAGAIN)
++ break;
++ if (retry)
++ dev_dbg(dev, "%s: retry firmware download\n", __func__);
++ }
+ if (ret)
+ goto exit;
+ ret = rtl8xxxu_start_firmware(priv);
+--
+2.39.5
+
--- /dev/null
+From cc1c37af7f080402b6e737231cdcf94a0b1533f6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 26 Jan 2025 16:03:11 +0200
+Subject: wifi: rtw88: Don't use static local variable in
+ rtw8822b_set_tx_power_index_by_rate
+
+From: Bitterblue Smith <rtl8821cerfe2@gmail.com>
+
+[ Upstream commit 00451eb3bec763f708e7e58326468c1e575e5a66 ]
+
+Some users want to plug two identical USB devices at the same time.
+This static variable could theoretically cause them to use incorrect
+TX power values.
+
+Move the variable to the caller and pass a pointer to it to
+rtw8822b_set_tx_power_index_by_rate().
+
+Signed-off-by: Bitterblue Smith <rtl8821cerfe2@gmail.com>
+Acked-by: Ping-Ke Shih <pkshih@realtek.com>
+Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
+Link: https://patch.msgid.link/8a60f581-0ab5-4d98-a97d-dd83b605008f@gmail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/realtek/rtw88/rtw8822b.c | 14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.c b/drivers/net/wireless/realtek/rtw88/rtw8822b.c
+index 7f03903ddf4bb..23a29019752da 100644
+--- a/drivers/net/wireless/realtek/rtw88/rtw8822b.c
++++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.c
+@@ -935,11 +935,11 @@ static void query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status,
+ }
+
+ static void
+-rtw8822b_set_tx_power_index_by_rate(struct rtw_dev *rtwdev, u8 path, u8 rs)
++rtw8822b_set_tx_power_index_by_rate(struct rtw_dev *rtwdev, u8 path,
++ u8 rs, u32 *phy_pwr_idx)
+ {
+ struct rtw_hal *hal = &rtwdev->hal;
+ static const u32 offset_txagc[2] = {0x1d00, 0x1d80};
+- static u32 phy_pwr_idx;
+ u8 rate, rate_idx, pwr_index, shift;
+ int j;
+
+@@ -947,12 +947,12 @@ rtw8822b_set_tx_power_index_by_rate(struct rtw_dev *rtwdev, u8 path, u8 rs)
+ rate = rtw_rate_section[rs][j];
+ pwr_index = hal->tx_pwr_tbl[path][rate];
+ shift = rate & 0x3;
+- phy_pwr_idx |= ((u32)pwr_index << (shift * 8));
++ *phy_pwr_idx |= ((u32)pwr_index << (shift * 8));
+ if (shift == 0x3) {
+ rate_idx = rate & 0xfc;
+ rtw_write32(rtwdev, offset_txagc[path] + rate_idx,
+- phy_pwr_idx);
+- phy_pwr_idx = 0;
++ *phy_pwr_idx);
++ *phy_pwr_idx = 0;
+ }
+ }
+ }
+@@ -960,11 +960,13 @@ rtw8822b_set_tx_power_index_by_rate(struct rtw_dev *rtwdev, u8 path, u8 rs)
+ static void rtw8822b_set_tx_power_index(struct rtw_dev *rtwdev)
+ {
+ struct rtw_hal *hal = &rtwdev->hal;
++ u32 phy_pwr_idx = 0;
+ int rs, path;
+
+ for (path = 0; path < hal->rf_path_num; path++) {
+ for (rs = 0; rs < RTW_RATE_SECTION_MAX; rs++)
+- rtw8822b_set_tx_power_index_by_rate(rtwdev, path, rs);
++ rtw8822b_set_tx_power_index_by_rate(rtwdev, path, rs,
++ &phy_pwr_idx);
+ }
+ }
+
+--
+2.39.5
+
--- /dev/null
+From 5ee42fcba174ed54dd27165c2f558beebe3fbd83 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Feb 2025 20:39:29 +0200
+Subject: wifi: rtw88: Extend rtw_fw_send_ra_info() for RTL8814AU
+
+From: Bitterblue Smith <rtl8821cerfe2@gmail.com>
+
+[ Upstream commit 8f0076726b66a70727a1bef5c087c60291e90ad8 ]
+
+The existing code is suitable for chips with up to 2 spatial streams.
+Inform the firmware about the rates it's allowed to use when
+transmitting 3 spatial streams.
+
+Signed-off-by: Bitterblue Smith <rtl8821cerfe2@gmail.com>
+Acked-by: Ping-Ke Shih <pkshih@realtek.com>
+Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
+Link: https://patch.msgid.link/08e2f328-1aab-4e50-93ac-c1e5dd9541ac@gmail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/realtek/rtw88/fw.c | 15 +++++++++++++++
+ drivers/net/wireless/realtek/rtw88/fw.h | 1 +
+ drivers/net/wireless/realtek/rtw88/main.h | 1 +
+ 3 files changed, 17 insertions(+)
+
+diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c
+index 02389b7c68768..6b563ac489a74 100644
+--- a/drivers/net/wireless/realtek/rtw88/fw.c
++++ b/drivers/net/wireless/realtek/rtw88/fw.c
+@@ -735,6 +735,7 @@ void rtw_fw_send_ra_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si,
+ {
+ u8 h2c_pkt[H2C_PKT_SIZE] = {0};
+ bool disable_pt = true;
++ u32 mask_hi;
+
+ SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_RA_INFO);
+
+@@ -755,6 +756,20 @@ void rtw_fw_send_ra_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si,
+ si->init_ra_lv = 0;
+
+ rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
++
++ if (rtwdev->chip->id != RTW_CHIP_TYPE_8814A)
++ return;
++
++ SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_RA_INFO_HI);
++
++ mask_hi = si->ra_mask >> 32;
++
++ SET_RA_INFO_RA_MASK0(h2c_pkt, (mask_hi & 0xff));
++ SET_RA_INFO_RA_MASK1(h2c_pkt, (mask_hi & 0xff00) >> 8);
++ SET_RA_INFO_RA_MASK2(h2c_pkt, (mask_hi & 0xff0000) >> 16);
++ SET_RA_INFO_RA_MASK3(h2c_pkt, (mask_hi & 0xff000000) >> 24);
++
++ rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
+ }
+
+ void rtw_fw_media_status_report(struct rtw_dev *rtwdev, u8 mac_id, bool connect)
+diff --git a/drivers/net/wireless/realtek/rtw88/fw.h b/drivers/net/wireless/realtek/rtw88/fw.h
+index 404de1b0c407b..48ad9ceab6ea1 100644
+--- a/drivers/net/wireless/realtek/rtw88/fw.h
++++ b/drivers/net/wireless/realtek/rtw88/fw.h
+@@ -557,6 +557,7 @@ static inline void rtw_h2c_pkt_set_header(u8 *h2c_pkt, u8 sub_id)
+ #define H2C_CMD_DEFAULT_PORT 0x2c
+ #define H2C_CMD_RA_INFO 0x40
+ #define H2C_CMD_RSSI_MONITOR 0x42
++#define H2C_CMD_RA_INFO_HI 0x46
+ #define H2C_CMD_BCN_FILTER_OFFLOAD_P0 0x56
+ #define H2C_CMD_BCN_FILTER_OFFLOAD_P1 0x57
+ #define H2C_CMD_WL_PHY_INFO 0x58
+diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h
+index 62cd4c5263019..a61ea853f98d9 100644
+--- a/drivers/net/wireless/realtek/rtw88/main.h
++++ b/drivers/net/wireless/realtek/rtw88/main.h
+@@ -191,6 +191,7 @@ enum rtw_chip_type {
+ RTW_CHIP_TYPE_8703B,
+ RTW_CHIP_TYPE_8821A,
+ RTW_CHIP_TYPE_8812A,
++ RTW_CHIP_TYPE_8814A,
+ };
+
+ enum rtw_tx_queue_type {
+--
+2.39.5
+
--- /dev/null
+From 08ac89be7dab29283ba5921415d55955e3582085 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Feb 2025 20:36:56 +0200
+Subject: wifi: rtw88: Fix __rtw_download_firmware() for RTL8814AU
+
+From: Bitterblue Smith <rtl8821cerfe2@gmail.com>
+
+[ Upstream commit 8425f5c8f04dbcf11ade78f984a494fc0b90e7a0 ]
+
+Don't call ltecoex_read_reg() and ltecoex_reg_write() when the
+ltecoex_addr member of struct rtw_chip_info is NULL. The RTL8814AU
+doesn't have this feature.
+
+Signed-off-by: Bitterblue Smith <rtl8821cerfe2@gmail.com>
+Acked-by: Ping-Ke Shih <pkshih@realtek.com>
+Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
+Link: https://patch.msgid.link/55b5641f-094e-4f94-9f79-ac053733f2cf@gmail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/realtek/rtw88/mac.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/wireless/realtek/rtw88/mac.c b/drivers/net/wireless/realtek/rtw88/mac.c
+index ea6406df42b3d..0491f501c1383 100644
+--- a/drivers/net/wireless/realtek/rtw88/mac.c
++++ b/drivers/net/wireless/realtek/rtw88/mac.c
+@@ -785,7 +785,8 @@ static int __rtw_download_firmware(struct rtw_dev *rtwdev,
+ if (!check_firmware_size(data, size))
+ return -EINVAL;
+
+- if (!ltecoex_read_reg(rtwdev, 0x38, <ecoex_bckp))
++ if (rtwdev->chip->ltecoex_addr &&
++ !ltecoex_read_reg(rtwdev, 0x38, <ecoex_bckp))
+ return -EBUSY;
+
+ wlan_cpu_enable(rtwdev, false);
+@@ -803,7 +804,8 @@ static int __rtw_download_firmware(struct rtw_dev *rtwdev,
+
+ wlan_cpu_enable(rtwdev, true);
+
+- if (!ltecoex_reg_write(rtwdev, 0x38, ltecoex_bckp)) {
++ if (rtwdev->chip->ltecoex_addr &&
++ !ltecoex_reg_write(rtwdev, 0x38, ltecoex_bckp)) {
+ ret = -EBUSY;
+ goto dlfw_fail;
+ }
+--
+2.39.5
+
--- /dev/null
+From 15e97621bb90bc4e5601b10842ba9c8916a67d96 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Feb 2025 20:37:36 +0200
+Subject: wifi: rtw88: Fix download_firmware_validate() for RTL8814AU
+
+From: Bitterblue Smith <rtl8821cerfe2@gmail.com>
+
+[ Upstream commit 9e8243025cc06abc975c876dffda052073207ab3 ]
+
+After the firmware is uploaded, download_firmware_validate() checks some
+bits in REG_MCUFW_CTRL to see if everything went okay. The
+RTL8814AU power on sequence sets bits 13 and 12 to 2, which this
+function does not expect, so it thinks the firmware upload failed.
+
+Make download_firmware_validate() ignore bits 13 and 12.
+
+Signed-off-by: Bitterblue Smith <rtl8821cerfe2@gmail.com>
+Acked-by: Ping-Ke Shih <pkshih@realtek.com>
+Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
+Link: https://patch.msgid.link/049d2887-22fc-47b7-9e59-62627cb525f8@gmail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/realtek/rtw88/reg.h | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/realtek/rtw88/reg.h b/drivers/net/wireless/realtek/rtw88/reg.h
+index e438405fba566..209b6fc08a73e 100644
+--- a/drivers/net/wireless/realtek/rtw88/reg.h
++++ b/drivers/net/wireless/realtek/rtw88/reg.h
+@@ -130,6 +130,7 @@
+ #define BIT_SHIFT_ROM_PGE 16
+ #define BIT_FW_INIT_RDY BIT(15)
+ #define BIT_FW_DW_RDY BIT(14)
++#define BIT_CPU_CLK_SEL (BIT(12) | BIT(13))
+ #define BIT_RPWM_TOGGLE BIT(7)
+ #define BIT_RAM_DL_SEL BIT(7) /* legacy only */
+ #define BIT_DMEM_CHKSUM_OK BIT(6)
+@@ -147,7 +148,7 @@
+ BIT_CHECK_SUM_OK)
+ #define FW_READY_LEGACY (BIT_MCUFWDL_RDY | BIT_FWDL_CHK_RPT | \
+ BIT_WINTINI_RDY | BIT_RAM_DL_SEL)
+-#define FW_READY_MASK 0xffff
++#define FW_READY_MASK (0xffff & ~BIT_CPU_CLK_SEL)
+
+ #define REG_MCU_TST_CFG 0x84
+ #define VAL_FW_TRIGGER 0x1
+--
+2.39.5
+
--- /dev/null
+From a1059fa495d749f16ad67e2f755ee66ecd3caf58 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Feb 2025 01:29:52 +0200
+Subject: wifi: rtw88: Fix rtw_desc_to_mcsrate() to handle MCS16-31
+
+From: Bitterblue Smith <rtl8821cerfe2@gmail.com>
+
+[ Upstream commit 86d04f8f991a0509e318fe886d5a1cf795736c7d ]
+
+This function translates the rate number reported by the hardware into
+something mac80211 can understand. It was ignoring the 3SS and 4SS HT
+rates. Translate them too.
+
+Also set *nss to 0 for the HT rates, just to make sure it's
+initialised.
+
+Signed-off-by: Bitterblue Smith <rtl8821cerfe2@gmail.com>
+Acked-by: Ping-Ke Shih <pkshih@realtek.com>
+Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
+Link: https://patch.msgid.link/d0a5a86b-4869-47f6-a5a7-01c0f987cc7f@gmail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/realtek/rtw88/util.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/realtek/rtw88/util.c b/drivers/net/wireless/realtek/rtw88/util.c
+index e222d3c01a77e..66819f6944055 100644
+--- a/drivers/net/wireless/realtek/rtw88/util.c
++++ b/drivers/net/wireless/realtek/rtw88/util.c
+@@ -101,7 +101,8 @@ void rtw_desc_to_mcsrate(u16 rate, u8 *mcs, u8 *nss)
+ *nss = 4;
+ *mcs = rate - DESC_RATEVHT4SS_MCS0;
+ } else if (rate >= DESC_RATEMCS0 &&
+- rate <= DESC_RATEMCS15) {
++ rate <= DESC_RATEMCS31) {
++ *nss = 0;
+ *mcs = rate - DESC_RATEMCS0;
+ }
+ }
+--
+2.39.5
+
--- /dev/null
+From 6c8e3a86883193e67cf00696dafa04613db635b3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Feb 2025 01:30:22 +0200
+Subject: wifi: rtw88: Fix rtw_init_ht_cap() for RTL8814AU
+
+From: Bitterblue Smith <rtl8821cerfe2@gmail.com>
+
+[ Upstream commit c7eea1ba05ca5b0dbf77a27cf2e1e6e2fb3c0043 ]
+
+Set the RX mask and the highest RX rate according to the number of
+spatial streams the chip can receive. For RTL8814AU that is 3.
+
+Signed-off-by: Bitterblue Smith <rtl8821cerfe2@gmail.com>
+Acked-by: Ping-Ke Shih <pkshih@realtek.com>
+Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
+Link: https://patch.msgid.link/4e786f50-ed1c-4387-8b28-e6ff00e35e81@gmail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/realtek/rtw88/main.c | 17 ++++++-----------
+ 1 file changed, 6 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c
+index d66abb31f091b..f4ee4e922afa7 100644
+--- a/drivers/net/wireless/realtek/rtw88/main.c
++++ b/drivers/net/wireless/realtek/rtw88/main.c
+@@ -1561,6 +1561,7 @@ static void rtw_init_ht_cap(struct rtw_dev *rtwdev,
+ {
+ const struct rtw_chip_info *chip = rtwdev->chip;
+ struct rtw_efuse *efuse = &rtwdev->efuse;
++ int i;
+
+ ht_cap->ht_supported = true;
+ ht_cap->cap = 0;
+@@ -1580,17 +1581,11 @@ static void rtw_init_ht_cap(struct rtw_dev *rtwdev,
+ ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
+ ht_cap->ampdu_density = chip->ampdu_density;
+ ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+- if (efuse->hw_cap.nss > 1) {
+- ht_cap->mcs.rx_mask[0] = 0xFF;
+- ht_cap->mcs.rx_mask[1] = 0xFF;
+- ht_cap->mcs.rx_mask[4] = 0x01;
+- ht_cap->mcs.rx_highest = cpu_to_le16(300);
+- } else {
+- ht_cap->mcs.rx_mask[0] = 0xFF;
+- ht_cap->mcs.rx_mask[1] = 0x00;
+- ht_cap->mcs.rx_mask[4] = 0x01;
+- ht_cap->mcs.rx_highest = cpu_to_le16(150);
+- }
++
++ for (i = 0; i < efuse->hw_cap.nss; i++)
++ ht_cap->mcs.rx_mask[i] = 0xFF;
++ ht_cap->mcs.rx_mask[4] = 0x01;
++ ht_cap->mcs.rx_highest = cpu_to_le16(150 * efuse->hw_cap.nss);
+ }
+
+ static void rtw_init_vht_cap(struct rtw_dev *rtwdev,
+--
+2.39.5
+
--- /dev/null
+From 74f3e0dea164fd71dc382e5c7566500b54065377 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Feb 2025 01:30:48 +0200
+Subject: wifi: rtw88: Fix rtw_init_vht_cap() for RTL8814AU
+
+From: Bitterblue Smith <rtl8821cerfe2@gmail.com>
+
+[ Upstream commit 6be7544d19fcfcb729495e793bc6181f85bb8949 ]
+
+Set the MCS maps and the highest rates according to the number of
+spatial streams the chip has. For RTL8814AU that is 3.
+
+Signed-off-by: Bitterblue Smith <rtl8821cerfe2@gmail.com>
+Acked-by: Ping-Ke Shih <pkshih@realtek.com>
+Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
+Link: https://patch.msgid.link/e86aa009-b5bf-4b3a-8112-ea5e3cd49465@gmail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/realtek/rtw88/main.c | 23 +++++++++--------------
+ 1 file changed, 9 insertions(+), 14 deletions(-)
+
+diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c
+index 0cee0fd8c0ef0..d66abb31f091b 100644
+--- a/drivers/net/wireless/realtek/rtw88/main.c
++++ b/drivers/net/wireless/realtek/rtw88/main.c
+@@ -1597,8 +1597,9 @@ static void rtw_init_vht_cap(struct rtw_dev *rtwdev,
+ struct ieee80211_sta_vht_cap *vht_cap)
+ {
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+- u16 mcs_map;
++ u16 mcs_map = 0;
+ __le16 highest;
++ int i;
+
+ if (efuse->hw_cap.ptcl != EFUSE_HW_CAP_IGNORE &&
+ efuse->hw_cap.ptcl != EFUSE_HW_CAP_PTCL_VHT)
+@@ -1621,21 +1622,15 @@ static void rtw_init_vht_cap(struct rtw_dev *rtwdev,
+ if (rtw_chip_has_rx_ldpc(rtwdev))
+ vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC;
+
+- mcs_map = IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 |
+- IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 |
+- IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 |
+- IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 |
+- IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 |
+- IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 |
+- IEEE80211_VHT_MCS_NOT_SUPPORTED << 14;
+- if (efuse->hw_cap.nss > 1) {
+- highest = cpu_to_le16(780);
+- mcs_map |= IEEE80211_VHT_MCS_SUPPORT_0_9 << 2;
+- } else {
+- highest = cpu_to_le16(390);
+- mcs_map |= IEEE80211_VHT_MCS_NOT_SUPPORTED << 2;
++ for (i = 0; i < 8; i++) {
++ if (i < efuse->hw_cap.nss)
++ mcs_map |= IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2);
++ else
++ mcs_map |= IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2);
+ }
+
++ highest = cpu_to_le16(390 * efuse->hw_cap.nss);
++
+ vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
+ vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
+ vht_cap->vht_mcs.rx_highest = highest;
+--
+2.39.5
+
--- /dev/null
+From d3b0bba30e3237d759262225e5915aa8b4a60eae Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Feb 2025 01:28:59 +0200
+Subject: wifi: rtw88: Fix rtw_mac_power_switch() for RTL8814AU
+
+From: Bitterblue Smith <rtl8821cerfe2@gmail.com>
+
+[ Upstream commit e66bca16638ee59e997f9d9a3711b3ae587d04d9 ]
+
+rtw_mac_power_switch() checks bit 8 of REG_SYS_STATUS1 to see if the
+chip is powered on. This bit appears to be always on in the RTL8814AU,
+so ignore it.
+
+Signed-off-by: Bitterblue Smith <rtl8821cerfe2@gmail.com>
+Acked-by: Ping-Ke Shih <pkshih@realtek.com>
+Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
+Link: https://patch.msgid.link/2f0fcffb-3067-4d95-a68c-f2f3a5a47921@gmail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/realtek/rtw88/mac.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/net/wireless/realtek/rtw88/mac.c b/drivers/net/wireless/realtek/rtw88/mac.c
+index cae9cca6dca3d..ea6406df42b3d 100644
+--- a/drivers/net/wireless/realtek/rtw88/mac.c
++++ b/drivers/net/wireless/realtek/rtw88/mac.c
+@@ -291,6 +291,7 @@ static int rtw_mac_power_switch(struct rtw_dev *rtwdev, bool pwr_on)
+ if (rtw_read8(rtwdev, REG_CR) == 0xea)
+ cur_pwr = false;
+ else if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_USB &&
++ chip->id != RTW_CHIP_TYPE_8814A &&
+ (rtw_read8(rtwdev, REG_SYS_STATUS1 + 1) & BIT(0)))
+ cur_pwr = false;
+ else
+--
+2.39.5
+
--- /dev/null
+From 447dc2002ed22c0b02a9d2aefbded524f0b70215 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Feb 2025 20:42:08 +0200
+Subject: wifi: rtw88: Fix rtw_update_sta_info() for RTL8814AU
+
+From: Bitterblue Smith <rtl8821cerfe2@gmail.com>
+
+[ Upstream commit 9f00e2218e15a2ea3c284567424a100c10b6fb85 ]
+
+This function tells the firmware what rates it can use.
+
+Put the 3SS and 4SS HT rates supported by the other station into the
+rate mask.
+
+Remove the 3SS and 4SS rates from the rate mask if the hardware only has
+2 spatial streams.
+
+And finally, select the right rate ID (a parameter for the firmware)
+when the hardware has 3 spatial streams.
+
+Signed-off-by: Bitterblue Smith <rtl8821cerfe2@gmail.com>
+Acked-by: Ping-Ke Shih <pkshih@realtek.com>
+Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
+Link: https://patch.msgid.link/48d1d90f-2aeb-4ec5-9a24-0980e10eae1e@gmail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/realtek/rtw88/main.c | 14 +++++++++-----
+ 1 file changed, 9 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c
+index f4ee4e922afa7..9b9e76eebce95 100644
+--- a/drivers/net/wireless/realtek/rtw88/main.c
++++ b/drivers/net/wireless/realtek/rtw88/main.c
+@@ -1234,7 +1234,9 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si,
+ if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC)
+ ldpc_en = VHT_LDPC_EN;
+ } else if (sta->deflink.ht_cap.ht_supported) {
+- ra_mask |= (sta->deflink.ht_cap.mcs.rx_mask[1] << 20) |
++ ra_mask |= ((u64)sta->deflink.ht_cap.mcs.rx_mask[3] << 36) |
++ ((u64)sta->deflink.ht_cap.mcs.rx_mask[2] << 28) |
++ (sta->deflink.ht_cap.mcs.rx_mask[1] << 20) |
+ (sta->deflink.ht_cap.mcs.rx_mask[0] << 12);
+ if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)
+ stbc_en = HT_STBC_EN;
+@@ -1244,6 +1246,9 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si,
+
+ if (efuse->hw_cap.nss == 1 || rtwdev->hal.txrx_1ss)
+ ra_mask &= RA_MASK_VHT_RATES_1SS | RA_MASK_HT_RATES_1SS;
++ else if (efuse->hw_cap.nss == 2)
++ ra_mask &= RA_MASK_VHT_RATES_2SS | RA_MASK_HT_RATES_2SS |
++ RA_MASK_VHT_RATES_1SS | RA_MASK_HT_RATES_1SS;
+
+ if (hal->current_band_type == RTW_BAND_5G) {
+ ra_mask |= (u64)sta->deflink.supp_rates[NL80211_BAND_5GHZ] << 4;
+@@ -1302,10 +1307,9 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si,
+ break;
+ }
+
+- if (sta->deflink.vht_cap.vht_supported && ra_mask & 0xffc00000)
+- tx_num = 2;
+- else if (sta->deflink.ht_cap.ht_supported && ra_mask & 0xfff00000)
+- tx_num = 2;
++ if (sta->deflink.vht_cap.vht_supported ||
++ sta->deflink.ht_cap.ht_supported)
++ tx_num = efuse->hw_cap.nss;
+
+ rate_id = get_rate_id(wireless_set, bw_mode, tx_num);
+
+--
+2.39.5
+
--- /dev/null
+From eba55d0778884be93adeabbef487a4f530842ae4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 17 Feb 2025 14:12:35 +0800
+Subject: wifi: rtw89: 8922a: fix incorrect STA-ID in EHT MU PPDU
+
+From: Kuan-Chung Chen <damon.chen@realtek.com>
+
+[ Upstream commit bdce0574243b43b3bb2064f609c0c326df44c4c6 ]
+
+EHT MU PPDU contains user field of EHT-SIG field with STA-ID that
+must match AID subfield in the Associate Response. Add a necessary
+setting to prevent these from being inconsistent.
+
+Signed-off-by: Kuan-Chung Chen <damon.chen@realtek.com>
+Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
+Link: https://patch.msgid.link/20250217061235.32031-1-pkshih@realtek.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/realtek/rtw89/fw.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
+index 92e6bc05cbf66..f4b3438615541 100644
+--- a/drivers/net/wireless/realtek/rtw89/fw.c
++++ b/drivers/net/wireless/realtek/rtw89/fw.c
+@@ -3329,9 +3329,10 @@ int rtw89_fw_h2c_assoc_cmac_tbl_g7(struct rtw89_dev *rtwdev,
+ CCTLINFO_G7_W5_NOMINAL_PKT_PADDING3 |
+ CCTLINFO_G7_W5_NOMINAL_PKT_PADDING4);
+
+- h2c->w6 = le32_encode_bits(vif->type == NL80211_IFTYPE_STATION ? 1 : 0,
++ h2c->w6 = le32_encode_bits(vif->cfg.aid, CCTLINFO_G7_W6_AID12_PAID) |
++ le32_encode_bits(vif->type == NL80211_IFTYPE_STATION ? 1 : 0,
+ CCTLINFO_G7_W6_ULDL);
+- h2c->m6 = cpu_to_le32(CCTLINFO_G7_W6_ULDL);
++ h2c->m6 = cpu_to_le32(CCTLINFO_G7_W6_AID12_PAID | CCTLINFO_G7_W6_ULDL);
+
+ if (rtwsta_link) {
+ h2c->w8 = le32_encode_bits(link_sta->he_cap.has_he,
+--
+2.39.5
+
--- /dev/null
+From 969d27cd411e02f7b2fc63449f4569ab7f9f0a1a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 22 Jan 2025 14:03:01 +0800
+Subject: wifi: rtw89: add wiphy_lock() to work that isn't held wiphy_lock()
+ yet
+
+From: Ping-Ke Shih <pkshih@realtek.com>
+
+[ Upstream commit ebfc9199df05d37b67f4d1b7ee997193f3d2e7c8 ]
+
+To ensure where are protected by driver mutex can also be protected by
+wiphy_lock(), so afterward we can remove driver mutex safely.
+
+Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
+Link: https://patch.msgid.link/20250122060310.31976-2-pkshih@realtek.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/realtek/rtw89/regd.c | 2 ++
+ drivers/net/wireless/realtek/rtw89/ser.c | 4 ++++
+ 2 files changed, 6 insertions(+)
+
+diff --git a/drivers/net/wireless/realtek/rtw89/regd.c b/drivers/net/wireless/realtek/rtw89/regd.c
+index 80b2f74589eb9..5b8d95c90d739 100644
+--- a/drivers/net/wireless/realtek/rtw89/regd.c
++++ b/drivers/net/wireless/realtek/rtw89/regd.c
+@@ -720,6 +720,7 @@ void rtw89_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request
+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+ struct rtw89_dev *rtwdev = hw->priv;
+
++ wiphy_lock(wiphy);
+ mutex_lock(&rtwdev->mutex);
+ rtw89_leave_ps_mode(rtwdev);
+
+@@ -737,6 +738,7 @@ void rtw89_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request
+
+ exit:
+ mutex_unlock(&rtwdev->mutex);
++ wiphy_unlock(wiphy);
+ }
+
+ /* Maximum Transmit Power field (@raw) can be EIRP or PSD.
+diff --git a/drivers/net/wireless/realtek/rtw89/ser.c b/drivers/net/wireless/realtek/rtw89/ser.c
+index 26a944d3b6727..d0c8584308c06 100644
+--- a/drivers/net/wireless/realtek/rtw89/ser.c
++++ b/drivers/net/wireless/realtek/rtw89/ser.c
+@@ -156,9 +156,11 @@ static void ser_state_run(struct rtw89_ser *ser, u8 evt)
+ rtw89_debug(rtwdev, RTW89_DBG_SER, "ser: %s receive %s\n",
+ ser_st_name(ser), ser_ev_name(ser, evt));
+
++ wiphy_lock(rtwdev->hw->wiphy);
+ mutex_lock(&rtwdev->mutex);
+ rtw89_leave_lps(rtwdev);
+ mutex_unlock(&rtwdev->mutex);
++ wiphy_unlock(rtwdev->hw->wiphy);
+
+ ser->st_tbl[ser->state].st_func(ser, evt);
+ }
+@@ -708,9 +710,11 @@ static void ser_l2_reset_st_hdl(struct rtw89_ser *ser, u8 evt)
+
+ switch (evt) {
+ case SER_EV_STATE_IN:
++ wiphy_lock(rtwdev->hw->wiphy);
+ mutex_lock(&rtwdev->mutex);
+ ser_l2_reset_st_pre_hdl(ser);
+ mutex_unlock(&rtwdev->mutex);
++ wiphy_unlock(rtwdev->hw->wiphy);
+
+ ieee80211_restart_hw(rtwdev->hw);
+ ser_set_alarm(ser, SER_RECFG_TIMEOUT, SER_EV_L2_RECFG_TIMEOUT);
+--
+2.39.5
+
--- /dev/null
+From c7d89529f6baa37fb22f34bbefa1d19bac9372e4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Feb 2025 15:29:08 +0800
+Subject: wifi: rtw89: call power_on ahead before selecting firmware
+
+From: Ping-Ke Shih <pkshih@realtek.com>
+
+[ Upstream commit d078f5857a00c06fa0ddee26d3cb722e938e1688 ]
+
+Driver selects firmware by hardware version, which normally can be read
+from registers before selecting firmware. However, certain chips such as
+RTL8851B, it needs to read hardware version from efuse while doing
+power_on, but do power_on after selecting firmware in current flow.
+
+To resolve this flow problem, move power_on out from
+rtw89_mac_partial_init(), and call rtw89_mac_pwr_on() separately at
+proper places to have expected flow.
+
+Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
+Link: https://patch.msgid.link/20250203072911.47313-2-pkshih@realtek.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/realtek/rtw89/core.c | 23 +++++++++++-------
+ drivers/net/wireless/realtek/rtw89/mac.c | 29 ++++++++++++++++-------
+ drivers/net/wireless/realtek/rtw89/mac.h | 1 +
+ 3 files changed, 36 insertions(+), 17 deletions(-)
+
+diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
+index c84446ec9e4f4..422cc3867f3bc 100644
+--- a/drivers/net/wireless/realtek/rtw89/core.c
++++ b/drivers/net/wireless/realtek/rtw89/core.c
+@@ -5086,8 +5086,6 @@ static int rtw89_chip_efuse_info_setup(struct rtw89_dev *rtwdev)
+
+ rtw89_hci_mac_pre_deinit(rtwdev);
+
+- rtw89_mac_pwr_off(rtwdev);
+-
+ return 0;
+ }
+
+@@ -5168,36 +5166,45 @@ int rtw89_chip_info_setup(struct rtw89_dev *rtwdev)
+
+ rtw89_read_chip_ver(rtwdev);
+
++ ret = rtw89_mac_pwr_on(rtwdev);
++ if (ret) {
++ rtw89_err(rtwdev, "failed to power on\n");
++ return ret;
++ }
++
+ ret = rtw89_wait_firmware_completion(rtwdev);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to wait firmware completion\n");
+- return ret;
++ goto out;
+ }
+
+ ret = rtw89_fw_recognize(rtwdev);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to recognize firmware\n");
+- return ret;
++ goto out;
+ }
+
+ ret = rtw89_chip_efuse_info_setup(rtwdev);
+ if (ret)
+- return ret;
++ goto out;
+
+ ret = rtw89_fw_recognize_elements(rtwdev);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to recognize firmware elements\n");
+- return ret;
++ goto out;
+ }
+
+ ret = rtw89_chip_board_info_setup(rtwdev);
+ if (ret)
+- return ret;
++ goto out;
+
+ rtw89_core_setup_rfe_parms(rtwdev);
+ rtwdev->ps_mode = rtw89_update_ps_mode(rtwdev);
+
+- return 0;
++out:
++ rtw89_mac_pwr_off(rtwdev);
++
++ return ret;
+ }
+ EXPORT_SYMBOL(rtw89_chip_info_setup);
+
+diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c
+index 2c74d7781bd40..def12dbfe48d3 100644
+--- a/drivers/net/wireless/realtek/rtw89/mac.c
++++ b/drivers/net/wireless/realtek/rtw89/mac.c
+@@ -1495,6 +1495,21 @@ static int rtw89_mac_power_switch(struct rtw89_dev *rtwdev, bool on)
+ #undef PWR_ACT
+ }
+
++int rtw89_mac_pwr_on(struct rtw89_dev *rtwdev)
++{
++ int ret;
++
++ ret = rtw89_mac_power_switch(rtwdev, true);
++ if (ret) {
++ rtw89_mac_power_switch(rtwdev, false);
++ ret = rtw89_mac_power_switch(rtwdev, true);
++ if (ret)
++ return ret;
++ }
++
++ return 0;
++}
++
+ void rtw89_mac_pwr_off(struct rtw89_dev *rtwdev)
+ {
+ rtw89_mac_power_switch(rtwdev, false);
+@@ -3996,14 +4011,6 @@ int rtw89_mac_partial_init(struct rtw89_dev *rtwdev, bool include_bb)
+ {
+ int ret;
+
+- ret = rtw89_mac_power_switch(rtwdev, true);
+- if (ret) {
+- rtw89_mac_power_switch(rtwdev, false);
+- ret = rtw89_mac_power_switch(rtwdev, true);
+- if (ret)
+- return ret;
+- }
+-
+ rtw89_mac_ctrl_hci_dma_trx(rtwdev, true);
+
+ if (include_bb) {
+@@ -4036,6 +4043,10 @@ int rtw89_mac_init(struct rtw89_dev *rtwdev)
+ bool include_bb = !!chip->bbmcu_nr;
+ int ret;
+
++ ret = rtw89_mac_pwr_on(rtwdev);
++ if (ret)
++ return ret;
++
+ ret = rtw89_mac_partial_init(rtwdev, include_bb);
+ if (ret)
+ goto fail;
+@@ -4067,7 +4078,7 @@ int rtw89_mac_init(struct rtw89_dev *rtwdev)
+
+ return ret;
+ fail:
+- rtw89_mac_power_switch(rtwdev, false);
++ rtw89_mac_pwr_off(rtwdev);
+
+ return ret;
+ }
+diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h
+index 373366a602e0b..71574dbd8764e 100644
+--- a/drivers/net/wireless/realtek/rtw89/mac.h
++++ b/drivers/net/wireless/realtek/rtw89/mac.h
+@@ -1145,6 +1145,7 @@ rtw89_write32_port_set(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_l
+ rtw89_write32_set(rtwdev, reg, bit);
+ }
+
++int rtw89_mac_pwr_on(struct rtw89_dev *rtwdev);
+ void rtw89_mac_pwr_off(struct rtw89_dev *rtwdev);
+ int rtw89_mac_partial_init(struct rtw89_dev *rtwdev, bool include_bb);
+ int rtw89_mac_init(struct rtw89_dev *rtwdev);
+--
+2.39.5
+
--- /dev/null
+From 077b13879e4a2d37ef3548387d77dc5e80b4218b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 10 Jan 2025 09:54:14 +0800
+Subject: wifi: rtw89: coex: Add protect to avoid A2DP lag while Wi-Fi
+ connecting
+
+From: Ching-Te Ku <ku920601@realtek.com>
+
+[ Upstream commit 5251fd321684b591245a072b765d01a6c22a112c ]
+
+To get a well Wi-Fi RF quality, Wi-Fi need to do RF calibrations. While
+Wi-Fi is doing RF calibrations, driver will pause the Bluetooth traffic
+to make sure the RF calibration will not be interfered by Bluetooth.
+However, if the RF calibrations take too much time, Bluetooth audio
+will perform a lag sound. Add a function to make Bluetooth can do
+traffic between the individual calibrations to avoid Bluetooth sound
+lag. And patch related A2DP coexistence mechanism actions.
+
+Signed-off-by: Ching-Te Ku <ku920601@realtek.com>
+Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
+Link: https://patch.msgid.link/20250110015416.10704-2-pkshih@realtek.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/realtek/rtw89/coex.c | 90 +++++++++++--------
+ drivers/net/wireless/realtek/rtw89/coex.h | 2 +
+ drivers/net/wireless/realtek/rtw89/core.h | 3 +-
+ drivers/net/wireless/realtek/rtw89/rtw8851b.c | 6 ++
+ drivers/net/wireless/realtek/rtw89/rtw8852a.c | 6 ++
+ drivers/net/wireless/realtek/rtw89/rtw8852b.c | 6 ++
+ .../net/wireless/realtek/rtw89/rtw8852bt.c | 6 ++
+ drivers/net/wireless/realtek/rtw89/rtw8852c.c | 6 ++
+ 8 files changed, 85 insertions(+), 40 deletions(-)
+
+diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
+index 7b10ee97c6277..86e8f78ec94a4 100644
+--- a/drivers/net/wireless/realtek/rtw89/coex.c
++++ b/drivers/net/wireless/realtek/rtw89/coex.c
+@@ -4587,17 +4587,16 @@ static void _action_bt_a2dp(struct rtw89_dev *rtwdev)
+
+ _set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
+
++ if (a2dp.vendor_id == 0x4c || dm->leak_ap || bt_linfo->slave_role)
++ dm->slot_dur[CXST_W1] = 20;
++ else
++ dm->slot_dur[CXST_W1] = 40;
++
++ dm->slot_dur[CXST_B1] = BTC_B1_MAX;
++
+ switch (btc->cx.state_map) {
+ case BTC_WBUSY_BNOSCAN: /* wl-busy + bt-A2DP */
+- if (a2dp.vendor_id == 0x4c || dm->leak_ap) {
+- dm->slot_dur[CXST_W1] = 40;
+- dm->slot_dur[CXST_B1] = 200;
+- _set_policy(rtwdev,
+- BTC_CXP_PAUTO_TDW1B1, BTC_ACT_BT_A2DP);
+- } else {
+- _set_policy(rtwdev,
+- BTC_CXP_PAUTO_TD50B1, BTC_ACT_BT_A2DP);
+- }
++ _set_policy(rtwdev, BTC_CXP_PAUTO_TDW1B1, BTC_ACT_BT_A2DP);
+ break;
+ case BTC_WBUSY_BSCAN: /* wl-busy + bt-inq + bt-A2DP */
+ _set_policy(rtwdev, BTC_CXP_PAUTO2_TD3050, BTC_ACT_BT_A2DP);
+@@ -4607,15 +4606,10 @@ static void _action_bt_a2dp(struct rtw89_dev *rtwdev)
+ break;
+ case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-A2DP */
+ case BTC_WLINKING: /* wl-connecting + bt-A2DP */
+- if (a2dp.vendor_id == 0x4c || dm->leak_ap) {
+- dm->slot_dur[CXST_W1] = 40;
+- dm->slot_dur[CXST_B1] = 200;
+- _set_policy(rtwdev, BTC_CXP_AUTO_TDW1B1,
+- BTC_ACT_BT_A2DP);
+- } else {
+- _set_policy(rtwdev, BTC_CXP_AUTO_TD50B1,
+- BTC_ACT_BT_A2DP);
+- }
++ if (btc->cx.wl.rfk_info.con_rfk)
++ _set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_BT_A2DP);
++ else
++ _set_policy(rtwdev, BTC_CXP_AUTO_TDW1B1, BTC_ACT_BT_A2DP);
+ break;
+ case BTC_WIDLE: /* wl-idle + bt-A2DP */
+ _set_policy(rtwdev, BTC_CXP_AUTO_TD20B1, BTC_ACT_BT_A2DP);
+@@ -4643,7 +4637,10 @@ static void _action_bt_a2dpsink(struct rtw89_dev *rtwdev)
+ _set_policy(rtwdev, BTC_CXP_FIX_TD2060, BTC_ACT_BT_A2DPSINK);
+ break;
+ case BTC_WLINKING: /* wl-connecting + bt-A2dp_Sink */
+- _set_policy(rtwdev, BTC_CXP_FIX_TD3030, BTC_ACT_BT_A2DPSINK);
++ if (btc->cx.wl.rfk_info.con_rfk)
++ _set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_BT_A2DPSINK);
++ else
++ _set_policy(rtwdev, BTC_CXP_FIX_TD3030, BTC_ACT_BT_A2DPSINK);
+ break;
+ case BTC_WIDLE: /* wl-idle + bt-A2dp_Sink */
+ _set_policy(rtwdev, BTC_CXP_FIX_TD2080, BTC_ACT_BT_A2DPSINK);
+@@ -4697,21 +4694,20 @@ static void _action_bt_a2dp_hid(struct rtw89_dev *rtwdev)
+
+ _set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
+
++ if (a2dp.vendor_id == 0x4c || dm->leak_ap || bt_linfo->slave_role)
++ dm->slot_dur[CXST_W1] = 20;
++ else
++ dm->slot_dur[CXST_W1] = 40;
++
++ dm->slot_dur[CXST_B1] = BTC_B1_MAX;
++
+ switch (btc->cx.state_map) {
+ case BTC_WBUSY_BNOSCAN: /* wl-busy + bt-A2DP+HID */
+ case BTC_WIDLE: /* wl-idle + bt-A2DP */
+- if (a2dp.vendor_id == 0x4c || dm->leak_ap) {
+- dm->slot_dur[CXST_W1] = 40;
+- dm->slot_dur[CXST_B1] = 200;
+- _set_policy(rtwdev,
+- BTC_CXP_PAUTO_TDW1B1, BTC_ACT_BT_A2DP_HID);
+- } else {
+- _set_policy(rtwdev,
+- BTC_CXP_PAUTO_TD50B1, BTC_ACT_BT_A2DP_HID);
+- }
++ _set_policy(rtwdev, BTC_CXP_PAUTO_TDW1B1, BTC_ACT_BT_A2DP_HID);
+ break;
+ case BTC_WBUSY_BSCAN: /* wl-busy + bt-inq + bt-A2DP+HID */
+- _set_policy(rtwdev, BTC_CXP_PAUTO2_TD3050, BTC_ACT_BT_A2DP_HID);
++ _set_policy(rtwdev, BTC_CXP_PAUTO2_TD3070, BTC_ACT_BT_A2DP_HID);
+ break;
+
+ case BTC_WSCAN_BSCAN: /* wl-scan + bt-inq + bt-A2DP+HID */
+@@ -4719,15 +4715,10 @@ static void _action_bt_a2dp_hid(struct rtw89_dev *rtwdev)
+ break;
+ case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-A2DP+HID */
+ case BTC_WLINKING: /* wl-connecting + bt-A2DP+HID */
+- if (a2dp.vendor_id == 0x4c || dm->leak_ap) {
+- dm->slot_dur[CXST_W1] = 40;
+- dm->slot_dur[CXST_B1] = 200;
+- _set_policy(rtwdev, BTC_CXP_AUTO_TDW1B1,
+- BTC_ACT_BT_A2DP_HID);
+- } else {
+- _set_policy(rtwdev, BTC_CXP_AUTO_TD50B1,
+- BTC_ACT_BT_A2DP_HID);
+- }
++ if (btc->cx.wl.rfk_info.con_rfk)
++ _set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_BT_A2DP_HID);
++ else
++ _set_policy(rtwdev, BTC_CXP_AUTO_TDW1B1, BTC_ACT_BT_A2DP_HID);
+ break;
+ }
+ }
+@@ -7001,7 +6992,7 @@ void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason)
+ goto exit;
+ }
+
+- if (wl->status.val & btc_scanning_map.val) {
++ if (wl->status.val & btc_scanning_map.val && !wl->rfk_info.con_rfk) {
+ _action_wl_scan(rtwdev);
+ bt->scan_rx_low_pri = true;
+ goto exit;
+@@ -11040,3 +11031,24 @@ void rtw89_coex_recognize_ver(struct rtw89_dev *rtwdev)
+ rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC] use version def[%d] = 0x%08x\n",
+ (int)(btc->ver - rtw89_btc_ver_defs), btc->ver->fw_ver_code);
+ }
++
++void rtw89_btc_ntfy_preserve_bt_time(struct rtw89_dev *rtwdev, u32 ms)
++{
++ struct rtw89_btc_bt_link_info *bt_linfo = &rtwdev->btc.cx.bt.link_info;
++ struct rtw89_btc_bt_a2dp_desc a2dp = bt_linfo->a2dp_desc;
++
++ if (test_bit(RTW89_FLAG_SER_HANDLING, rtwdev->flags))
++ return;
++
++ if (!a2dp.exist)
++ return;
++
++ fsleep(ms * 1000);
++}
++EXPORT_SYMBOL(rtw89_btc_ntfy_preserve_bt_time);
++
++void rtw89_btc_ntfy_conn_rfk(struct rtw89_dev *rtwdev, bool state)
++{
++ rtwdev->btc.cx.wl.rfk_info.con_rfk = state;
++}
++EXPORT_SYMBOL(rtw89_btc_ntfy_conn_rfk);
+diff --git a/drivers/net/wireless/realtek/rtw89/coex.h b/drivers/net/wireless/realtek/rtw89/coex.h
+index dbdb56e063ef0..757d03675cf4e 100644
+--- a/drivers/net/wireless/realtek/rtw89/coex.h
++++ b/drivers/net/wireless/realtek/rtw89/coex.h
+@@ -290,6 +290,8 @@ void rtw89_coex_power_on(struct rtw89_dev *rtwdev);
+ void rtw89_btc_set_policy(struct rtw89_dev *rtwdev, u16 policy_type);
+ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type);
+ void rtw89_coex_recognize_ver(struct rtw89_dev *rtwdev);
++void rtw89_btc_ntfy_preserve_bt_time(struct rtw89_dev *rtwdev, u32 ms);
++void rtw89_btc_ntfy_conn_rfk(struct rtw89_dev *rtwdev, bool state);
+
+ static inline u8 rtw89_btc_phymap(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx,
+diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
+index c493153ec77b3..963f0046f0bc3 100644
+--- a/drivers/net/wireless/realtek/rtw89/core.h
++++ b/drivers/net/wireless/realtek/rtw89/core.h
+@@ -1762,7 +1762,8 @@ struct rtw89_btc_wl_rfk_info {
+ u32 phy_map: 2;
+ u32 band: 2;
+ u32 type: 8;
+- u32 rsvd: 14;
++ u32 con_rfk: 1;
++ u32 rsvd: 13;
+
+ u32 start_time;
+ u32 proc_time;
+diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c
+index a1df4ba97cd4d..546e88cd46493 100644
+--- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c
++++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c
+@@ -1596,10 +1596,16 @@ static void rtw8851b_rfk_channel(struct rtw89_dev *rtwdev,
+ enum rtw89_chanctx_idx chanctx_idx = rtwvif_link->chanctx_idx;
+ enum rtw89_phy_idx phy_idx = rtwvif_link->phy_idx;
+
++ rtw89_btc_ntfy_conn_rfk(rtwdev, true);
++
+ rtw8851b_rx_dck(rtwdev, phy_idx, chanctx_idx);
+ rtw8851b_iqk(rtwdev, phy_idx, chanctx_idx);
++ rtw89_btc_ntfy_preserve_bt_time(rtwdev, 30);
+ rtw8851b_tssi(rtwdev, phy_idx, true, chanctx_idx);
++ rtw89_btc_ntfy_preserve_bt_time(rtwdev, 30);
+ rtw8851b_dpk(rtwdev, phy_idx, chanctx_idx);
++
++ rtw89_btc_ntfy_conn_rfk(rtwdev, false);
+ }
+
+ static void rtw8851b_rfk_band_changed(struct rtw89_dev *rtwdev,
+diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c
+index cd79a997fe022..e12e5bd402e5b 100644
+--- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c
++++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c
+@@ -1356,10 +1356,16 @@ static void rtw8852a_rfk_channel(struct rtw89_dev *rtwdev,
+ enum rtw89_chanctx_idx chanctx_idx = rtwvif_link->chanctx_idx;
+ enum rtw89_phy_idx phy_idx = rtwvif_link->phy_idx;
+
++ rtw89_btc_ntfy_conn_rfk(rtwdev, true);
++
+ rtw8852a_rx_dck(rtwdev, phy_idx, true, chanctx_idx);
+ rtw8852a_iqk(rtwdev, phy_idx, chanctx_idx);
++ rtw89_btc_ntfy_preserve_bt_time(rtwdev, 30);
+ rtw8852a_tssi(rtwdev, phy_idx, chanctx_idx);
++ rtw89_btc_ntfy_preserve_bt_time(rtwdev, 30);
+ rtw8852a_dpk(rtwdev, phy_idx, chanctx_idx);
++
++ rtw89_btc_ntfy_conn_rfk(rtwdev, false);
+ }
+
+ static void rtw8852a_rfk_band_changed(struct rtw89_dev *rtwdev,
+diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c
+index fcb69fa6cf86d..ab9365b0ec089 100644
+--- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c
++++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c
+@@ -568,10 +568,16 @@ static void rtw8852b_rfk_channel(struct rtw89_dev *rtwdev,
+ enum rtw89_chanctx_idx chanctx_idx = rtwvif_link->chanctx_idx;
+ enum rtw89_phy_idx phy_idx = rtwvif_link->phy_idx;
+
++ rtw89_btc_ntfy_conn_rfk(rtwdev, true);
++
+ rtw8852b_rx_dck(rtwdev, phy_idx, chanctx_idx);
+ rtw8852b_iqk(rtwdev, phy_idx, chanctx_idx);
++ rtw89_btc_ntfy_preserve_bt_time(rtwdev, 30);
+ rtw8852b_tssi(rtwdev, phy_idx, true, chanctx_idx);
++ rtw89_btc_ntfy_preserve_bt_time(rtwdev, 30);
+ rtw8852b_dpk(rtwdev, phy_idx, chanctx_idx);
++
++ rtw89_btc_ntfy_conn_rfk(rtwdev, false);
+ }
+
+ static void rtw8852b_rfk_band_changed(struct rtw89_dev *rtwdev,
+diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c
+index bc740e9abf263..412e633944f37 100644
+--- a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c
++++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c
+@@ -541,10 +541,16 @@ static void rtw8852bt_rfk_channel(struct rtw89_dev *rtwdev,
+ enum rtw89_chanctx_idx chanctx_idx = rtwvif_link->chanctx_idx;
+ enum rtw89_phy_idx phy_idx = rtwvif_link->phy_idx;
+
++ rtw89_btc_ntfy_conn_rfk(rtwdev, true);
++
+ rtw8852bt_rx_dck(rtwdev, phy_idx, chanctx_idx);
+ rtw8852bt_iqk(rtwdev, phy_idx, chanctx_idx);
++ rtw89_btc_ntfy_preserve_bt_time(rtwdev, 30);
+ rtw8852bt_tssi(rtwdev, phy_idx, true, chanctx_idx);
++ rtw89_btc_ntfy_preserve_bt_time(rtwdev, 30);
+ rtw8852bt_dpk(rtwdev, phy_idx, chanctx_idx);
++
++ rtw89_btc_ntfy_conn_rfk(rtwdev, false);
+ }
+
+ static void rtw8852bt_rfk_band_changed(struct rtw89_dev *rtwdev,
+diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
+index 63a2bc88cdbcd..cd68f6cbeecbf 100644
+--- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c
++++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
+@@ -1853,10 +1853,16 @@ static void rtw8852c_rfk_channel(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx = rtwvif_link->phy_idx;
+
+ rtw8852c_mcc_get_ch_info(rtwdev, phy_idx);
++ rtw89_btc_ntfy_conn_rfk(rtwdev, true);
++
+ rtw8852c_rx_dck(rtwdev, phy_idx, false);
+ rtw8852c_iqk(rtwdev, phy_idx, chanctx_idx);
++ rtw89_btc_ntfy_preserve_bt_time(rtwdev, 30);
+ rtw8852c_tssi(rtwdev, phy_idx, chanctx_idx);
++ rtw89_btc_ntfy_preserve_bt_time(rtwdev, 30);
+ rtw8852c_dpk(rtwdev, phy_idx, chanctx_idx);
++
++ rtw89_btc_ntfy_conn_rfk(rtwdev, false);
+ rtw89_fw_h2c_rf_ntfy_mcc(rtwdev);
+ }
+
+--
+2.39.5
+
--- /dev/null
+From 08d709fc50675992488589ab835a99b3b4760ba1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Feb 2025 09:32:31 +0800
+Subject: wifi: rtw89: coex: Assign value over than 0 to avoid firmware timer
+ hang
+
+From: Ching-Te Ku <ku920601@realtek.com>
+
+[ Upstream commit 2e4c4717b3f6f019c71af984564b6e4d0ae8d0bd ]
+
+If the slot duration is 0, the firmware timer will trigger timer hang at
+the timer initializing state in a low rate due to hardware algorithm.
+
+Signed-off-by: Ching-Te Ku <ku920601@realtek.com>
+Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
+Link: https://patch.msgid.link/20250205013233.10945-2-pkshih@realtek.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/realtek/rtw89/coex.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
+index 9e06cc36a75e2..d94a028555e20 100644
+--- a/drivers/net/wireless/realtek/rtw89/coex.c
++++ b/drivers/net/wireless/realtek/rtw89/coex.c
+@@ -89,10 +89,10 @@ static const struct rtw89_btc_fbtc_slot s_def[] = {
+ [CXST_B4] = __DEF_FBTC_SLOT(50, 0xe5555555, SLOT_MIX),
+ [CXST_LK] = __DEF_FBTC_SLOT(20, 0xea5a5a5a, SLOT_ISO),
+ [CXST_BLK] = __DEF_FBTC_SLOT(500, 0x55555555, SLOT_MIX),
+- [CXST_E2G] = __DEF_FBTC_SLOT(0, 0xea5a5a5a, SLOT_MIX),
+- [CXST_E5G] = __DEF_FBTC_SLOT(0, 0xffffffff, SLOT_ISO),
++ [CXST_E2G] = __DEF_FBTC_SLOT(5, 0xea5a5a5a, SLOT_MIX),
++ [CXST_E5G] = __DEF_FBTC_SLOT(5, 0xffffffff, SLOT_ISO),
+ [CXST_EBT] = __DEF_FBTC_SLOT(5, 0xe5555555, SLOT_MIX),
+- [CXST_ENULL] = __DEF_FBTC_SLOT(0, 0xaaaaaaaa, SLOT_ISO),
++ [CXST_ENULL] = __DEF_FBTC_SLOT(5, 0xaaaaaaaa, SLOT_ISO),
+ [CXST_WLK] = __DEF_FBTC_SLOT(250, 0xea5a5a5a, SLOT_MIX),
+ [CXST_W1FDD] = __DEF_FBTC_SLOT(50, 0xffffffff, SLOT_ISO),
+ [CXST_B1FDD] = __DEF_FBTC_SLOT(50, 0xffffdfff, SLOT_ISO),
+--
+2.39.5
+
--- /dev/null
+From 4d139cd5c91c8e377e02d1d3a43a5e97a4c043a9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 8 Mar 2025 10:58:30 +0800
+Subject: wifi: rtw89: coex: Fix coexistence report not show as expected
+
+From: Ching-Te Ku <ku920601@realtek.com>
+
+[ Upstream commit a36230aa5f5efceaf5f81682673732a921b91518 ]
+
+This report will feedback some basic information from firmware(PTA counter,
+report counter, mailbox counter etc). And the report version need to match
+driver & firmware both side. The original logic break the switch case logic
+before driver update the report version. It made the report can not be
+parsed correctly. Delete the break at the version 7 and 8.
+Add logic to count C2H event report.
+
+Signed-off-by: Ching-Te Ku <ku920601@realtek.com>
+Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
+Link: https://patch.msgid.link/20250308025832.10400-3-pkshih@realtek.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/realtek/rtw89/coex.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
+index 68316d44b2043..9e06cc36a75e2 100644
+--- a/drivers/net/wireless/realtek/rtw89/coex.c
++++ b/drivers/net/wireless/realtek/rtw89/coex.c
+@@ -1372,11 +1372,9 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
+ } else if (ver->fcxbtcrpt == 8) {
+ pfinfo = &pfwinfo->rpt_ctrl.finfo.v8;
+ pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v8);
+- break;
+ } else if (ver->fcxbtcrpt == 7) {
+ pfinfo = &pfwinfo->rpt_ctrl.finfo.v7;
+ pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v7);
+- break;
+ } else {
+ goto err;
+ }
+@@ -8115,6 +8113,7 @@ void rtw89_btc_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb,
+ return;
+
+ func = rtw89_btc_c2h_get_index_by_ver(rtwdev, func);
++ pfwinfo->cnt_c2h++;
+
+ switch (func) {
+ case BTF_EVNT_BUF_OVERFLOW:
+--
+2.39.5
+
--- /dev/null
+From 17e516cfa51c9ed2d81caa000123416b6ae0e685 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 10 Jan 2025 09:54:15 +0800
+Subject: wifi: rtw89: coex: Separated Wi-Fi connecting event from Wi-Fi scan
+ event
+
+From: Ching-Te Ku <ku920601@realtek.com>
+
+[ Upstream commit 4a57346652154bb339c48b41166df9154cff33f5 ]
+
+Wi-Fi connecting process don't need to assign to firmware slot control,
+if assign firmware slot control for Wi-Fi connecting event, firmware will
+not toggle slots because driver don't tell the slot schedule to firmware.
+Wi-Fi connecting event end should also cancel the 4way handshake status.
+
+Signed-off-by: Ching-Te Ku <ku920601@realtek.com>
+Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
+Link: https://patch.msgid.link/20250110015416.10704-3-pkshih@realtek.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/realtek/rtw89/coex.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
+index d94a028555e20..7b10ee97c6277 100644
+--- a/drivers/net/wireless/realtek/rtw89/coex.c
++++ b/drivers/net/wireless/realtek/rtw89/coex.c
+@@ -5406,7 +5406,8 @@ static void _action_wl_scan(struct rtw89_dev *rtwdev)
+ struct rtw89_btc_wl_info *wl = &btc->cx.wl;
+ struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info;
+
+- if (RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD, &rtwdev->fw)) {
++ if (btc->cx.state_map != BTC_WLINKING &&
++ RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD, &rtwdev->fw)) {
+ _action_wl_25g_mcc(rtwdev);
+ rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], Scan offload!\n");
+ } else if (rtwdev->dbcc_en) {
+@@ -7221,6 +7222,8 @@ void rtw89_btc_ntfy_scan_finish(struct rtw89_dev *rtwdev, u8 phy_idx)
+ _fw_set_drv_info(rtwdev, CXDRVINFO_DBCC);
+ }
+
++ btc->dm.tdma_instant_excute = 1;
++
+ _run_coex(rtwdev, BTC_RSN_NTFY_SCAN_FINISH);
+ }
+
+@@ -7669,7 +7672,8 @@ void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev,
+ else
+ wl->status.map.connecting = 0;
+
+- if (state == BTC_ROLE_MSTS_STA_DIS_CONN)
++ if (state == BTC_ROLE_MSTS_STA_DIS_CONN ||
++ state == BTC_ROLE_MSTS_STA_CONN_END)
+ wl->status.map._4way = false;
+
+ _run_coex(rtwdev, BTC_RSN_NTFY_ROLE_INFO);
+--
+2.39.5
+
--- /dev/null
+From 7873bb14b5fc355d74255892d090d1d87b87ea34 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 17 Feb 2025 14:43:04 +0800
+Subject: wifi: rtw89: fw: add blacklist to avoid obsolete secure firmware
+
+From: Ping-Ke Shih <pkshih@realtek.com>
+
+[ Upstream commit f11d042b3a2e92ab1aa10e0da8e290bcdcf31d39 ]
+
+To ensure secure chip only runs expected secure firmware, stop using
+obsolete firmware in blacklist which weakness or flaw was found.
+
+Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
+Link: https://patch.msgid.link/20250217064308.43559-2-pkshih@realtek.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/realtek/rtw89/core.h | 2 +
+ drivers/net/wireless/realtek/rtw89/fw.c | 52 ++++++++++++++++++-
+ drivers/net/wireless/realtek/rtw89/fw.h | 12 +++++
+ drivers/net/wireless/realtek/rtw89/rtw8851b.c | 1 +
+ drivers/net/wireless/realtek/rtw89/rtw8852a.c | 1 +
+ drivers/net/wireless/realtek/rtw89/rtw8852b.c | 1 +
+ .../net/wireless/realtek/rtw89/rtw8852bt.c | 1 +
+ drivers/net/wireless/realtek/rtw89/rtw8852c.c | 1 +
+ drivers/net/wireless/realtek/rtw89/rtw8922a.c | 1 +
+ 9 files changed, 71 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
+index 979587e92c849..c493153ec77b3 100644
+--- a/drivers/net/wireless/realtek/rtw89/core.h
++++ b/drivers/net/wireless/realtek/rtw89/core.h
+@@ -17,6 +17,7 @@ struct rtw89_dev;
+ struct rtw89_pci_info;
+ struct rtw89_mac_gen_def;
+ struct rtw89_phy_gen_def;
++struct rtw89_fw_blacklist;
+ struct rtw89_efuse_block_cfg;
+ struct rtw89_h2c_rf_tssi;
+ struct rtw89_fw_txpwr_track_cfg;
+@@ -4251,6 +4252,7 @@ struct rtw89_chip_info {
+ bool try_ce_fw;
+ u8 bbmcu_nr;
+ u32 needed_fw_elms;
++ const struct rtw89_fw_blacklist *fw_blacklist;
+ u32 fifo_size;
+ bool small_fifo_size;
+ u32 dle_scc_rsvd_size;
+diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
+index 3164ff69803a1..92e6bc05cbf66 100644
+--- a/drivers/net/wireless/realtek/rtw89/fw.c
++++ b/drivers/net/wireless/realtek/rtw89/fw.c
+@@ -38,6 +38,16 @@ struct rtw89_arp_rsp {
+
+ static const u8 mss_signature[] = {0x4D, 0x53, 0x53, 0x4B, 0x50, 0x4F, 0x4F, 0x4C};
+
++const struct rtw89_fw_blacklist rtw89_fw_blacklist_default = {
++ .ver = 0x00,
++ .list = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
++ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
++ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
++ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
++ },
++};
++EXPORT_SYMBOL(rtw89_fw_blacklist_default);
++
+ union rtw89_fw_element_arg {
+ size_t offset;
+ enum rtw89_rf_path rf_path;
+@@ -344,6 +354,46 @@ static int __parse_formatted_mssc(struct rtw89_dev *rtwdev,
+ return 0;
+ }
+
++static int __check_secure_blacklist(struct rtw89_dev *rtwdev,
++ struct rtw89_fw_bin_info *info,
++ struct rtw89_fw_hdr_section_info *section_info,
++ const void *content)
++{
++ const struct rtw89_fw_blacklist *chip_blacklist = rtwdev->chip->fw_blacklist;
++ const union rtw89_fw_section_mssc_content *section_content = content;
++ struct rtw89_fw_secure *sec = &rtwdev->fw.sec;
++ u8 byte_idx;
++ u8 bit_mask;
++
++ if (!sec->secure_boot)
++ return 0;
++
++ if (!info->secure_section_exist || section_info->ignore)
++ return 0;
++
++ if (!chip_blacklist) {
++ rtw89_err(rtwdev, "chip no blacklist for secure firmware\n");
++ return -ENOENT;
++ }
++
++ byte_idx = section_content->blacklist.bit_in_chip_list >> 3;
++ bit_mask = BIT(section_content->blacklist.bit_in_chip_list & 0x7);
++
++ if (section_content->blacklist.ver > chip_blacklist->ver) {
++ rtw89_err(rtwdev, "chip blacklist out of date (%u, %u)\n",
++ section_content->blacklist.ver, chip_blacklist->ver);
++ return -EINVAL;
++ }
++
++ if (chip_blacklist->list[byte_idx] & bit_mask) {
++ rtw89_err(rtwdev, "firmware %u in chip blacklist\n",
++ section_content->blacklist.ver);
++ return -EPERM;
++ }
++
++ return 0;
++}
++
+ static int __parse_security_section(struct rtw89_dev *rtwdev,
+ struct rtw89_fw_bin_info *info,
+ struct rtw89_fw_hdr_section_info *section_info,
+@@ -374,7 +424,7 @@ static int __parse_security_section(struct rtw89_dev *rtwdev,
+ info->secure_section_exist = true;
+ }
+
+- return 0;
++ return __check_secure_blacklist(rtwdev, info, section_info, content);
+ }
+
+ static int rtw89_fw_hdr_parser_v1(struct rtw89_dev *rtwdev, const u8 *fw, u32 len,
+diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
+index 2026bc2fd2acd..ee2be09bd3dbd 100644
+--- a/drivers/net/wireless/realtek/rtw89/fw.h
++++ b/drivers/net/wireless/realtek/rtw89/fw.h
+@@ -663,6 +663,11 @@ struct rtw89_fw_mss_pool_hdr {
+ } __packed;
+
+ union rtw89_fw_section_mssc_content {
++ struct {
++ u8 pad[0x20];
++ u8 bit_in_chip_list;
++ u8 ver;
++ } __packed blacklist;
+ struct {
+ u8 pad[58];
+ __le32 v;
+@@ -673,6 +678,13 @@ union rtw89_fw_section_mssc_content {
+ } __packed key_sign_len;
+ } __packed;
+
++struct rtw89_fw_blacklist {
++ u8 ver;
++ u8 list[32];
++};
++
++extern const struct rtw89_fw_blacklist rtw89_fw_blacklist_default;
++
+ static inline void SET_CTRL_INFO_MACID(void *table, u32 val)
+ {
+ le32p_replace_bits((__le32 *)(table) + 0, val, GENMASK(6, 0));
+diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c
+index 24d48aced57ac..a1df4ba97cd4d 100644
+--- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c
++++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c
+@@ -2445,6 +2445,7 @@ const struct rtw89_chip_info rtw8851b_chip_info = {
+ .try_ce_fw = true,
+ .bbmcu_nr = 0,
+ .needed_fw_elms = 0,
++ .fw_blacklist = NULL,
+ .fifo_size = 196608,
+ .small_fifo_size = true,
+ .dle_scc_rsvd_size = 98304,
+diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c
+index eeb40a60c2b98..cd79a997fe022 100644
+--- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c
++++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c
+@@ -2162,6 +2162,7 @@ const struct rtw89_chip_info rtw8852a_chip_info = {
+ .try_ce_fw = false,
+ .bbmcu_nr = 0,
+ .needed_fw_elms = 0,
++ .fw_blacklist = NULL,
+ .fifo_size = 458752,
+ .small_fifo_size = false,
+ .dle_scc_rsvd_size = 0,
+diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c
+index 4335fa85c334b..fcb69fa6cf86d 100644
+--- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c
++++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c
+@@ -798,6 +798,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = {
+ .try_ce_fw = true,
+ .bbmcu_nr = 0,
+ .needed_fw_elms = 0,
++ .fw_blacklist = &rtw89_fw_blacklist_default,
+ .fifo_size = 196608,
+ .small_fifo_size = true,
+ .dle_scc_rsvd_size = 98304,
+diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c
+index 7f64a5695486b..bc740e9abf263 100644
+--- a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c
++++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c
+@@ -732,6 +732,7 @@ const struct rtw89_chip_info rtw8852bt_chip_info = {
+ .try_ce_fw = true,
+ .bbmcu_nr = 0,
+ .needed_fw_elms = RTW89_AX_GEN_DEF_NEEDED_FW_ELEMENTS_NO_6GHZ,
++ .fw_blacklist = &rtw89_fw_blacklist_default,
+ .fifo_size = 458752,
+ .small_fifo_size = true,
+ .dle_scc_rsvd_size = 98304,
+diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
+index 9778621d9bc41..63a2bc88cdbcd 100644
+--- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c
++++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
+@@ -2954,6 +2954,7 @@ const struct rtw89_chip_info rtw8852c_chip_info = {
+ .try_ce_fw = false,
+ .bbmcu_nr = 0,
+ .needed_fw_elms = 0,
++ .fw_blacklist = &rtw89_fw_blacklist_default,
+ .fifo_size = 458752,
+ .small_fifo_size = false,
+ .dle_scc_rsvd_size = 0,
+diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c
+index 731bc6f18d38b..2696fdf350f63 100644
+--- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c
++++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c
+@@ -2721,6 +2721,7 @@ const struct rtw89_chip_info rtw8922a_chip_info = {
+ .try_ce_fw = false,
+ .bbmcu_nr = 1,
+ .needed_fw_elms = RTW89_BE_GEN_DEF_NEEDED_FW_ELEMENTS,
++ .fw_blacklist = &rtw89_fw_blacklist_default,
+ .fifo_size = 589824,
+ .small_fifo_size = false,
+ .dle_scc_rsvd_size = 0,
+--
+2.39.5
+
--- /dev/null
+From 156150c1a836d95a1a2849a74918ede35d0c9498 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 17 Feb 2025 14:43:05 +0800
+Subject: wifi: rtw89: fw: get sb_sel_ver via get_unaligned_le32()
+
+From: Ping-Ke Shih <pkshih@realtek.com>
+
+[ Upstream commit 2f9da853f4d848d23bade4c22931ea0f5a011674 ]
+
+The sb_sel_ver is selection version for secure boot recorded in firmware
+binary data, and its size is 4 and offset is 58 (not natural alignment).
+Use get_unaligned_le32() to get this value safely. Find this by reviewing.
+
+Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
+Link: https://patch.msgid.link/20250217064308.43559-3-pkshih@realtek.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/realtek/rtw89/fw.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
+index 4727eeb55b486..3164ff69803a1 100644
+--- a/drivers/net/wireless/realtek/rtw89/fw.c
++++ b/drivers/net/wireless/realtek/rtw89/fw.c
+@@ -314,7 +314,7 @@ static int __parse_formatted_mssc(struct rtw89_dev *rtwdev,
+ if (!sec->secure_boot)
+ goto out;
+
+- sb_sel_ver = le32_to_cpu(section_content->sb_sel_ver.v);
++ sb_sel_ver = get_unaligned_le32(§ion_content->sb_sel_ver.v);
+ if (sb_sel_ver && sb_sel_ver != sec->sb_sel_mgn)
+ goto ignore;
+
+--
+2.39.5
+
--- /dev/null
+From 57d3696f52e93d3871f6c4d23c4ea316a5e09c66 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 17 Feb 2025 14:43:06 +0800
+Subject: wifi: rtw89: fw: propagate error code from rtw89_h2c_tx()
+
+From: Ping-Ke Shih <pkshih@realtek.com>
+
+[ Upstream commit 56e1acaa0f80620b8e2c3410db35b4b975782b0a ]
+
+The error code should be propagated to callers during downloading firmware
+header and body. Remove unnecessary assignment of -1.
+
+Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
+Link: https://patch.msgid.link/20250217064308.43559-4-pkshih@realtek.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/realtek/rtw89/fw.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
+index 2f3869c700696..4727eeb55b486 100644
+--- a/drivers/net/wireless/realtek/rtw89/fw.c
++++ b/drivers/net/wireless/realtek/rtw89/fw.c
+@@ -1322,7 +1322,6 @@ static int __rtw89_fw_download_hdr(struct rtw89_dev *rtwdev,
+ ret = rtw89_h2c_tx(rtwdev, skb, false);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to send h2c\n");
+- ret = -1;
+ goto fail;
+ }
+
+@@ -1409,7 +1408,6 @@ static int __rtw89_fw_download_main(struct rtw89_dev *rtwdev,
+ ret = rtw89_h2c_tx(rtwdev, skb, true);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to send h2c\n");
+- ret = -1;
+ goto fail;
+ }
+
+--
+2.39.5
+
--- /dev/null
+From 602a36a06df1539b937d49289fe4646ea26f734b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Feb 2025 15:29:11 +0800
+Subject: wifi: rtw89: fw: validate multi-firmware header before getting its
+ size
+
+From: Ping-Ke Shih <pkshih@realtek.com>
+
+[ Upstream commit 2b8bdc5237014cc61784b3676cbaca5325959f3d ]
+
+To access firmware elements appended after multi-firmware, add its size
+as offset to get start address of firmware elements.
+
+ +-----+-------+------+---------+--------------+ --
+ | sig | fw_nr | rsvd | version | reserved | \
+ +---------------------------------------------+ |
+ fw 0 | cv | type | mp | rsvd | shift | size | rsvd | |
+ +---------------------------------------------+ |
+ fw 1 | cv | type | mp | rsvd | shift | size | rsvd | |
+ +---------------------------------------------+ |
+ fw N-1 | ... | |
+ +=============================================+ | mfw size
+ | fw 0 content | |
+ +=============================================+ |
+ | fw 1 content | |
+ +=============================================+ |
+ | ... | |
+ +=============================================+ |
+ | fw N -1 content | |
+ +=============================================+ --/
+ | fw element TLV X |
+ +=============================================+
+ | fw element TLV Y |
+ +=============================================+
+ | fw element TLV Z |
+ +=============================================+
+
+To avoid Coverity warning when getting mfw size, validate it header ahead.
+
+Addresses-Coverity-ID: 1544385 ("Untrusted array index read")
+
+Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
+Link: https://patch.msgid.link/20250203072911.47313-5-pkshih@realtek.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/realtek/rtw89/fw.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
+index f4b3438615541..aed0647955d8e 100644
+--- a/drivers/net/wireless/realtek/rtw89/fw.c
++++ b/drivers/net/wireless/realtek/rtw89/fw.c
+@@ -601,12 +601,17 @@ static u32 rtw89_mfw_get_size(struct rtw89_dev *rtwdev)
+ (const struct rtw89_mfw_hdr *)firmware->data;
+ const struct rtw89_mfw_info *mfw_info;
+ u32 size;
++ int ret;
+
+ if (mfw_hdr->sig != RTW89_MFW_SIG) {
+ rtw89_warn(rtwdev, "not mfw format\n");
+ return 0;
+ }
+
++ ret = rtw89_mfw_validate_hdr(rtwdev, firmware, mfw_hdr);
++ if (ret)
++ return ret;
++
+ mfw_info = &mfw_hdr->info[mfw_hdr->fw_nr - 1];
+ size = le32_to_cpu(mfw_info->shift) + le32_to_cpu(mfw_info->size);
+
+--
+2.39.5
+
--- /dev/null
+From 279c639077ee54c3542ea9d54a9b4745a20bf41a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Feb 2025 15:29:10 +0800
+Subject: wifi: rtw89: fw: validate multi-firmware header before accessing
+
+From: Ping-Ke Shih <pkshih@realtek.com>
+
+[ Upstream commit 1f0efffd597893404aea5c3d4f1bdaa1c61d4434 ]
+
+A firmeware file contains multi-firmware with a header to represent
+contents. The mfw_hdr->fw_nr is to define number of firmware in file.
+
+ +-----+-------+------+---------+--------------+
+ | sig | fw_nr | rsvd | version | reserved |
+ +---------------------------------------------+ --
+ fw 0 | cv | type | mp | rsvd | shift | size | rsvd | \
+ +---------------------------------------------+ |
+ fw 1 | cv | type | mp | rsvd | shift | size | rsvd | | mfw_hdr->fw_nr
+ +---------------------------------------------+ |
+ fw N-1 | ... | /
+ +=============================================+ --
+ | fw 0 content |
+ | (pointed by fw0 shift/size) |
+ +=============================================+
+
+To avoid Coverity warning, validate header is in range of firmware size,
+and also validate the range of actual firmware content is in range.
+
+Addresses-Coverity-ID: 1494046 ("Untrusted loop bound")
+
+Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
+Link: https://patch.msgid.link/20250203072911.47313-4-pkshih@realtek.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/realtek/rtw89/fw.c | 35 +++++++++++++++++++++++++
+ 1 file changed, 35 insertions(+)
+
+diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
+index aed0647955d8e..1fbcba718998f 100644
+--- a/drivers/net/wireless/realtek/rtw89/fw.c
++++ b/drivers/net/wireless/realtek/rtw89/fw.c
+@@ -539,6 +539,30 @@ static int rtw89_fw_hdr_parser(struct rtw89_dev *rtwdev,
+ }
+ }
+
++static int rtw89_mfw_validate_hdr(struct rtw89_dev *rtwdev,
++ const struct firmware *firmware,
++ const struct rtw89_mfw_hdr *mfw_hdr)
++{
++ const void *mfw = firmware->data;
++ u32 mfw_len = firmware->size;
++ u8 fw_nr = mfw_hdr->fw_nr;
++ const void *ptr;
++
++ if (fw_nr == 0) {
++ rtw89_err(rtwdev, "mfw header has no fw entry\n");
++ return -ENOENT;
++ }
++
++ ptr = &mfw_hdr->info[fw_nr];
++
++ if (ptr > mfw + mfw_len) {
++ rtw89_err(rtwdev, "mfw header out of address\n");
++ return -EFAULT;
++ }
++
++ return 0;
++}
++
+ static
+ int rtw89_mfw_recognize(struct rtw89_dev *rtwdev, enum rtw89_fw_type type,
+ struct rtw89_fw_suit *fw_suit, bool nowarn)
+@@ -549,6 +573,7 @@ int rtw89_mfw_recognize(struct rtw89_dev *rtwdev, enum rtw89_fw_type type,
+ u32 mfw_len = firmware->size;
+ const struct rtw89_mfw_hdr *mfw_hdr = (const struct rtw89_mfw_hdr *)mfw;
+ const struct rtw89_mfw_info *mfw_info = NULL, *tmp;
++ int ret;
+ int i;
+
+ if (mfw_hdr->sig != RTW89_MFW_SIG) {
+@@ -561,6 +586,10 @@ int rtw89_mfw_recognize(struct rtw89_dev *rtwdev, enum rtw89_fw_type type,
+ return 0;
+ }
+
++ ret = rtw89_mfw_validate_hdr(rtwdev, firmware, mfw_hdr);
++ if (ret)
++ return ret;
++
+ for (i = 0; i < mfw_hdr->fw_nr; i++) {
+ tmp = &mfw_hdr->info[i];
+ if (tmp->type != type)
+@@ -590,6 +619,12 @@ int rtw89_mfw_recognize(struct rtw89_dev *rtwdev, enum rtw89_fw_type type,
+ found:
+ fw_suit->data = mfw + le32_to_cpu(mfw_info->shift);
+ fw_suit->size = le32_to_cpu(mfw_info->size);
++
++ if (fw_suit->data + fw_suit->size > mfw + mfw_len) {
++ rtw89_err(rtwdev, "fw_suit %d out of address\n", type);
++ return -EFAULT;
++ }
++
+ return 0;
+ }
+
+--
+2.39.5
+
--- /dev/null
+From 8fa7acc8503f8b18bc832a80eeea40b29e7b57e6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 20 Feb 2025 14:43:57 +0800
+Subject: wifi: rtw89: Parse channel from IE to correct invalid hardware
+ reports during scanning
+
+From: Chih-Kang Chang <gary.chang@realtek.com>
+
+[ Upstream commit e16acf907a3c66b9996a5df43e177a5edec8e0a5 ]
+
+For some packets, we could not get channel information from PPDU status.
+And this causes wrong frequencies being reported. Parse the channel
+information from IE if provided by AP to fix this.
+
+Signed-off-by: Chih-Kang Chang <gary.chang@realtek.com>
+Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
+Link: https://patch.msgid.link/20250220064357.17962-1-pkshih@realtek.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/realtek/rtw89/core.c | 44 +++++++++++++++++++
+ drivers/net/wireless/realtek/rtw89/core.h | 1 +
+ drivers/net/wireless/realtek/rtw89/rtw8851b.c | 1 +
+ drivers/net/wireless/realtek/rtw89/rtw8852a.c | 1 +
+ drivers/net/wireless/realtek/rtw89/rtw8852b.c | 1 +
+ .../net/wireless/realtek/rtw89/rtw8852bt.c | 1 +
+ drivers/net/wireless/realtek/rtw89/rtw8852c.c | 1 +
+ drivers/net/wireless/realtek/rtw89/rtw8922a.c | 1 +
+ 8 files changed, 51 insertions(+)
+
+diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
+index 85f739f1173d8..c84446ec9e4f4 100644
+--- a/drivers/net/wireless/realtek/rtw89/core.c
++++ b/drivers/net/wireless/realtek/rtw89/core.c
+@@ -2381,6 +2381,49 @@ static void rtw89_core_validate_rx_signal(struct ieee80211_rx_status *rx_status)
+ rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;
+ }
+
++static void rtw89_core_update_rx_freq_from_ie(struct rtw89_dev *rtwdev,
++ struct sk_buff *skb,
++ struct ieee80211_rx_status *rx_status)
++{
++ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
++ size_t hdr_len, ielen;
++ u8 *variable;
++ int chan;
++
++ if (!rtwdev->chip->rx_freq_frome_ie)
++ return;
++
++ if (!rtwdev->scanning)
++ return;
++
++ if (ieee80211_is_beacon(mgmt->frame_control)) {
++ variable = mgmt->u.beacon.variable;
++ hdr_len = offsetof(struct ieee80211_mgmt,
++ u.beacon.variable);
++ } else if (ieee80211_is_probe_resp(mgmt->frame_control)) {
++ variable = mgmt->u.probe_resp.variable;
++ hdr_len = offsetof(struct ieee80211_mgmt,
++ u.probe_resp.variable);
++ } else {
++ return;
++ }
++
++ if (skb->len > hdr_len)
++ ielen = skb->len - hdr_len;
++ else
++ return;
++
++ /* The parsing code for both 2GHz and 5GHz bands is the same in this
++ * function.
++ */
++ chan = cfg80211_get_ies_channel_number(variable, ielen, NL80211_BAND_2GHZ);
++ if (chan == -1)
++ return;
++
++ rx_status->band = chan > 14 ? RTW89_BAND_5G : RTW89_BAND_2G;
++ rx_status->freq = ieee80211_channel_to_frequency(chan, rx_status->band);
++}
++
+ static void rtw89_core_rx_to_mac80211(struct rtw89_dev *rtwdev,
+ struct rtw89_rx_phy_ppdu *phy_ppdu,
+ struct rtw89_rx_desc_info *desc_info,
+@@ -2398,6 +2441,7 @@ static void rtw89_core_rx_to_mac80211(struct rtw89_dev *rtwdev,
+ rtw89_core_update_rx_status_by_ppdu(rtwdev, rx_status, phy_ppdu);
+ rtw89_core_update_radiotap(rtwdev, skb_ppdu, rx_status);
+ rtw89_core_validate_rx_signal(rx_status);
++ rtw89_core_update_rx_freq_from_ie(rtwdev, skb_ppdu, rx_status);
+
+ /* In low power mode, it does RX in thread context. */
+ local_bh_disable();
+diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
+index 93e41def81b40..979587e92c849 100644
+--- a/drivers/net/wireless/realtek/rtw89/core.h
++++ b/drivers/net/wireless/realtek/rtw89/core.h
+@@ -4273,6 +4273,7 @@ struct rtw89_chip_info {
+ bool support_ant_gain;
+ bool ul_tb_waveform_ctrl;
+ bool ul_tb_pwr_diff;
++ bool rx_freq_frome_ie;
+ bool hw_sec_hdr;
+ bool hw_mgmt_tx_encrypt;
+ u8 rf_path_num;
+diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c
+index c56f70267882a..24d48aced57ac 100644
+--- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c
++++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c
+@@ -2485,6 +2485,7 @@ const struct rtw89_chip_info rtw8851b_chip_info = {
+ .support_ant_gain = false,
+ .ul_tb_waveform_ctrl = true,
+ .ul_tb_pwr_diff = false,
++ .rx_freq_frome_ie = true,
+ .hw_sec_hdr = false,
+ .hw_mgmt_tx_encrypt = false,
+ .rf_path_num = 1,
+diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c
+index 9bd2842c27d50..eeb40a60c2b98 100644
+--- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c
++++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c
+@@ -2203,6 +2203,7 @@ const struct rtw89_chip_info rtw8852a_chip_info = {
+ .support_ant_gain = false,
+ .ul_tb_waveform_ctrl = false,
+ .ul_tb_pwr_diff = false,
++ .rx_freq_frome_ie = true,
+ .hw_sec_hdr = false,
+ .hw_mgmt_tx_encrypt = false,
+ .rf_path_num = 2,
+diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c
+index dfb2bf61b0b83..4335fa85c334b 100644
+--- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c
++++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c
+@@ -839,6 +839,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = {
+ .support_ant_gain = true,
+ .ul_tb_waveform_ctrl = true,
+ .ul_tb_pwr_diff = false,
++ .rx_freq_frome_ie = true,
+ .hw_sec_hdr = false,
+ .hw_mgmt_tx_encrypt = false,
+ .rf_path_num = 2,
+diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c
+index bde3e1fb7ca62..7f64a5695486b 100644
+--- a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c
++++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c
+@@ -772,6 +772,7 @@ const struct rtw89_chip_info rtw8852bt_chip_info = {
+ .support_ant_gain = true,
+ .ul_tb_waveform_ctrl = true,
+ .ul_tb_pwr_diff = false,
++ .rx_freq_frome_ie = true,
+ .hw_sec_hdr = false,
+ .hw_mgmt_tx_encrypt = false,
+ .rf_path_num = 2,
+diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
+index bc84b15e7826d..9778621d9bc41 100644
+--- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c
++++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
+@@ -2998,6 +2998,7 @@ const struct rtw89_chip_info rtw8852c_chip_info = {
+ .support_ant_gain = true,
+ .ul_tb_waveform_ctrl = false,
+ .ul_tb_pwr_diff = true,
++ .rx_freq_frome_ie = false,
+ .hw_sec_hdr = true,
+ .hw_mgmt_tx_encrypt = true,
+ .rf_path_num = 2,
+diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c
+index 11d66bfceb15f..731bc6f18d38b 100644
+--- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c
++++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c
+@@ -2763,6 +2763,7 @@ const struct rtw89_chip_info rtw8922a_chip_info = {
+ .support_ant_gain = false,
+ .ul_tb_waveform_ctrl = false,
+ .ul_tb_pwr_diff = false,
++ .rx_freq_frome_ie = false,
+ .hw_sec_hdr = true,
+ .hw_mgmt_tx_encrypt = true,
+ .rf_path_num = 2,
+--
+2.39.5
+
--- /dev/null
+From 694dfc113e44dca46df8a6149f6fc6b0f706f46a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Mar 2025 10:11:44 +0800
+Subject: wifi: rtw89: set force HE TB mode when connecting to 11ax AP
+
+From: Dian-Syuan Yang <dian_syuan0116@realtek.com>
+
+[ Upstream commit a9b56f219a0fa550f92e65ac58443a7892380e09 ]
+
+Some of 11ax AP set the UL HE-SIG-A2 reserved subfield to all 0s, which
+will cause the 11be chip to recognize trigger frame as EHT. We propose
+a method to bypass the "UL HE-SIG-A2 reserved subfield" and always uses
+HE TB in response to the AP's trigger frame.
+
+Signed-off-by: Dian-Syuan Yang <dian_syuan0116@realtek.com>
+Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
+Link: https://patch.msgid.link/20250306021144.12854-6-pkshih@realtek.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/realtek/rtw89/mac.c | 26 +++++++++++++++++++
+ drivers/net/wireless/realtek/rtw89/mac.h | 2 ++
+ drivers/net/wireless/realtek/rtw89/mac80211.c | 1 +
+ drivers/net/wireless/realtek/rtw89/reg.h | 4 +++
+ 4 files changed, 33 insertions(+)
+
+diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c
+index a37c6d525d6f0..2c74d7781bd40 100644
+--- a/drivers/net/wireless/realtek/rtw89/mac.c
++++ b/drivers/net/wireless/realtek/rtw89/mac.c
+@@ -4826,6 +4826,32 @@ void rtw89_mac_set_he_obss_narrow_bw_ru(struct rtw89_dev *rtwdev,
+ rtw89_write32_set(rtwdev, reg, mac->narrow_bw_ru_dis.mask);
+ }
+
++void rtw89_mac_set_he_tb(struct rtw89_dev *rtwdev,
++ struct rtw89_vif_link *rtwvif_link)
++{
++ struct ieee80211_bss_conf *bss_conf;
++ bool set;
++ u32 reg;
++
++ if (rtwdev->chip->chip_gen != RTW89_CHIP_BE)
++ return;
++
++ rcu_read_lock();
++
++ bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true);
++ set = bss_conf->he_support && !bss_conf->eht_support;
++
++ rcu_read_unlock();
++
++ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_CLIENT_OM_CTRL,
++ rtwvif_link->mac_idx);
++
++ if (set)
++ rtw89_write32_set(rtwdev, reg, B_BE_TRIG_DIS_EHTTB);
++ else
++ rtw89_write32_clr(rtwdev, reg, B_BE_TRIG_DIS_EHTTB);
++}
++
+ void rtw89_mac_stop_ap(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link)
+ {
+ rtw89_mac_port_cfg_func_sw(rtwdev, rtwvif_link);
+diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h
+index 8edea96d037f6..373366a602e0b 100644
+--- a/drivers/net/wireless/realtek/rtw89/mac.h
++++ b/drivers/net/wireless/realtek/rtw89/mac.h
+@@ -1185,6 +1185,8 @@ void rtw89_mac_port_cfg_rx_sync(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link, bool en);
+ void rtw89_mac_set_he_obss_narrow_bw_ru(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link);
++void rtw89_mac_set_he_tb(struct rtw89_dev *rtwdev,
++ struct rtw89_vif_link *rtwvif_link);
+ void rtw89_mac_stop_ap(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link);
+ void rtw89_mac_enable_beacon_for_ap_vifs(struct rtw89_dev *rtwdev, bool en);
+ int rtw89_mac_remove_vif(struct rtw89_dev *rtwdev, struct rtw89_vif_link *vif);
+diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c
+index b3669e0074df9..7c9b53a9ba3b7 100644
+--- a/drivers/net/wireless/realtek/rtw89/mac80211.c
++++ b/drivers/net/wireless/realtek/rtw89/mac80211.c
+@@ -670,6 +670,7 @@ static void __rtw89_ops_bss_link_assoc(struct rtw89_dev *rtwdev,
+ rtw89_chip_cfg_txpwr_ul_tb_offset(rtwdev, rtwvif_link);
+ rtw89_mac_port_update(rtwdev, rtwvif_link);
+ rtw89_mac_set_he_obss_narrow_bw_ru(rtwdev, rtwvif_link);
++ rtw89_mac_set_he_tb(rtwdev, rtwvif_link);
+ }
+
+ static void __rtw89_ops_bss_assoc(struct rtw89_dev *rtwdev,
+diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h
+index 10d0efa7a58ef..850ae5bf50ef3 100644
+--- a/drivers/net/wireless/realtek/rtw89/reg.h
++++ b/drivers/net/wireless/realtek/rtw89/reg.h
+@@ -7095,6 +7095,10 @@
+ #define B_BE_MACLBK_RDY_NUM_MASK GENMASK(7, 3)
+ #define B_BE_MACLBK_EN BIT(0)
+
++#define R_BE_CLIENT_OM_CTRL 0x11040
++#define R_BE_CLIENT_OM_CTRL_C1 0x15040
++#define B_BE_TRIG_DIS_EHTTB BIT(24)
++
+ #define R_BE_WMAC_NAV_CTL 0x11080
+ #define R_BE_WMAC_NAV_CTL_C1 0x15080
+ #define B_BE_WMAC_NAV_UPPER_EN BIT(26)
+--
+2.39.5
+
--- /dev/null
+From 20180ecc6e94dc891504d85cf375881e35d9d205 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jan 2025 19:48:56 +0000
+Subject: x86/amd_node: Add SMN offsets to exclusive region access
+
+From: Mario Limonciello <mario.limonciello@amd.com>
+
+[ Upstream commit 83518453074d1f3eadbf7e61652b608a60087317 ]
+
+Offsets 0x60 and 0x64 are used internally by kernel drivers that call
+the amd_smn_read() and amd_smn_write() functions. If userspace accesses
+the regions at the same time as the kernel it may cause malfunctions in
+drivers using the offsets.
+
+Add these offsets to the exclusions so that the kernel is tainted if a
+non locked down userspace tries to access them.
+
+Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
+Signed-off-by: Yazen Ghannam <yazen.ghannam@amd.com>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Link: https://lore.kernel.org/r/20250130-wip-x86-amd-nb-cleanup-v4-2-b5cc997e471b@amd.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/kernel/amd_node.c | 41 ++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 41 insertions(+)
+
+diff --git a/arch/x86/kernel/amd_node.c b/arch/x86/kernel/amd_node.c
+index 65045f223c10a..ac571948cb353 100644
+--- a/arch/x86/kernel/amd_node.c
++++ b/arch/x86/kernel/amd_node.c
+@@ -93,6 +93,7 @@ static struct pci_dev **amd_roots;
+
+ /* Protect the PCI config register pairs used for SMN. */
+ static DEFINE_MUTEX(smn_mutex);
++static bool smn_exclusive;
+
+ #define SMN_INDEX_OFFSET 0x60
+ #define SMN_DATA_OFFSET 0x64
+@@ -149,6 +150,9 @@ static int __amd_smn_rw(u8 i_off, u8 d_off, u16 node, u32 address, u32 *value, b
+ if (!root)
+ return err;
+
++ if (!smn_exclusive)
++ return err;
++
+ guard(mutex)(&smn_mutex);
+
+ err = pci_write_config_dword(root, i_off, address);
+@@ -202,6 +206,39 @@ static int amd_cache_roots(void)
+ return 0;
+ }
+
++static int reserve_root_config_spaces(void)
++{
++ struct pci_dev *root = NULL;
++ struct pci_bus *bus = NULL;
++
++ while ((bus = pci_find_next_bus(bus))) {
++ /* Root device is Device 0 Function 0 on each Primary Bus. */
++ root = pci_get_slot(bus, 0);
++ if (!root)
++ continue;
++
++ if (root->vendor != PCI_VENDOR_ID_AMD &&
++ root->vendor != PCI_VENDOR_ID_HYGON)
++ continue;
++
++ pci_dbg(root, "Reserving PCI config space\n");
++
++ /*
++ * There are a few SMN index/data pairs and other registers
++ * that shouldn't be accessed by user space.
++ * So reserve the entire PCI config space for simplicity rather
++ * than covering specific registers piecemeal.
++ */
++ if (!pci_request_config_region_exclusive(root, 0, PCI_CFG_SPACE_SIZE, NULL)) {
++ pci_err(root, "Failed to reserve config space\n");
++ return -EEXIST;
++ }
++ }
++
++ smn_exclusive = true;
++ return 0;
++}
++
+ static int __init amd_smn_init(void)
+ {
+ int err;
+@@ -218,6 +255,10 @@ static int __init amd_smn_init(void)
+ if (err)
+ return err;
+
++ err = reserve_root_config_spaces();
++ if (err)
++ return err;
++
+ return 0;
+ }
+
+--
+2.39.5
+
--- /dev/null
+From 4fef5393716667e290946e84de38b209bda14ad6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 23 Jan 2025 14:07:35 -0500
+Subject: x86/boot: Disable stack protector for early boot code
+
+From: Brian Gerst <brgerst@gmail.com>
+
+[ Upstream commit a9a76b38aaf577887103e3ebb41d70e6aa5a4b19 ]
+
+On 64-bit, this will prevent crashes when the canary access is changed
+from %gs:40 to %gs:__stack_chk_guard(%rip). RIP-relative addresses from
+the identity-mapped early boot code will target the wrong address with
+zero-based percpu. KASLR could then shift that address to an unmapped
+page causing a crash on boot.
+
+This early boot code runs well before user-space is active and does not
+need stack protector enabled.
+
+Signed-off-by: Brian Gerst <brgerst@gmail.com>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Link: https://lore.kernel.org/r/20250123190747.745588-4-brgerst@gmail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/kernel/Makefile | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
+index b43eb7e384eba..84cfa179802c3 100644
+--- a/arch/x86/kernel/Makefile
++++ b/arch/x86/kernel/Makefile
+@@ -44,6 +44,8 @@ KCOV_INSTRUMENT_unwind_orc.o := n
+ KCOV_INSTRUMENT_unwind_frame.o := n
+ KCOV_INSTRUMENT_unwind_guess.o := n
+
++CFLAGS_head32.o := -fno-stack-protector
++CFLAGS_head64.o := -fno-stack-protector
+ CFLAGS_irq.o := -I $(src)/../include/asm/trace
+
+ obj-y += head_$(BITS).o
+--
+2.39.5
+
--- /dev/null
+From 2b095ffb92dcc2b39a11b125be14f0d58b784c69 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 7 Feb 2025 13:15:34 +0100
+Subject: x86/boot: Mark start_secondary() with __noendbr
+
+From: Peter Zijlstra <peterz@infradead.org>
+
+[ Upstream commit 93f16a1ab78ca56e3cd997d1ea54c214774781ac ]
+
+The handoff between the boot stubs and start_secondary() are before IBT is
+enabled and is definitely not subject to kCFI. As such, suppress all that for
+this function.
+
+Notably when the ENDBR poison would become fatal (ud1 instead of nop) this will
+trigger a tripple fault because we haven't set up the IDT to handle #UD yet.
+
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Reviewed-by: Sami Tolvanen <samitolvanen@google.com>
+Link: https://lore.kernel.org/r/20250207122546.509520369@infradead.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/kernel/smpboot.c | 3 ++-
+ include/linux/objtool.h | 4 +++-
+ 2 files changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
+index 3d5069ee297bf..463634b138bbb 100644
+--- a/arch/x86/kernel/smpboot.c
++++ b/arch/x86/kernel/smpboot.c
+@@ -229,7 +229,7 @@ static void ap_calibrate_delay(void)
+ /*
+ * Activate a secondary processor.
+ */
+-static void notrace start_secondary(void *unused)
++static void notrace __noendbr start_secondary(void *unused)
+ {
+ /*
+ * Don't put *anything* except direct CPU state initialization
+@@ -314,6 +314,7 @@ static void notrace start_secondary(void *unused)
+ wmb();
+ cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
+ }
++ANNOTATE_NOENDBR_SYM(start_secondary);
+
+ /*
+ * The bootstrap kernel entry code has set these up. Save them for
+diff --git a/include/linux/objtool.h b/include/linux/objtool.h
+index c722a921165ba..3ca965a2ddc80 100644
+--- a/include/linux/objtool.h
++++ b/include/linux/objtool.h
+@@ -128,7 +128,7 @@
+ #define UNWIND_HINT(type, sp_reg, sp_offset, signal) "\n\t"
+ #define STACK_FRAME_NON_STANDARD(func)
+ #define STACK_FRAME_NON_STANDARD_FP(func)
+-#define __ASM_ANNOTATE(label, type)
++#define __ASM_ANNOTATE(label, type) ""
+ #define ASM_ANNOTATE(type)
+ #else
+ .macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0
+@@ -147,6 +147,8 @@
+ * these relocations will never be used for indirect calls.
+ */
+ #define ANNOTATE_NOENDBR ASM_ANNOTATE(ANNOTYPE_NOENDBR)
++#define ANNOTATE_NOENDBR_SYM(sym) asm(__ASM_ANNOTATE(sym, ANNOTYPE_NOENDBR))
++
+ /*
+ * This should be used immediately before an indirect jump/call. It tells
+ * objtool the subsequent indirect jump/call is vouched safe for retpoline
+--
+2.39.5
+
--- /dev/null
+From 6df764c77bf53fde074bac365d16ca7b0f47a889 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Feb 2025 12:13:33 +0100
+Subject: x86/bugs: KVM: Add support for SRSO_MSR_FIX
+
+From: Borislav Petkov <bp@alien8.de>
+
+[ Upstream commit 8442df2b49ed9bcd67833ad4f091d15ac91efd00 ]
+
+Add support for
+
+ CPUID Fn8000_0021_EAX[31] (SRSO_MSR_FIX). If this bit is 1, it
+ indicates that software may use MSR BP_CFG[BpSpecReduce] to mitigate
+ SRSO.
+
+Enable BpSpecReduce to mitigate SRSO across guest/host boundaries.
+
+Switch back to enabling the bit when virtualization is enabled and to
+clear the bit when virtualization is disabled because using a MSR slot
+would clear the bit when the guest is exited and any training the guest
+has done, would potentially influence the host kernel when execution
+enters the kernel and hasn't VMRUN the guest yet.
+
+More detail on the public thread in Link below.
+
+Co-developed-by: Sean Christopherson <seanjc@google.com>
+Signed-off-by: Sean Christopherson <seanjc@google.com>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Link: https://lore.kernel.org/r/20241202120416.6054-1-bp@kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ Documentation/admin-guide/hw-vuln/srso.rst | 13 ++++++++++++
+ arch/x86/include/asm/cpufeatures.h | 4 ++++
+ arch/x86/include/asm/msr-index.h | 1 +
+ arch/x86/kernel/cpu/bugs.c | 24 ++++++++++++++++++----
+ arch/x86/kvm/svm/svm.c | 6 ++++++
+ arch/x86/lib/msr.c | 2 ++
+ 6 files changed, 46 insertions(+), 4 deletions(-)
+
+diff --git a/Documentation/admin-guide/hw-vuln/srso.rst b/Documentation/admin-guide/hw-vuln/srso.rst
+index 2ad1c05b8c883..66af95251a3d1 100644
+--- a/Documentation/admin-guide/hw-vuln/srso.rst
++++ b/Documentation/admin-guide/hw-vuln/srso.rst
+@@ -104,7 +104,20 @@ The possible values in this file are:
+
+ (spec_rstack_overflow=ibpb-vmexit)
+
++ * 'Mitigation: Reduced Speculation':
+
++ This mitigation gets automatically enabled when the above one "IBPB on
++ VMEXIT" has been selected and the CPU supports the BpSpecReduce bit.
++
++ It gets automatically enabled on machines which have the
++ SRSO_USER_KERNEL_NO=1 CPUID bit. In that case, the code logic is to switch
++ to the above =ibpb-vmexit mitigation because the user/kernel boundary is
++ not affected anymore and thus "safe RET" is not needed.
++
++ After enabling the IBPB on VMEXIT mitigation option, the BpSpecReduce bit
++ is detected (functionality present on all such machines) and that
++ practically overrides IBPB on VMEXIT as it has a lot less performance
++ impact and takes care of the guest->host attack vector too.
+
+ In order to exploit vulnerability, an attacker needs to:
+
+diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h
+index b8fbd847c34af..06631474ede29 100644
+--- a/arch/x86/include/asm/cpufeatures.h
++++ b/arch/x86/include/asm/cpufeatures.h
+@@ -468,6 +468,10 @@
+ #define X86_FEATURE_IBPB_BRTYPE (20*32+28) /* MSR_PRED_CMD[IBPB] flushes all branch type predictions */
+ #define X86_FEATURE_SRSO_NO (20*32+29) /* CPU is not affected by SRSO */
+ #define X86_FEATURE_SRSO_USER_KERNEL_NO (20*32+30) /* CPU is not affected by SRSO across user/kernel boundaries */
++#define X86_FEATURE_SRSO_BP_SPEC_REDUCE (20*32+31) /*
++ * BP_CFG[BpSpecReduce] can be used to mitigate SRSO for VMs.
++ * (SRSO_MSR_FIX in the official doc).
++ */
+
+ /*
+ * Extended auxiliary flags: Linux defined - for features scattered in various
+diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
+index d4308e78a009a..9f402a7b211b9 100644
+--- a/arch/x86/include/asm/msr-index.h
++++ b/arch/x86/include/asm/msr-index.h
+@@ -729,6 +729,7 @@
+
+ /* Zen4 */
+ #define MSR_ZEN4_BP_CFG 0xc001102e
++#define MSR_ZEN4_BP_CFG_BP_SPEC_REDUCE_BIT 4
+ #define MSR_ZEN4_BP_CFG_SHARED_BTB_FIX_BIT 5
+
+ /* Fam 19h MSRs */
+diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c
+index e0e0ecc401947..f1954147cc5d5 100644
+--- a/arch/x86/kernel/cpu/bugs.c
++++ b/arch/x86/kernel/cpu/bugs.c
+@@ -2675,6 +2675,7 @@ enum srso_mitigation {
+ SRSO_MITIGATION_SAFE_RET,
+ SRSO_MITIGATION_IBPB,
+ SRSO_MITIGATION_IBPB_ON_VMEXIT,
++ SRSO_MITIGATION_BP_SPEC_REDUCE,
+ };
+
+ enum srso_mitigation_cmd {
+@@ -2692,7 +2693,8 @@ static const char * const srso_strings[] = {
+ [SRSO_MITIGATION_MICROCODE] = "Vulnerable: Microcode, no safe RET",
+ [SRSO_MITIGATION_SAFE_RET] = "Mitigation: Safe RET",
+ [SRSO_MITIGATION_IBPB] = "Mitigation: IBPB",
+- [SRSO_MITIGATION_IBPB_ON_VMEXIT] = "Mitigation: IBPB on VMEXIT only"
++ [SRSO_MITIGATION_IBPB_ON_VMEXIT] = "Mitigation: IBPB on VMEXIT only",
++ [SRSO_MITIGATION_BP_SPEC_REDUCE] = "Mitigation: Reduced Speculation"
+ };
+
+ static enum srso_mitigation srso_mitigation __ro_after_init = SRSO_MITIGATION_NONE;
+@@ -2731,7 +2733,7 @@ static void __init srso_select_mitigation(void)
+ srso_cmd == SRSO_CMD_OFF) {
+ if (boot_cpu_has(X86_FEATURE_SBPB))
+ x86_pred_cmd = PRED_CMD_SBPB;
+- return;
++ goto out;
+ }
+
+ if (has_microcode) {
+@@ -2743,7 +2745,7 @@ static void __init srso_select_mitigation(void)
+ */
+ if (boot_cpu_data.x86 < 0x19 && !cpu_smt_possible()) {
+ setup_force_cpu_cap(X86_FEATURE_SRSO_NO);
+- return;
++ goto out;
+ }
+
+ if (retbleed_mitigation == RETBLEED_MITIGATION_IBPB) {
+@@ -2823,6 +2825,12 @@ static void __init srso_select_mitigation(void)
+
+ ibpb_on_vmexit:
+ case SRSO_CMD_IBPB_ON_VMEXIT:
++ if (boot_cpu_has(X86_FEATURE_SRSO_BP_SPEC_REDUCE)) {
++ pr_notice("Reducing speculation to address VM/HV SRSO attack vector.\n");
++ srso_mitigation = SRSO_MITIGATION_BP_SPEC_REDUCE;
++ break;
++ }
++
+ if (IS_ENABLED(CONFIG_MITIGATION_IBPB_ENTRY)) {
+ if (has_microcode) {
+ setup_force_cpu_cap(X86_FEATURE_IBPB_ON_VMEXIT);
+@@ -2844,7 +2852,15 @@ static void __init srso_select_mitigation(void)
+ }
+
+ out:
+- pr_info("%s\n", srso_strings[srso_mitigation]);
++ /*
++ * Clear the feature flag if this mitigation is not selected as that
++ * feature flag controls the BpSpecReduce MSR bit toggling in KVM.
++ */
++ if (srso_mitigation != SRSO_MITIGATION_BP_SPEC_REDUCE)
++ setup_clear_cpu_cap(X86_FEATURE_SRSO_BP_SPEC_REDUCE);
++
++ if (srso_mitigation != SRSO_MITIGATION_NONE)
++ pr_info("%s\n", srso_strings[srso_mitigation]);
+ }
+
+ #undef pr_fmt
+diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
+index 282c91c6aa338..b8f12b808d83a 100644
+--- a/arch/x86/kvm/svm/svm.c
++++ b/arch/x86/kvm/svm/svm.c
+@@ -607,6 +607,9 @@ static void svm_disable_virtualization_cpu(void)
+ kvm_cpu_svm_disable();
+
+ amd_pmu_disable_virt();
++
++ if (cpu_feature_enabled(X86_FEATURE_SRSO_BP_SPEC_REDUCE))
++ msr_clear_bit(MSR_ZEN4_BP_CFG, MSR_ZEN4_BP_CFG_BP_SPEC_REDUCE_BIT);
+ }
+
+ static int svm_enable_virtualization_cpu(void)
+@@ -684,6 +687,9 @@ static int svm_enable_virtualization_cpu(void)
+ rdmsr(MSR_TSC_AUX, sev_es_host_save_area(sd)->tsc_aux, msr_hi);
+ }
+
++ if (cpu_feature_enabled(X86_FEATURE_SRSO_BP_SPEC_REDUCE))
++ msr_set_bit(MSR_ZEN4_BP_CFG, MSR_ZEN4_BP_CFG_BP_SPEC_REDUCE_BIT);
++
+ return 0;
+ }
+
+diff --git a/arch/x86/lib/msr.c b/arch/x86/lib/msr.c
+index 4bf4fad5b148e..5a18ecc04a6c3 100644
+--- a/arch/x86/lib/msr.c
++++ b/arch/x86/lib/msr.c
+@@ -103,6 +103,7 @@ int msr_set_bit(u32 msr, u8 bit)
+ {
+ return __flip_bit(msr, bit, true);
+ }
++EXPORT_SYMBOL_GPL(msr_set_bit);
+
+ /**
+ * msr_clear_bit - Clear @bit in a MSR @msr.
+@@ -118,6 +119,7 @@ int msr_clear_bit(u32 msr, u8 bit)
+ {
+ return __flip_bit(msr, bit, false);
+ }
++EXPORT_SYMBOL_GPL(msr_clear_bit);
+
+ #ifdef CONFIG_TRACEPOINTS
+ void do_trace_write_msr(unsigned int msr, u64 val, int failed)
+--
+2.39.5
+
--- /dev/null
+From 57693499df99672024f45f2ba16ab3f37d5a4a1d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 31 Oct 2024 04:06:17 -0700
+Subject: x86/bugs: Make spectre user default depend on MITIGATION_SPECTRE_V2
+
+From: Breno Leitao <leitao@debian.org>
+
+[ Upstream commit 98fdaeb296f51ef08e727a7cc72e5b5c864c4f4d ]
+
+Change the default value of spectre v2 in user mode to respect the
+CONFIG_MITIGATION_SPECTRE_V2 config option.
+
+Currently, user mode spectre v2 is set to auto
+(SPECTRE_V2_USER_CMD_AUTO) by default, even if
+CONFIG_MITIGATION_SPECTRE_V2 is disabled.
+
+Set the spectre_v2 value to auto (SPECTRE_V2_USER_CMD_AUTO) if the
+Spectre v2 config (CONFIG_MITIGATION_SPECTRE_V2) is enabled, otherwise
+set the value to none (SPECTRE_V2_USER_CMD_NONE).
+
+Important to say the command line argument "spectre_v2_user" overwrites
+the default value in both cases.
+
+When CONFIG_MITIGATION_SPECTRE_V2 is not set, users have the flexibility
+to opt-in for specific mitigations independently. In this scenario,
+setting spectre_v2= will not enable spectre_v2_user=, and command line
+options spectre_v2_user and spectre_v2 are independent when
+CONFIG_MITIGATION_SPECTRE_V2=n.
+
+Signed-off-by: Breno Leitao <leitao@debian.org>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Reviewed-by: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+Acked-by: Josh Poimboeuf <jpoimboe@kernel.org>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: David Kaplan <David.Kaplan@amd.com>
+Link: https://lore.kernel.org/r/20241031-x86_bugs_last_v2-v2-2-b7ff1dab840e@debian.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ Documentation/admin-guide/kernel-parameters.txt | 2 ++
+ arch/x86/kernel/cpu/bugs.c | 10 +++++++---
+ 2 files changed, 9 insertions(+), 3 deletions(-)
+
+diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
+index f9e11cebc598c..a8e98f75b610a 100644
+--- a/Documentation/admin-guide/kernel-parameters.txt
++++ b/Documentation/admin-guide/kernel-parameters.txt
+@@ -6602,6 +6602,8 @@
+
+ Selecting 'on' will also enable the mitigation
+ against user space to user space task attacks.
++ Selecting specific mitigation does not force enable
++ user mitigations.
+
+ Selecting 'off' will disable both the kernel and
+ the user space protections.
+diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c
+index b6994993c39f7..e0e0ecc401947 100644
+--- a/arch/x86/kernel/cpu/bugs.c
++++ b/arch/x86/kernel/cpu/bugs.c
+@@ -1442,9 +1442,13 @@ static __ro_after_init enum spectre_v2_mitigation_cmd spectre_v2_cmd;
+ static enum spectre_v2_user_cmd __init
+ spectre_v2_parse_user_cmdline(void)
+ {
++ enum spectre_v2_user_cmd mode;
+ char arg[20];
+ int ret, i;
+
++ mode = IS_ENABLED(CONFIG_MITIGATION_SPECTRE_V2) ?
++ SPECTRE_V2_USER_CMD_AUTO : SPECTRE_V2_USER_CMD_NONE;
++
+ switch (spectre_v2_cmd) {
+ case SPECTRE_V2_CMD_NONE:
+ return SPECTRE_V2_USER_CMD_NONE;
+@@ -1457,7 +1461,7 @@ spectre_v2_parse_user_cmdline(void)
+ ret = cmdline_find_option(boot_command_line, "spectre_v2_user",
+ arg, sizeof(arg));
+ if (ret < 0)
+- return SPECTRE_V2_USER_CMD_AUTO;
++ return mode;
+
+ for (i = 0; i < ARRAY_SIZE(v2_user_options); i++) {
+ if (match_option(arg, ret, v2_user_options[i].option)) {
+@@ -1467,8 +1471,8 @@ spectre_v2_parse_user_cmdline(void)
+ }
+ }
+
+- pr_err("Unknown user space protection option (%s). Switching to AUTO select\n", arg);
+- return SPECTRE_V2_USER_CMD_AUTO;
++ pr_err("Unknown user space protection option (%s). Switching to default\n", arg);
++ return mode;
+ }
+
+ static inline bool spectre_v2_in_ibrs_mode(enum spectre_v2_mitigation mode)
+--
+2.39.5
+
--- /dev/null
+From e885695a8f380dde4e575ef6b6c9ca6fe647667a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 10 Jan 2025 12:05:00 +0000
+Subject: x86/build: Fix broken copy command in genimage.sh when making
+ isoimage
+
+From: Nir Lichtman <nir@lichtman.org>
+
+[ Upstream commit e451630226bd09dc730eedb4e32cab1cc7155ae8 ]
+
+Problem: Currently when running the "make isoimage" command there is an
+error related to wrong parameters passed to the cp command:
+
+ "cp: missing destination file operand after 'arch/x86/boot/isoimage/'"
+
+This is caused because FDINITRDS is an empty array.
+
+Solution: Check if FDINITRDS is empty before executing the "cp" command,
+similar to how it is done in the case of hdimage.
+
+Signed-off-by: Nir Lichtman <nir@lichtman.org>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Cc: "H. Peter Anvin" <hpa@zytor.com>
+Cc: Ard Biesheuvel <ardb@kernel.org>
+Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
+Cc: Michal Marek <michal.lkml@markovi.net>
+Link: https://lore.kernel.org/r/20250110120500.GA923218@lichtman.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/boot/genimage.sh | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/arch/x86/boot/genimage.sh b/arch/x86/boot/genimage.sh
+index c9299aeb7333e..3882ead513f74 100644
+--- a/arch/x86/boot/genimage.sh
++++ b/arch/x86/boot/genimage.sh
+@@ -22,6 +22,7 @@
+ # This script requires:
+ # bash
+ # syslinux
++# genisoimage
+ # mtools (for fdimage* and hdimage)
+ # edk2/OVMF (for hdimage)
+ #
+@@ -251,7 +252,9 @@ geniso() {
+ cp "$isolinux" "$ldlinux" "$tmp_dir"
+ cp "$FBZIMAGE" "$tmp_dir"/linux
+ echo default linux "$KCMDLINE" > "$tmp_dir"/isolinux.cfg
+- cp "${FDINITRDS[@]}" "$tmp_dir"/
++ if [ ${#FDINITRDS[@]} -gt 0 ]; then
++ cp "${FDINITRDS[@]}" "$tmp_dir"/
++ fi
+ genisoimage -J -r -appid 'LINUX_BOOT' -input-charset=utf-8 \
+ -quiet -o "$FIMAGE" -b isolinux.bin \
+ -c boot.cat -no-emul-boot -boot-load-size 4 \
+--
+2.39.5
+
--- /dev/null
+From 089effee814b14c6cff9e1ace77996688d6a9bf2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 1 Apr 2025 00:57:27 -0700
+Subject: x86/fred: Fix system hang during S4 resume with FRED enabled
+
+From: Xin Li (Intel) <xin@zytor.com>
+
+[ Upstream commit e5f1e8af9c9e151ecd665f6d2e36fb25fec3b110 ]
+
+Upon a wakeup from S4, the restore kernel starts and initializes the
+FRED MSRs as needed from its perspective. It then loads a hibernation
+image, including the image kernel, and attempts to load image pages
+directly into their original page frames used before hibernation unless
+those frames are currently in use. Once all pages are moved to their
+original locations, it jumps to a "trampoline" page in the image kernel.
+
+At this point, the image kernel takes control, but the FRED MSRs still
+contain values set by the restore kernel, which may differ from those
+set by the image kernel before hibernation. Therefore, the image kernel
+must ensure the FRED MSRs have the same values as before hibernation.
+Since these values depend only on the location of the kernel text and
+data, they can be recomputed from scratch.
+
+Reported-by: Xi Pardee <xi.pardee@intel.com>
+Reported-by: Todd Brandt <todd.e.brandt@intel.com>
+Tested-by: Todd Brandt <todd.e.brandt@intel.com>
+Suggested-by: H. Peter Anvin (Intel) <hpa@zytor.com>
+Signed-off-by: Xin Li (Intel) <xin@zytor.com>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Reviewed-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Reviewed-by: H. Peter Anvin (Intel) <hpa@zytor.com>
+Cc: Andy Lutomirski <luto@kernel.org>
+Cc: Brian Gerst <brgerst@gmail.com>
+Cc: Juergen Gross <jgross@suse.com>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Link: https://lore.kernel.org/r/20250401075728.3626147-1-xin@zytor.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/power/cpu.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/arch/x86/power/cpu.c b/arch/x86/power/cpu.c
+index 63230ff8cf4f0..08e76a5ca1553 100644
+--- a/arch/x86/power/cpu.c
++++ b/arch/x86/power/cpu.c
+@@ -27,6 +27,7 @@
+ #include <asm/mmu_context.h>
+ #include <asm/cpu_device_id.h>
+ #include <asm/microcode.h>
++#include <asm/fred.h>
+
+ #ifdef CONFIG_X86_32
+ __visible unsigned long saved_context_ebx;
+@@ -231,6 +232,19 @@ static void notrace __restore_processor_state(struct saved_context *ctxt)
+ */
+ #ifdef CONFIG_X86_64
+ wrmsrl(MSR_GS_BASE, ctxt->kernelmode_gs_base);
++
++ /*
++ * Reinitialize FRED to ensure the FRED MSRs contain the same values
++ * as before hibernation.
++ *
++ * Note, the setup of FRED RSPs requires access to percpu data
++ * structures. Therefore, FRED reinitialization can only occur after
++ * the percpu access pointer (i.e., MSR_GS_BASE) is restored.
++ */
++ if (ctxt->cr4 & X86_CR4_FRED) {
++ cpu_init_fred_exceptions();
++ cpu_init_fred_rsps();
++ }
+ #else
+ loadsegment(fs, __KERNEL_PERCPU);
+ #endif
+--
+2.39.5
+
--- /dev/null
+From 33c2fd3e499ad954c10239300b231df207eb7924 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 19 Mar 2025 11:30:57 +0100
+Subject: x86/headers: Replace __ASSEMBLY__ with __ASSEMBLER__ in non-UAPI
+ headers
+
+From: Thomas Huth <thuth@redhat.com>
+
+[ Upstream commit 24a295e4ef1ca8e97d8b7015e1887b6e83e1c8be ]
+
+While the GCC and Clang compilers already define __ASSEMBLER__
+automatically when compiling assembly code, __ASSEMBLY__ is a
+macro that only gets defined by the Makefiles in the kernel.
+
+This can be very confusing when switching between userspace
+and kernelspace coding, or when dealing with UAPI headers that
+rather should use __ASSEMBLER__ instead. So let's standardize on
+the __ASSEMBLER__ macro that is provided by the compilers now.
+
+This is mostly a mechanical patch (done with a simple "sed -i"
+statement), with some manual tweaks in <asm/frame.h>, <asm/hw_irq.h>
+and <asm/setup.h> that mentioned this macro in comments with some
+missing underscores.
+
+Signed-off-by: Thomas Huth <thuth@redhat.com>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Cc: Brian Gerst <brgerst@gmail.com>
+Cc: Juergen Gross <jgross@suse.com>
+Cc: H. Peter Anvin <hpa@zytor.com>
+Cc: Kees Cook <keescook@chromium.org>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Link: https://lore.kernel.org/r/20250314071013.1575167-38-thuth@redhat.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/boot/boot.h | 4 ++--
+ arch/x86/entry/vdso/extable.h | 2 +-
+ arch/x86/include/asm/alternative.h | 6 +++---
+ arch/x86/include/asm/asm.h | 10 +++++-----
+ arch/x86/include/asm/boot.h | 2 +-
+ arch/x86/include/asm/cpufeature.h | 4 ++--
+ arch/x86/include/asm/cpumask.h | 4 ++--
+ arch/x86/include/asm/current.h | 4 ++--
+ arch/x86/include/asm/desc_defs.h | 4 ++--
+ arch/x86/include/asm/dwarf2.h | 2 +-
+ arch/x86/include/asm/fixmap.h | 4 ++--
+ arch/x86/include/asm/frame.h | 10 +++++-----
+ arch/x86/include/asm/fred.h | 4 ++--
+ arch/x86/include/asm/fsgsbase.h | 4 ++--
+ arch/x86/include/asm/ftrace.h | 8 ++++----
+ arch/x86/include/asm/hw_irq.h | 4 ++--
+ arch/x86/include/asm/ibt.h | 12 ++++++------
+ arch/x86/include/asm/idtentry.h | 6 +++---
+ arch/x86/include/asm/inst.h | 2 +-
+ arch/x86/include/asm/irqflags.h | 10 +++++-----
+ arch/x86/include/asm/jump_label.h | 4 ++--
+ arch/x86/include/asm/kasan.h | 2 +-
+ arch/x86/include/asm/kexec.h | 4 ++--
+ arch/x86/include/asm/linkage.h | 6 +++---
+ arch/x86/include/asm/mem_encrypt.h | 4 ++--
+ arch/x86/include/asm/msr.h | 4 ++--
+ arch/x86/include/asm/nops.h | 2 +-
+ arch/x86/include/asm/nospec-branch.h | 6 +++---
+ arch/x86/include/asm/orc_types.h | 4 ++--
+ arch/x86/include/asm/page.h | 4 ++--
+ arch/x86/include/asm/page_32.h | 4 ++--
+ arch/x86/include/asm/page_32_types.h | 4 ++--
+ arch/x86/include/asm/page_64.h | 4 ++--
+ arch/x86/include/asm/page_64_types.h | 2 +-
+ arch/x86/include/asm/page_types.h | 4 ++--
+ arch/x86/include/asm/paravirt.h | 14 +++++++-------
+ arch/x86/include/asm/paravirt_types.h | 4 ++--
+ arch/x86/include/asm/percpu.h | 4 ++--
+ arch/x86/include/asm/pgtable-2level_types.h | 4 ++--
+ arch/x86/include/asm/pgtable-3level_types.h | 4 ++--
+ arch/x86/include/asm/pgtable-invert.h | 4 ++--
+ arch/x86/include/asm/pgtable.h | 12 ++++++------
+ arch/x86/include/asm/pgtable_32.h | 4 ++--
+ arch/x86/include/asm/pgtable_32_areas.h | 2 +-
+ arch/x86/include/asm/pgtable_64.h | 6 +++---
+ arch/x86/include/asm/pgtable_64_types.h | 4 ++--
+ arch/x86/include/asm/pgtable_types.h | 10 +++++-----
+ arch/x86/include/asm/prom.h | 4 ++--
+ arch/x86/include/asm/pti.h | 4 ++--
+ arch/x86/include/asm/ptrace.h | 4 ++--
+ arch/x86/include/asm/purgatory.h | 4 ++--
+ arch/x86/include/asm/pvclock-abi.h | 4 ++--
+ arch/x86/include/asm/realmode.h | 4 ++--
+ arch/x86/include/asm/segment.h | 8 ++++----
+ arch/x86/include/asm/setup.h | 6 +++---
+ arch/x86/include/asm/setup_data.h | 4 ++--
+ arch/x86/include/asm/shared/tdx.h | 4 ++--
+ arch/x86/include/asm/shstk.h | 4 ++--
+ arch/x86/include/asm/signal.h | 8 ++++----
+ arch/x86/include/asm/smap.h | 6 +++---
+ arch/x86/include/asm/smp.h | 4 ++--
+ arch/x86/include/asm/tdx.h | 4 ++--
+ arch/x86/include/asm/thread_info.h | 12 ++++++------
+ arch/x86/include/asm/unwind_hints.h | 4 ++--
+ arch/x86/include/asm/vdso/getrandom.h | 4 ++--
+ arch/x86/include/asm/vdso/gettimeofday.h | 4 ++--
+ arch/x86/include/asm/vdso/processor.h | 4 ++--
+ arch/x86/include/asm/vdso/vsyscall.h | 4 ++--
+ arch/x86/include/asm/xen/interface.h | 10 +++++-----
+ arch/x86/include/asm/xen/interface_32.h | 4 ++--
+ arch/x86/include/asm/xen/interface_64.h | 4 ++--
+ arch/x86/math-emu/control_w.h | 2 +-
+ arch/x86/math-emu/exception.h | 6 +++---
+ arch/x86/math-emu/fpu_emu.h | 6 +++---
+ arch/x86/math-emu/status_w.h | 6 +++---
+ arch/x86/realmode/rm/realmode.h | 4 ++--
+ arch/x86/realmode/rm/wakeup.h | 2 +-
+ tools/arch/x86/include/asm/asm.h | 8 ++++----
+ tools/arch/x86/include/asm/nops.h | 2 +-
+ tools/arch/x86/include/asm/orc_types.h | 4 ++--
+ tools/arch/x86/include/asm/pvclock-abi.h | 4 ++--
+ 81 files changed, 201 insertions(+), 201 deletions(-)
+
+diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h
+index 0f24f7ebec9ba..38f17a1e1e367 100644
+--- a/arch/x86/boot/boot.h
++++ b/arch/x86/boot/boot.h
+@@ -16,7 +16,7 @@
+
+ #define STACK_SIZE 1024 /* Minimum number of bytes for stack */
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ #include <linux/stdarg.h>
+ #include <linux/types.h>
+@@ -327,6 +327,6 @@ void probe_cards(int unsafe);
+ /* video-vesa.c */
+ void vesa_store_edid(void);
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ #endif /* BOOT_BOOT_H */
+diff --git a/arch/x86/entry/vdso/extable.h b/arch/x86/entry/vdso/extable.h
+index b56f6b0129416..baba612b832c3 100644
+--- a/arch/x86/entry/vdso/extable.h
++++ b/arch/x86/entry/vdso/extable.h
+@@ -7,7 +7,7 @@
+ * vDSO uses a dedicated handler the addresses are relative to the overall
+ * exception table, not each individual entry.
+ */
+-#ifdef __ASSEMBLY__
++#ifdef __ASSEMBLER__
+ #define _ASM_VDSO_EXTABLE_HANDLE(from, to) \
+ ASM_VDSO_EXTABLE_HANDLE from to
+
+diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h
+index 9e01490220ece..abfca03f47a79 100644
+--- a/arch/x86/include/asm/alternative.h
++++ b/arch/x86/include/asm/alternative.h
+@@ -16,7 +16,7 @@
+ #define ALT_DIRECT_CALL(feature) ((ALT_FLAG_DIRECT_CALL << ALT_FLAGS_SHIFT) | (feature))
+ #define ALT_CALL_ALWAYS ALT_DIRECT_CALL(X86_FEATURE_ALWAYS)
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ #include <linux/stddef.h>
+
+@@ -318,7 +318,7 @@ static inline int alternatives_text_reserved(void *start, void *end)
+ void BUG_func(void);
+ void nop_func(void);
+
+-#else /* __ASSEMBLY__ */
++#else /* __ASSEMBLER__ */
+
+ #ifdef CONFIG_SMP
+ .macro LOCK_PREFIX
+@@ -401,6 +401,6 @@ void nop_func(void);
+ ALTERNATIVE_2 oldinstr, newinstr_no, X86_FEATURE_ALWAYS, \
+ newinstr_yes, ft_flags
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ #endif /* _ASM_X86_ALTERNATIVE_H */
+diff --git a/arch/x86/include/asm/asm.h b/arch/x86/include/asm/asm.h
+index 2bec0c89a95c2..e9653ee72813c 100644
+--- a/arch/x86/include/asm/asm.h
++++ b/arch/x86/include/asm/asm.h
+@@ -2,7 +2,7 @@
+ #ifndef _ASM_X86_ASM_H
+ #define _ASM_X86_ASM_H
+
+-#ifdef __ASSEMBLY__
++#ifdef __ASSEMBLER__
+ # define __ASM_FORM(x, ...) x,## __VA_ARGS__
+ # define __ASM_FORM_RAW(x, ...) x,## __VA_ARGS__
+ # define __ASM_FORM_COMMA(x, ...) x,## __VA_ARGS__,
+@@ -113,7 +113,7 @@
+
+ #endif
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ #ifndef __pic__
+ static __always_inline __pure void *rip_rel_ptr(void *p)
+ {
+@@ -144,7 +144,7 @@ static __always_inline __pure void *rip_rel_ptr(void *p)
+ # include <asm/extable_fixup_types.h>
+
+ /* Exception table entry */
+-#ifdef __ASSEMBLY__
++#ifdef __ASSEMBLER__
+
+ # define _ASM_EXTABLE_TYPE(from, to, type) \
+ .pushsection "__ex_table","a" ; \
+@@ -164,7 +164,7 @@ static __always_inline __pure void *rip_rel_ptr(void *p)
+ # define _ASM_NOKPROBE(entry)
+ # endif
+
+-#else /* ! __ASSEMBLY__ */
++#else /* ! __ASSEMBLER__ */
+
+ # define DEFINE_EXTABLE_TYPE_REG \
+ ".macro extable_type_reg type:req reg:req\n" \
+@@ -221,7 +221,7 @@ static __always_inline __pure void *rip_rel_ptr(void *p)
+ */
+ register unsigned long current_stack_pointer asm(_ASM_SP);
+ #define ASM_CALL_CONSTRAINT "+r" (current_stack_pointer)
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ #define _ASM_EXTABLE(from, to) \
+ _ASM_EXTABLE_TYPE(from, to, EX_TYPE_DEFAULT)
+diff --git a/arch/x86/include/asm/boot.h b/arch/x86/include/asm/boot.h
+index 3e5b111e619d4..3f02ff6d333d3 100644
+--- a/arch/x86/include/asm/boot.h
++++ b/arch/x86/include/asm/boot.h
+@@ -74,7 +74,7 @@
+ # define BOOT_STACK_SIZE 0x1000
+ #endif
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ extern unsigned int output_len;
+ extern const unsigned long kernel_text_size;
+ extern const unsigned long kernel_total_size;
+diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
+index de1ad09fe8d72..7e67bacf02f37 100644
+--- a/arch/x86/include/asm/cpufeature.h
++++ b/arch/x86/include/asm/cpufeature.h
+@@ -4,7 +4,7 @@
+
+ #include <asm/processor.h>
+
+-#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
++#if defined(__KERNEL__) && !defined(__ASSEMBLER__)
+
+ #include <asm/asm.h>
+ #include <linux/bitops.h>
+@@ -208,5 +208,5 @@ static __always_inline bool _static_cpu_has(u16 bit)
+ #define CPU_FEATURE_TYPEVAL boot_cpu_data.x86_vendor, boot_cpu_data.x86, \
+ boot_cpu_data.x86_model
+
+-#endif /* defined(__KERNEL__) && !defined(__ASSEMBLY__) */
++#endif /* defined(__KERNEL__) && !defined(__ASSEMBLER__) */
+ #endif /* _ASM_X86_CPUFEATURE_H */
+diff --git a/arch/x86/include/asm/cpumask.h b/arch/x86/include/asm/cpumask.h
+index 4acfd57de8f1c..70f6b60ad67b9 100644
+--- a/arch/x86/include/asm/cpumask.h
++++ b/arch/x86/include/asm/cpumask.h
+@@ -1,7 +1,7 @@
+ /* SPDX-License-Identifier: GPL-2.0 */
+ #ifndef _ASM_X86_CPUMASK_H
+ #define _ASM_X86_CPUMASK_H
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ #include <linux/cpumask.h>
+
+ extern void setup_cpu_local_masks(void);
+@@ -34,5 +34,5 @@ static __always_inline void arch_cpumask_clear_cpu(int cpu, struct cpumask *dstp
+
+ #define arch_cpu_is_offline(cpu) unlikely(!arch_cpu_online(cpu))
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+ #endif /* _ASM_X86_CPUMASK_H */
+diff --git a/arch/x86/include/asm/current.h b/arch/x86/include/asm/current.h
+index bf5953883ec36..f2d0b38879808 100644
+--- a/arch/x86/include/asm/current.h
++++ b/arch/x86/include/asm/current.h
+@@ -5,7 +5,7 @@
+ #include <linux/build_bug.h>
+ #include <linux/compiler.h>
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ #include <linux/cache.h>
+ #include <asm/percpu.h>
+@@ -51,6 +51,6 @@ static __always_inline struct task_struct *get_current(void)
+
+ #define current get_current()
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ #endif /* _ASM_X86_CURRENT_H */
+diff --git a/arch/x86/include/asm/desc_defs.h b/arch/x86/include/asm/desc_defs.h
+index d440a65af8f39..7e6b9314758a1 100644
+--- a/arch/x86/include/asm/desc_defs.h
++++ b/arch/x86/include/asm/desc_defs.h
+@@ -58,7 +58,7 @@
+
+ #define DESC_USER (_DESC_DPL(3))
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ #include <linux/types.h>
+
+@@ -166,7 +166,7 @@ struct desc_ptr {
+ unsigned long address;
+ } __attribute__((packed)) ;
+
+-#endif /* !__ASSEMBLY__ */
++#endif /* !__ASSEMBLER__ */
+
+ /* Boot IDT definitions */
+ #define BOOT_IDT_ENTRIES 32
+diff --git a/arch/x86/include/asm/dwarf2.h b/arch/x86/include/asm/dwarf2.h
+index 430fca13bb568..302e11b15da86 100644
+--- a/arch/x86/include/asm/dwarf2.h
++++ b/arch/x86/include/asm/dwarf2.h
+@@ -2,7 +2,7 @@
+ #ifndef _ASM_X86_DWARF2_H
+ #define _ASM_X86_DWARF2_H
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ #warning "asm/dwarf2.h should be only included in pure assembly files"
+ #endif
+
+diff --git a/arch/x86/include/asm/fixmap.h b/arch/x86/include/asm/fixmap.h
+index d0dcefb5cc59d..4519c9f35ba04 100644
+--- a/arch/x86/include/asm/fixmap.h
++++ b/arch/x86/include/asm/fixmap.h
+@@ -31,7 +31,7 @@
+ /* fixmap starts downwards from the 507th entry in level2_fixmap_pgt */
+ #define FIXMAP_PMD_TOP 507
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ #include <linux/kernel.h>
+ #include <asm/apicdef.h>
+ #include <asm/page.h>
+@@ -196,5 +196,5 @@ void __init *early_memremap_decrypted_wp(resource_size_t phys_addr,
+ void __early_set_fixmap(enum fixed_addresses idx,
+ phys_addr_t phys, pgprot_t flags);
+
+-#endif /* !__ASSEMBLY__ */
++#endif /* !__ASSEMBLER__ */
+ #endif /* _ASM_X86_FIXMAP_H */
+diff --git a/arch/x86/include/asm/frame.h b/arch/x86/include/asm/frame.h
+index fb42659f6e988..0ab65073c1cc0 100644
+--- a/arch/x86/include/asm/frame.h
++++ b/arch/x86/include/asm/frame.h
+@@ -11,7 +11,7 @@
+
+ #ifdef CONFIG_FRAME_POINTER
+
+-#ifdef __ASSEMBLY__
++#ifdef __ASSEMBLER__
+
+ .macro FRAME_BEGIN
+ push %_ASM_BP
+@@ -51,7 +51,7 @@
+ .endm
+ #endif /* CONFIG_X86_64 */
+
+-#else /* !__ASSEMBLY__ */
++#else /* !__ASSEMBLER__ */
+
+ #define FRAME_BEGIN \
+ "push %" _ASM_BP "\n" \
+@@ -82,18 +82,18 @@ static inline unsigned long encode_frame_pointer(struct pt_regs *regs)
+
+ #endif /* CONFIG_X86_64 */
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ #define FRAME_OFFSET __ASM_SEL(4, 8)
+
+ #else /* !CONFIG_FRAME_POINTER */
+
+-#ifdef __ASSEMBLY__
++#ifdef __ASSEMBLER__
+
+ .macro ENCODE_FRAME_POINTER ptregs_offset=0
+ .endm
+
+-#else /* !__ASSEMBLY */
++#else /* !__ASSEMBLER__ */
+
+ #define ENCODE_FRAME_POINTER
+
+diff --git a/arch/x86/include/asm/fred.h b/arch/x86/include/asm/fred.h
+index 25ca00bd70e83..2a29e52168815 100644
+--- a/arch/x86/include/asm/fred.h
++++ b/arch/x86/include/asm/fred.h
+@@ -32,7 +32,7 @@
+ #define FRED_CONFIG_INT_STKLVL(l) (_AT(unsigned long, l) << 9)
+ #define FRED_CONFIG_ENTRYPOINT(p) _AT(unsigned long, (p))
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ #ifdef CONFIG_X86_FRED
+ #include <linux/kernel.h>
+@@ -113,6 +113,6 @@ static inline void fred_entry_from_kvm(unsigned int type, unsigned int vector) {
+ static inline void fred_sync_rsp0(unsigned long rsp0) { }
+ static inline void fred_update_rsp0(void) { }
+ #endif /* CONFIG_X86_FRED */
+-#endif /* !__ASSEMBLY__ */
++#endif /* !__ASSEMBLER__ */
+
+ #endif /* ASM_X86_FRED_H */
+diff --git a/arch/x86/include/asm/fsgsbase.h b/arch/x86/include/asm/fsgsbase.h
+index 9e7e8ca8e2997..02f239569b93d 100644
+--- a/arch/x86/include/asm/fsgsbase.h
++++ b/arch/x86/include/asm/fsgsbase.h
+@@ -2,7 +2,7 @@
+ #ifndef _ASM_FSGSBASE_H
+ #define _ASM_FSGSBASE_H
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ #ifdef CONFIG_X86_64
+
+@@ -80,6 +80,6 @@ extern unsigned long x86_fsgsbase_read_task(struct task_struct *task,
+
+ #endif /* CONFIG_X86_64 */
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ #endif /* _ASM_FSGSBASE_H */
+diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h
+index f9cb4d07df58f..2d02d5b0517c1 100644
+--- a/arch/x86/include/asm/ftrace.h
++++ b/arch/x86/include/asm/ftrace.h
+@@ -22,7 +22,7 @@
+ #define ARCH_SUPPORTS_FTRACE_OPS 1
+ #endif
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ extern void __fentry__(void);
+
+ static inline unsigned long ftrace_call_adjust(unsigned long addr)
+@@ -118,11 +118,11 @@ struct dyn_arch_ftrace {
+ };
+
+ #endif /* CONFIG_DYNAMIC_FTRACE */
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+ #endif /* CONFIG_FUNCTION_TRACER */
+
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ void prepare_ftrace_return(unsigned long ip, unsigned long *parent,
+ unsigned long frame_pointer);
+@@ -166,6 +166,6 @@ static inline bool arch_trace_is_compat_syscall(struct pt_regs *regs)
+ }
+ #endif /* CONFIG_FTRACE_SYSCALLS && CONFIG_IA32_EMULATION */
+ #endif /* !COMPILE_OFFSETS */
+-#endif /* !__ASSEMBLY__ */
++#endif /* !__ASSEMBLER__ */
+
+ #endif /* _ASM_X86_FTRACE_H */
+diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h
+index edebf1020e049..162ebd73a6981 100644
+--- a/arch/x86/include/asm/hw_irq.h
++++ b/arch/x86/include/asm/hw_irq.h
+@@ -16,7 +16,7 @@
+
+ #include <asm/irq_vectors.h>
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ #include <linux/percpu.h>
+ #include <linux/profile.h>
+@@ -128,6 +128,6 @@ extern char spurious_entries_start[];
+ typedef struct irq_desc* vector_irq_t[NR_VECTORS];
+ DECLARE_PER_CPU(vector_irq_t, vector_irq);
+
+-#endif /* !ASSEMBLY_ */
++#endif /* !__ASSEMBLER__ */
+
+ #endif /* _ASM_X86_HW_IRQ_H */
+diff --git a/arch/x86/include/asm/ibt.h b/arch/x86/include/asm/ibt.h
+index 1e59581d500ca..e7f4caa42839a 100644
+--- a/arch/x86/include/asm/ibt.h
++++ b/arch/x86/include/asm/ibt.h
+@@ -21,7 +21,7 @@
+
+ #define HAS_KERNEL_IBT 1
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ #ifdef CONFIG_X86_64
+ #define ASM_ENDBR "endbr64\n\t"
+@@ -77,7 +77,7 @@ static inline bool is_endbr(u32 val)
+ extern __noendbr u64 ibt_save(bool disable);
+ extern __noendbr void ibt_restore(u64 save);
+
+-#else /* __ASSEMBLY__ */
++#else /* __ASSEMBLER__ */
+
+ #ifdef CONFIG_X86_64
+ #define ENDBR endbr64
+@@ -85,13 +85,13 @@ extern __noendbr void ibt_restore(u64 save);
+ #define ENDBR endbr32
+ #endif
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ #else /* !IBT */
+
+ #define HAS_KERNEL_IBT 0
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ #define ASM_ENDBR
+ #define IBT_NOSEAL(name)
+@@ -103,11 +103,11 @@ static inline bool is_endbr(u32 val) { return false; }
+ static inline u64 ibt_save(bool disable) { return 0; }
+ static inline void ibt_restore(u64 save) { }
+
+-#else /* __ASSEMBLY__ */
++#else /* __ASSEMBLER__ */
+
+ #define ENDBR
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ #endif /* CONFIG_X86_KERNEL_IBT */
+
+diff --git a/arch/x86/include/asm/idtentry.h b/arch/x86/include/asm/idtentry.h
+index ad5c68f0509d4..a4ec27c679887 100644
+--- a/arch/x86/include/asm/idtentry.h
++++ b/arch/x86/include/asm/idtentry.h
+@@ -7,7 +7,7 @@
+
+ #define IDT_ALIGN (8 * (1 + HAS_KERNEL_IBT))
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ #include <linux/entry-common.h>
+ #include <linux/hardirq.h>
+
+@@ -474,7 +474,7 @@ static inline void fred_install_sysvec(unsigned int vector, const idtentry_t fun
+ idt_install_sysvec(vector, asm_##function); \
+ }
+
+-#else /* !__ASSEMBLY__ */
++#else /* !__ASSEMBLER__ */
+
+ /*
+ * The ASM variants for DECLARE_IDTENTRY*() which emit the ASM entry stubs.
+@@ -579,7 +579,7 @@ SYM_CODE_START(spurious_entries_start)
+ SYM_CODE_END(spurious_entries_start)
+ #endif
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ /*
+ * The actual entry points. Note that DECLARE_IDTENTRY*() serves two
+diff --git a/arch/x86/include/asm/inst.h b/arch/x86/include/asm/inst.h
+index 438ccd4f3cc45..e48a00b3311d5 100644
+--- a/arch/x86/include/asm/inst.h
++++ b/arch/x86/include/asm/inst.h
+@@ -6,7 +6,7 @@
+ #ifndef X86_ASM_INST_H
+ #define X86_ASM_INST_H
+
+-#ifdef __ASSEMBLY__
++#ifdef __ASSEMBLER__
+
+ #define REG_NUM_INVALID 100
+
+diff --git a/arch/x86/include/asm/irqflags.h b/arch/x86/include/asm/irqflags.h
+index 1c2db11a2c3cb..9a9b21b78905a 100644
+--- a/arch/x86/include/asm/irqflags.h
++++ b/arch/x86/include/asm/irqflags.h
+@@ -4,7 +4,7 @@
+
+ #include <asm/processor-flags.h>
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ #include <asm/nospec-branch.h>
+
+@@ -101,7 +101,7 @@ static __always_inline void halt(void)
+ #ifdef CONFIG_PARAVIRT_XXL
+ #include <asm/paravirt.h>
+ #else
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ #include <linux/types.h>
+
+ static __always_inline unsigned long arch_local_save_flags(void)
+@@ -137,10 +137,10 @@ static __always_inline unsigned long arch_local_irq_save(void)
+
+ #endif
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+ #endif /* CONFIG_PARAVIRT_XXL */
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ static __always_inline int arch_irqs_disabled_flags(unsigned long flags)
+ {
+ return !(flags & X86_EFLAGS_IF);
+@@ -158,6 +158,6 @@ static __always_inline void arch_local_irq_restore(unsigned long flags)
+ if (!arch_irqs_disabled_flags(flags))
+ arch_local_irq_enable();
+ }
+-#endif /* !__ASSEMBLY__ */
++#endif /* !__ASSEMBLER__ */
+
+ #endif
+diff --git a/arch/x86/include/asm/jump_label.h b/arch/x86/include/asm/jump_label.h
+index 3f1c1d6c0da12..61dd1dee7812e 100644
+--- a/arch/x86/include/asm/jump_label.h
++++ b/arch/x86/include/asm/jump_label.h
+@@ -7,7 +7,7 @@
+ #include <asm/asm.h>
+ #include <asm/nops.h>
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ #include <linux/stringify.h>
+ #include <linux/types.h>
+@@ -55,6 +55,6 @@ static __always_inline bool arch_static_branch_jump(struct static_key * const ke
+
+ extern int arch_jump_entry_size(struct jump_entry *entry);
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ #endif
+diff --git a/arch/x86/include/asm/kasan.h b/arch/x86/include/asm/kasan.h
+index de75306b932ef..d7e33c7f096b0 100644
+--- a/arch/x86/include/asm/kasan.h
++++ b/arch/x86/include/asm/kasan.h
+@@ -23,7 +23,7 @@
+ (1ULL << (__VIRTUAL_MASK_SHIFT - \
+ KASAN_SHADOW_SCALE_SHIFT)))
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ #ifdef CONFIG_KASAN
+ void __init kasan_early_init(void);
+diff --git a/arch/x86/include/asm/kexec.h b/arch/x86/include/asm/kexec.h
+index 8ad187462b68e..c75509241ff28 100644
+--- a/arch/x86/include/asm/kexec.h
++++ b/arch/x86/include/asm/kexec.h
+@@ -13,7 +13,7 @@
+ # define KEXEC_CONTROL_PAGE_SIZE 4096
+ # define KEXEC_CONTROL_CODE_MAX_SIZE 2048
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ #include <linux/string.h>
+ #include <linux/kernel.h>
+@@ -225,6 +225,6 @@ unsigned int arch_crash_get_elfcorehdr_size(void);
+ #define crash_get_elfcorehdr_size arch_crash_get_elfcorehdr_size
+ #endif
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ #endif /* _ASM_X86_KEXEC_H */
+diff --git a/arch/x86/include/asm/linkage.h b/arch/x86/include/asm/linkage.h
+index dc31b13b87a0d..c95dad65801d5 100644
+--- a/arch/x86/include/asm/linkage.h
++++ b/arch/x86/include/asm/linkage.h
+@@ -38,7 +38,7 @@
+ #define ASM_FUNC_ALIGN __stringify(__FUNC_ALIGN)
+ #define SYM_F_ALIGN __FUNC_ALIGN
+
+-#ifdef __ASSEMBLY__
++#ifdef __ASSEMBLER__
+
+ #if defined(CONFIG_MITIGATION_RETHUNK) && !defined(__DISABLE_EXPORTS) && !defined(BUILD_VDSO)
+ #define RET jmp __x86_return_thunk
+@@ -50,7 +50,7 @@
+ #endif
+ #endif /* CONFIG_MITIGATION_RETPOLINE */
+
+-#else /* __ASSEMBLY__ */
++#else /* __ASSEMBLER__ */
+
+ #if defined(CONFIG_MITIGATION_RETHUNK) && !defined(__DISABLE_EXPORTS) && !defined(BUILD_VDSO)
+ #define ASM_RET "jmp __x86_return_thunk\n\t"
+@@ -62,7 +62,7 @@
+ #endif
+ #endif /* CONFIG_MITIGATION_RETPOLINE */
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ /*
+ * Depending on -fpatchable-function-entry=N,N usage (CONFIG_CALL_PADDING) the
+diff --git a/arch/x86/include/asm/mem_encrypt.h b/arch/x86/include/asm/mem_encrypt.h
+index f922b682b9b4c..1530ee301dfea 100644
+--- a/arch/x86/include/asm/mem_encrypt.h
++++ b/arch/x86/include/asm/mem_encrypt.h
+@@ -10,7 +10,7 @@
+ #ifndef __X86_MEM_ENCRYPT_H__
+ #define __X86_MEM_ENCRYPT_H__
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ #include <linux/init.h>
+ #include <linux/cc_platform.h>
+@@ -114,6 +114,6 @@ void add_encrypt_protection_map(void);
+
+ extern char __start_bss_decrypted[], __end_bss_decrypted[], __start_bss_decrypted_unused[];
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ #endif /* __X86_MEM_ENCRYPT_H__ */
+diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h
+index 001853541f1e8..9397a319d165d 100644
+--- a/arch/x86/include/asm/msr.h
++++ b/arch/x86/include/asm/msr.h
+@@ -4,7 +4,7 @@
+
+ #include "msr-index.h"
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ #include <asm/asm.h>
+ #include <asm/errno.h>
+@@ -397,5 +397,5 @@ static inline int wrmsr_safe_regs_on_cpu(unsigned int cpu, u32 regs[8])
+ return wrmsr_safe_regs(regs);
+ }
+ #endif /* CONFIG_SMP */
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+ #endif /* _ASM_X86_MSR_H */
+diff --git a/arch/x86/include/asm/nops.h b/arch/x86/include/asm/nops.h
+index 1c1b7550fa550..cd94221d83358 100644
+--- a/arch/x86/include/asm/nops.h
++++ b/arch/x86/include/asm/nops.h
+@@ -82,7 +82,7 @@
+ #define ASM_NOP7 _ASM_BYTES(BYTES_NOP7)
+ #define ASM_NOP8 _ASM_BYTES(BYTES_NOP8)
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ extern const unsigned char * const x86_nops[];
+ #endif
+
+diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h
+index b1ac1d0d29ca8..0cc2d535e5c5f 100644
+--- a/arch/x86/include/asm/nospec-branch.h
++++ b/arch/x86/include/asm/nospec-branch.h
+@@ -177,7 +177,7 @@
+ add $(BITS_PER_LONG/8), %_ASM_SP; \
+ lfence;
+
+-#ifdef __ASSEMBLY__
++#ifdef __ASSEMBLER__
+
+ /*
+ * (ab)use RETPOLINE_SAFE on RET to annotate away 'bare' RET instructions
+@@ -335,7 +335,7 @@
+ #define CLEAR_BRANCH_HISTORY_VMEXIT
+ #endif
+
+-#else /* __ASSEMBLY__ */
++#else /* __ASSEMBLER__ */
+
+ #define ITS_THUNK_SIZE 64
+
+@@ -612,6 +612,6 @@ static __always_inline void mds_idle_clear_cpu_buffers(void)
+ mds_clear_cpu_buffers();
+ }
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ #endif /* _ASM_X86_NOSPEC_BRANCH_H_ */
+diff --git a/arch/x86/include/asm/orc_types.h b/arch/x86/include/asm/orc_types.h
+index 46d7e06763c9f..e0125afa53fb9 100644
+--- a/arch/x86/include/asm/orc_types.h
++++ b/arch/x86/include/asm/orc_types.h
+@@ -45,7 +45,7 @@
+ #define ORC_TYPE_REGS 3
+ #define ORC_TYPE_REGS_PARTIAL 4
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ #include <asm/byteorder.h>
+
+ /*
+@@ -73,6 +73,6 @@ struct orc_entry {
+ #endif
+ } __packed;
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ #endif /* _ORC_TYPES_H */
+diff --git a/arch/x86/include/asm/page.h b/arch/x86/include/asm/page.h
+index c9fe207916f48..9265f2fca99ae 100644
+--- a/arch/x86/include/asm/page.h
++++ b/arch/x86/include/asm/page.h
+@@ -14,7 +14,7 @@
+ #include <asm/page_32.h>
+ #endif /* CONFIG_X86_64 */
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ struct page;
+
+@@ -84,7 +84,7 @@ static __always_inline u64 __is_canonical_address(u64 vaddr, u8 vaddr_bits)
+ return __canonical_address(vaddr, vaddr_bits) == vaddr;
+ }
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ #include <asm-generic/memory_model.h>
+ #include <asm-generic/getorder.h>
+diff --git a/arch/x86/include/asm/page_32.h b/arch/x86/include/asm/page_32.h
+index 580d71aca65a4..0c623706cb7ef 100644
+--- a/arch/x86/include/asm/page_32.h
++++ b/arch/x86/include/asm/page_32.h
+@@ -4,7 +4,7 @@
+
+ #include <asm/page_32_types.h>
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ #define __phys_addr_nodebug(x) ((x) - PAGE_OFFSET)
+ #ifdef CONFIG_DEBUG_VIRTUAL
+@@ -26,6 +26,6 @@ static inline void copy_page(void *to, void *from)
+ {
+ memcpy(to, from, PAGE_SIZE);
+ }
+-#endif /* !__ASSEMBLY__ */
++#endif /* !__ASSEMBLER__ */
+
+ #endif /* _ASM_X86_PAGE_32_H */
+diff --git a/arch/x86/include/asm/page_32_types.h b/arch/x86/include/asm/page_32_types.h
+index faf9cc1c14bb6..88e3c8d582986 100644
+--- a/arch/x86/include/asm/page_32_types.h
++++ b/arch/x86/include/asm/page_32_types.h
+@@ -63,7 +63,7 @@
+ */
+ #define KERNEL_IMAGE_SIZE (512 * 1024 * 1024)
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ /*
+ * This much address space is reserved for vmalloc() and iomap()
+@@ -75,6 +75,6 @@ extern int sysctl_legacy_va_layout;
+ extern void find_low_pfn_range(void);
+ extern void setup_bootmem_allocator(void);
+
+-#endif /* !__ASSEMBLY__ */
++#endif /* !__ASSEMBLER__ */
+
+ #endif /* _ASM_X86_PAGE_32_DEFS_H */
+diff --git a/arch/x86/include/asm/page_64.h b/arch/x86/include/asm/page_64.h
+index d63576608ce76..442357defa117 100644
+--- a/arch/x86/include/asm/page_64.h
++++ b/arch/x86/include/asm/page_64.h
+@@ -4,7 +4,7 @@
+
+ #include <asm/page_64_types.h>
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ #include <asm/cpufeatures.h>
+ #include <asm/alternative.h>
+
+@@ -94,7 +94,7 @@ static __always_inline unsigned long task_size_max(void)
+ }
+ #endif /* CONFIG_X86_5LEVEL */
+
+-#endif /* !__ASSEMBLY__ */
++#endif /* !__ASSEMBLER__ */
+
+ #ifdef CONFIG_X86_VSYSCALL_EMULATION
+ # define __HAVE_ARCH_GATE_AREA 1
+diff --git a/arch/x86/include/asm/page_64_types.h b/arch/x86/include/asm/page_64_types.h
+index 06ef25411d622..1faa8f88850ab 100644
+--- a/arch/x86/include/asm/page_64_types.h
++++ b/arch/x86/include/asm/page_64_types.h
+@@ -2,7 +2,7 @@
+ #ifndef _ASM_X86_PAGE_64_DEFS_H
+ #define _ASM_X86_PAGE_64_DEFS_H
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ #include <asm/kaslr.h>
+ #endif
+
+diff --git a/arch/x86/include/asm/page_types.h b/arch/x86/include/asm/page_types.h
+index 974688973cf6e..9f77bf03d7472 100644
+--- a/arch/x86/include/asm/page_types.h
++++ b/arch/x86/include/asm/page_types.h
+@@ -43,7 +43,7 @@
+ #define IOREMAP_MAX_ORDER (PMD_SHIFT)
+ #endif /* CONFIG_X86_64 */
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ #ifdef CONFIG_DYNAMIC_PHYSICAL_MASK
+ extern phys_addr_t physical_mask;
+@@ -66,6 +66,6 @@ bool pfn_range_is_mapped(unsigned long start_pfn, unsigned long end_pfn);
+
+ extern void initmem_init(void);
+
+-#endif /* !__ASSEMBLY__ */
++#endif /* !__ASSEMBLER__ */
+
+ #endif /* _ASM_X86_PAGE_DEFS_H */
+diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h
+index 29e7331a0c98d..0ace044d6f2cd 100644
+--- a/arch/x86/include/asm/paravirt.h
++++ b/arch/x86/include/asm/paravirt.h
+@@ -6,7 +6,7 @@
+
+ #include <asm/paravirt_types.h>
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ struct mm_struct;
+ #endif
+
+@@ -15,7 +15,7 @@ struct mm_struct;
+ #include <asm/asm.h>
+ #include <asm/nospec-branch.h>
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ #include <linux/bug.h>
+ #include <linux/types.h>
+ #include <linux/cpumask.h>
+@@ -720,7 +720,7 @@ static __always_inline unsigned long arch_local_irq_save(void)
+ extern void default_banner(void);
+ void native_pv_lock_init(void) __init;
+
+-#else /* __ASSEMBLY__ */
++#else /* __ASSEMBLER__ */
+
+ #ifdef CONFIG_X86_64
+ #ifdef CONFIG_PARAVIRT_XXL
+@@ -740,18 +740,18 @@ void native_pv_lock_init(void) __init;
+ #endif /* CONFIG_PARAVIRT_XXL */
+ #endif /* CONFIG_X86_64 */
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+ #else /* CONFIG_PARAVIRT */
+ # define default_banner x86_init_noop
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ static inline void native_pv_lock_init(void)
+ {
+ }
+ #endif
+ #endif /* !CONFIG_PARAVIRT */
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ #ifndef CONFIG_PARAVIRT_XXL
+ static inline void paravirt_enter_mmap(struct mm_struct *mm)
+ {
+@@ -769,5 +769,5 @@ static inline void paravirt_set_cap(void)
+ {
+ }
+ #endif
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+ #endif /* _ASM_X86_PARAVIRT_H */
+diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h
+index abccfccc2e3fa..1fca6281988a9 100644
+--- a/arch/x86/include/asm/paravirt_types.h
++++ b/arch/x86/include/asm/paravirt_types.h
+@@ -4,7 +4,7 @@
+
+ #ifdef CONFIG_PARAVIRT
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ #include <linux/types.h>
+
+ #include <asm/desc_defs.h>
+@@ -518,7 +518,7 @@ unsigned long pv_native_read_cr2(void);
+
+ #define paravirt_nop ((void *)nop_func)
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ #define ALT_NOT_XEN ALT_NOT(X86_FEATURE_XENPV)
+
+diff --git a/arch/x86/include/asm/percpu.h b/arch/x86/include/asm/percpu.h
+index e525cd85f999f..afb9099fba9fc 100644
+--- a/arch/x86/include/asm/percpu.h
++++ b/arch/x86/include/asm/percpu.h
+@@ -10,7 +10,7 @@
+ # define __percpu_rel
+ #endif
+
+-#ifdef __ASSEMBLY__
++#ifdef __ASSEMBLER__
+
+ #ifdef CONFIG_SMP
+ # define __percpu %__percpu_seg:
+@@ -619,7 +619,7 @@ do { \
+ /* We can use this directly for local CPU (faster). */
+ DECLARE_PER_CPU_READ_MOSTLY(unsigned long, this_cpu_off);
+
+-#endif /* !__ASSEMBLY__ */
++#endif /* !__ASSEMBLER__ */
+
+ #ifdef CONFIG_SMP
+
+diff --git a/arch/x86/include/asm/pgtable-2level_types.h b/arch/x86/include/asm/pgtable-2level_types.h
+index 4a12c276b1812..66425424ce91a 100644
+--- a/arch/x86/include/asm/pgtable-2level_types.h
++++ b/arch/x86/include/asm/pgtable-2level_types.h
+@@ -2,7 +2,7 @@
+ #ifndef _ASM_X86_PGTABLE_2LEVEL_DEFS_H
+ #define _ASM_X86_PGTABLE_2LEVEL_DEFS_H
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ #include <linux/types.h>
+
+ typedef unsigned long pteval_t;
+@@ -16,7 +16,7 @@ typedef union {
+ pteval_t pte;
+ pteval_t pte_low;
+ } pte_t;
+-#endif /* !__ASSEMBLY__ */
++#endif /* !__ASSEMBLER__ */
+
+ #define SHARED_KERNEL_PMD 0
+
+diff --git a/arch/x86/include/asm/pgtable-3level_types.h b/arch/x86/include/asm/pgtable-3level_types.h
+index 80911349519e8..9d5b257d44e3c 100644
+--- a/arch/x86/include/asm/pgtable-3level_types.h
++++ b/arch/x86/include/asm/pgtable-3level_types.h
+@@ -2,7 +2,7 @@
+ #ifndef _ASM_X86_PGTABLE_3LEVEL_DEFS_H
+ #define _ASM_X86_PGTABLE_3LEVEL_DEFS_H
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ #include <linux/types.h>
+
+ typedef u64 pteval_t;
+@@ -25,7 +25,7 @@ typedef union {
+ };
+ pmdval_t pmd;
+ } pmd_t;
+-#endif /* !__ASSEMBLY__ */
++#endif /* !__ASSEMBLER__ */
+
+ #define SHARED_KERNEL_PMD (!static_cpu_has(X86_FEATURE_PTI))
+
+diff --git a/arch/x86/include/asm/pgtable-invert.h b/arch/x86/include/asm/pgtable-invert.h
+index a0c1525f1b6f4..e12e52ae8083d 100644
+--- a/arch/x86/include/asm/pgtable-invert.h
++++ b/arch/x86/include/asm/pgtable-invert.h
+@@ -2,7 +2,7 @@
+ #ifndef _ASM_PGTABLE_INVERT_H
+ #define _ASM_PGTABLE_INVERT_H 1
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ /*
+ * A clear pte value is special, and doesn't get inverted.
+@@ -36,6 +36,6 @@ static inline u64 flip_protnone_guard(u64 oldval, u64 val, u64 mask)
+ return val;
+ }
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ #endif
+diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
+index 593f10aabd45a..7bd6bd6df4a11 100644
+--- a/arch/x86/include/asm/pgtable.h
++++ b/arch/x86/include/asm/pgtable.h
+@@ -15,7 +15,7 @@
+ cachemode2protval(_PAGE_CACHE_MODE_UC_MINUS))) \
+ : (prot))
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ #include <linux/spinlock.h>
+ #include <asm/x86_init.h>
+ #include <asm/pkru.h>
+@@ -973,7 +973,7 @@ static inline pgd_t pti_set_user_pgtbl(pgd_t *pgdp, pgd_t pgd)
+ }
+ #endif /* CONFIG_MITIGATION_PAGE_TABLE_ISOLATION */
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+
+ #ifdef CONFIG_X86_32
+@@ -982,7 +982,7 @@ static inline pgd_t pti_set_user_pgtbl(pgd_t *pgdp, pgd_t pgd)
+ # include <asm/pgtable_64.h>
+ #endif
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ #include <linux/mm_types.h>
+ #include <linux/mmdebug.h>
+ #include <linux/log2.h>
+@@ -1233,12 +1233,12 @@ static inline int pgd_none(pgd_t pgd)
+ }
+ #endif /* CONFIG_PGTABLE_LEVELS > 4 */
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ #define KERNEL_PGD_BOUNDARY pgd_index(PAGE_OFFSET)
+ #define KERNEL_PGD_PTRS (PTRS_PER_PGD - KERNEL_PGD_BOUNDARY)
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ extern int direct_gbpages;
+ void init_mem_mapping(void);
+@@ -1812,6 +1812,6 @@ bool arch_is_platform_page(u64 paddr);
+ WARN_ON_ONCE(pgd_present(*pgdp) && !pgd_same(*pgdp, pgd)); \
+ set_pgd(pgdp, pgd); \
+ })
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ #endif /* _ASM_X86_PGTABLE_H */
+diff --git a/arch/x86/include/asm/pgtable_32.h b/arch/x86/include/asm/pgtable_32.h
+index 7d4ad8907297c..b612cc57a4d34 100644
+--- a/arch/x86/include/asm/pgtable_32.h
++++ b/arch/x86/include/asm/pgtable_32.h
+@@ -13,7 +13,7 @@
+ * This file contains the functions and defines necessary to modify and use
+ * the i386 page table tree.
+ */
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ #include <asm/processor.h>
+ #include <linux/threads.h>
+ #include <asm/paravirt.h>
+@@ -45,7 +45,7 @@ do { \
+ flush_tlb_one_kernel((vaddr)); \
+ } while (0)
+
+-#endif /* !__ASSEMBLY__ */
++#endif /* !__ASSEMBLER__ */
+
+ /*
+ * This is used to calculate the .brk reservation for initial pagetables.
+diff --git a/arch/x86/include/asm/pgtable_32_areas.h b/arch/x86/include/asm/pgtable_32_areas.h
+index b6355416a15a8..921148b429676 100644
+--- a/arch/x86/include/asm/pgtable_32_areas.h
++++ b/arch/x86/include/asm/pgtable_32_areas.h
+@@ -13,7 +13,7 @@
+ */
+ #define VMALLOC_OFFSET (8 * 1024 * 1024)
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ extern bool __vmalloc_start_set; /* set once high_memory is set */
+ #endif
+
+diff --git a/arch/x86/include/asm/pgtable_64.h b/arch/x86/include/asm/pgtable_64.h
+index d1426b64c1b97..b89f8f1194a9f 100644
+--- a/arch/x86/include/asm/pgtable_64.h
++++ b/arch/x86/include/asm/pgtable_64.h
+@@ -5,7 +5,7 @@
+ #include <linux/const.h>
+ #include <asm/pgtable_64_types.h>
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ /*
+ * This file contains the functions and defines necessary to modify and use
+@@ -270,7 +270,7 @@ static inline bool gup_fast_permitted(unsigned long start, unsigned long end)
+
+ #include <asm/pgtable-invert.h>
+
+-#else /* __ASSEMBLY__ */
++#else /* __ASSEMBLER__ */
+
+ #define l4_index(x) (((x) >> 39) & 511)
+ #define pud_index(x) (((x) >> PUD_SHIFT) & (PTRS_PER_PUD - 1))
+@@ -291,5 +291,5 @@ L3_START_KERNEL = pud_index(__START_KERNEL_map)
+ i = i + 1 ; \
+ .endr
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+ #endif /* _ASM_X86_PGTABLE_64_H */
+diff --git a/arch/x86/include/asm/pgtable_64_types.h b/arch/x86/include/asm/pgtable_64_types.h
+index ec68f8369bdca..5bb782d856f2c 100644
+--- a/arch/x86/include/asm/pgtable_64_types.h
++++ b/arch/x86/include/asm/pgtable_64_types.h
+@@ -4,7 +4,7 @@
+
+ #include <asm/sparsemem.h>
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ #include <linux/types.h>
+ #include <asm/kaslr.h>
+
+@@ -44,7 +44,7 @@ static inline bool pgtable_l5_enabled(void)
+ extern unsigned int pgdir_shift;
+ extern unsigned int ptrs_per_p4d;
+
+-#endif /* !__ASSEMBLY__ */
++#endif /* !__ASSEMBLER__ */
+
+ #define SHARED_KERNEL_PMD 0
+
+diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h
+index 4b804531b03c3..ded7075c60634 100644
+--- a/arch/x86/include/asm/pgtable_types.h
++++ b/arch/x86/include/asm/pgtable_types.h
+@@ -164,7 +164,7 @@
+ * to have the WB mode at index 0 (all bits clear). This is the default
+ * right now and likely would break too much if changed.
+ */
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ enum page_cache_mode {
+ _PAGE_CACHE_MODE_WB = 0,
+ _PAGE_CACHE_MODE_WC = 1,
+@@ -239,7 +239,7 @@ enum page_cache_mode {
+ #define __PAGE_KERNEL_IO_NOCACHE __PAGE_KERNEL_NOCACHE
+
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ #define __PAGE_KERNEL_ENC (__PAGE_KERNEL | _ENC)
+ #define __PAGE_KERNEL_ENC_WP (__PAGE_KERNEL_WP | _ENC)
+@@ -262,7 +262,7 @@ enum page_cache_mode {
+ #define PAGE_KERNEL_IO __pgprot_mask(__PAGE_KERNEL_IO)
+ #define PAGE_KERNEL_IO_NOCACHE __pgprot_mask(__PAGE_KERNEL_IO_NOCACHE)
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ /*
+ * early identity mapping pte attrib macros.
+@@ -281,7 +281,7 @@ enum page_cache_mode {
+ # include <asm/pgtable_64_types.h>
+ #endif
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ #include <linux/types.h>
+
+@@ -580,6 +580,6 @@ extern int __init kernel_map_pages_in_pgd(pgd_t *pgd, u64 pfn,
+ unsigned long page_flags);
+ extern int __init kernel_unmap_pages_in_pgd(pgd_t *pgd, unsigned long address,
+ unsigned long numpages);
+-#endif /* !__ASSEMBLY__ */
++#endif /* !__ASSEMBLER__ */
+
+ #endif /* _ASM_X86_PGTABLE_DEFS_H */
+diff --git a/arch/x86/include/asm/prom.h b/arch/x86/include/asm/prom.h
+index 365798cb4408d..5d0dbab852640 100644
+--- a/arch/x86/include/asm/prom.h
++++ b/arch/x86/include/asm/prom.h
+@@ -8,7 +8,7 @@
+
+ #ifndef _ASM_X86_PROM_H
+ #define _ASM_X86_PROM_H
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ #include <linux/of.h>
+ #include <linux/types.h>
+@@ -33,5 +33,5 @@ static inline void x86_flattree_get_config(void) { }
+
+ extern char cmd_line[COMMAND_LINE_SIZE];
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+ #endif
+diff --git a/arch/x86/include/asm/pti.h b/arch/x86/include/asm/pti.h
+index ab167c96b9ab4..88d0a1ab1f77e 100644
+--- a/arch/x86/include/asm/pti.h
++++ b/arch/x86/include/asm/pti.h
+@@ -1,7 +1,7 @@
+ /* SPDX-License-Identifier: GPL-2.0 */
+ #ifndef _ASM_X86_PTI_H
+ #define _ASM_X86_PTI_H
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ #ifdef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION
+ extern void pti_init(void);
+@@ -11,5 +11,5 @@ extern void pti_finalize(void);
+ static inline void pti_check_boottime_disable(void) { }
+ #endif
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+ #endif /* _ASM_X86_PTI_H */
+diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h
+index 5a83fbd9bc0b4..50f75467f73d0 100644
+--- a/arch/x86/include/asm/ptrace.h
++++ b/arch/x86/include/asm/ptrace.h
+@@ -6,7 +6,7 @@
+ #include <asm/page_types.h>
+ #include <uapi/asm/ptrace.h>
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ #ifdef __i386__
+
+ struct pt_regs {
+@@ -469,5 +469,5 @@ extern int do_set_thread_area(struct task_struct *p, int idx,
+ # define do_set_thread_area_64(p, s, t) (0)
+ #endif
+
+-#endif /* !__ASSEMBLY__ */
++#endif /* !__ASSEMBLER__ */
+ #endif /* _ASM_X86_PTRACE_H */
+diff --git a/arch/x86/include/asm/purgatory.h b/arch/x86/include/asm/purgatory.h
+index 5528e93250494..2fee5e9f1ccc3 100644
+--- a/arch/x86/include/asm/purgatory.h
++++ b/arch/x86/include/asm/purgatory.h
+@@ -2,10 +2,10 @@
+ #ifndef _ASM_X86_PURGATORY_H
+ #define _ASM_X86_PURGATORY_H
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ #include <linux/purgatory.h>
+
+ extern void purgatory(void);
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ #endif /* _ASM_PURGATORY_H */
+diff --git a/arch/x86/include/asm/pvclock-abi.h b/arch/x86/include/asm/pvclock-abi.h
+index 1436226efe3ef..b9fece5fc96d6 100644
+--- a/arch/x86/include/asm/pvclock-abi.h
++++ b/arch/x86/include/asm/pvclock-abi.h
+@@ -1,7 +1,7 @@
+ /* SPDX-License-Identifier: GPL-2.0 */
+ #ifndef _ASM_X86_PVCLOCK_ABI_H
+ #define _ASM_X86_PVCLOCK_ABI_H
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ /*
+ * These structs MUST NOT be changed.
+@@ -44,5 +44,5 @@ struct pvclock_wall_clock {
+ #define PVCLOCK_GUEST_STOPPED (1 << 1)
+ /* PVCLOCK_COUNTS_FROM_ZERO broke ABI and can't be used anymore. */
+ #define PVCLOCK_COUNTS_FROM_ZERO (1 << 2)
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+ #endif /* _ASM_X86_PVCLOCK_ABI_H */
+diff --git a/arch/x86/include/asm/realmode.h b/arch/x86/include/asm/realmode.h
+index 87e5482acd0dc..f607081a022ab 100644
+--- a/arch/x86/include/asm/realmode.h
++++ b/arch/x86/include/asm/realmode.h
+@@ -9,7 +9,7 @@
+ #define TH_FLAGS_SME_ACTIVE_BIT 0
+ #define TH_FLAGS_SME_ACTIVE BIT(TH_FLAGS_SME_ACTIVE_BIT)
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ #include <linux/types.h>
+ #include <asm/io.h>
+@@ -95,6 +95,6 @@ void reserve_real_mode(void);
+ void load_trampoline_pgtable(void);
+ void init_real_mode(void);
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ #endif /* _ARCH_X86_REALMODE_H */
+diff --git a/arch/x86/include/asm/segment.h b/arch/x86/include/asm/segment.h
+index 9d6411c659205..77d8f49b92bdd 100644
+--- a/arch/x86/include/asm/segment.h
++++ b/arch/x86/include/asm/segment.h
+@@ -233,7 +233,7 @@
+ #define VDSO_CPUNODE_BITS 12
+ #define VDSO_CPUNODE_MASK 0xfff
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ /* Helper functions to store/load CPU and node numbers */
+
+@@ -265,7 +265,7 @@ static inline void vdso_read_cpunode(unsigned *cpu, unsigned *node)
+ *node = (p >> VDSO_CPUNODE_BITS);
+ }
+
+-#endif /* !__ASSEMBLY__ */
++#endif /* !__ASSEMBLER__ */
+
+ #ifdef __KERNEL__
+
+@@ -286,7 +286,7 @@ static inline void vdso_read_cpunode(unsigned *cpu, unsigned *node)
+ */
+ #define XEN_EARLY_IDT_HANDLER_SIZE (8 + ENDBR_INSN_SIZE)
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ extern const char early_idt_handler_array[NUM_EXCEPTION_VECTORS][EARLY_IDT_HANDLER_SIZE];
+ extern void early_ignore_irq(void);
+@@ -350,7 +350,7 @@ static inline void __loadsegment_fs(unsigned short value)
+ #define savesegment(seg, value) \
+ asm("mov %%" #seg ",%0":"=r" (value) : : "memory")
+
+-#endif /* !__ASSEMBLY__ */
++#endif /* !__ASSEMBLER__ */
+ #endif /* __KERNEL__ */
+
+ #endif /* _ASM_X86_SEGMENT_H */
+diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h
+index 85f4fde3515c4..09201d47c967b 100644
+--- a/arch/x86/include/asm/setup.h
++++ b/arch/x86/include/asm/setup.h
+@@ -27,7 +27,7 @@
+ #define OLD_CL_ADDRESS 0x020 /* Relative to real mode data */
+ #define NEW_CL_POINTER 0x228 /* Relative to real mode data */
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ #include <linux/cache.h>
+
+ #include <asm/bootparam.h>
+@@ -141,7 +141,7 @@ extern bool builtin_cmdline_added __ro_after_init;
+ #define builtin_cmdline_added 0
+ #endif
+
+-#else /* __ASSEMBLY */
++#else /* __ASSEMBLER__ */
+
+ .macro __RESERVE_BRK name, size
+ .pushsection .bss..brk, "aw"
+@@ -153,6 +153,6 @@ SYM_DATA_END(__brk_\name)
+
+ #define RESERVE_BRK(name, size) __RESERVE_BRK name, size
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ #endif /* _ASM_X86_SETUP_H */
+diff --git a/arch/x86/include/asm/setup_data.h b/arch/x86/include/asm/setup_data.h
+index 77c51111a8939..7bb16f843c93d 100644
+--- a/arch/x86/include/asm/setup_data.h
++++ b/arch/x86/include/asm/setup_data.h
+@@ -4,7 +4,7 @@
+
+ #include <uapi/asm/setup_data.h>
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ struct pci_setup_rom {
+ struct setup_data data;
+@@ -27,6 +27,6 @@ struct efi_setup_data {
+ u64 reserved[8];
+ };
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ #endif /* _ASM_X86_SETUP_DATA_H */
+diff --git a/arch/x86/include/asm/shared/tdx.h b/arch/x86/include/asm/shared/tdx.h
+index fcbbef484a78e..a28ff6b141458 100644
+--- a/arch/x86/include/asm/shared/tdx.h
++++ b/arch/x86/include/asm/shared/tdx.h
+@@ -106,7 +106,7 @@
+ #define TDX_PS_1G 2
+ #define TDX_PS_NR (TDX_PS_1G + 1)
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ #include <linux/compiler_attributes.h>
+
+@@ -177,5 +177,5 @@ static __always_inline u64 hcall_func(u64 exit_reason)
+ return exit_reason;
+ }
+
+-#endif /* !__ASSEMBLY__ */
++#endif /* !__ASSEMBLER__ */
+ #endif /* _ASM_X86_SHARED_TDX_H */
+diff --git a/arch/x86/include/asm/shstk.h b/arch/x86/include/asm/shstk.h
+index 4cb77e004615d..ba6f2fe438488 100644
+--- a/arch/x86/include/asm/shstk.h
++++ b/arch/x86/include/asm/shstk.h
+@@ -2,7 +2,7 @@
+ #ifndef _ASM_X86_SHSTK_H
+ #define _ASM_X86_SHSTK_H
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ #include <linux/types.h>
+
+ struct task_struct;
+@@ -37,6 +37,6 @@ static inline int shstk_update_last_frame(unsigned long val) { return 0; }
+ static inline bool shstk_is_enabled(void) { return false; }
+ #endif /* CONFIG_X86_USER_SHADOW_STACK */
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ #endif /* _ASM_X86_SHSTK_H */
+diff --git a/arch/x86/include/asm/signal.h b/arch/x86/include/asm/signal.h
+index 4a4043ca64934..c72d461753742 100644
+--- a/arch/x86/include/asm/signal.h
++++ b/arch/x86/include/asm/signal.h
+@@ -2,7 +2,7 @@
+ #ifndef _ASM_X86_SIGNAL_H
+ #define _ASM_X86_SIGNAL_H
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ #include <linux/linkage.h>
+
+ /* Most things should be clean enough to redefine this at will, if care
+@@ -28,9 +28,9 @@ typedef struct {
+ #define SA_IA32_ABI 0x02000000u
+ #define SA_X32_ABI 0x01000000u
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+ #include <uapi/asm/signal.h>
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ #define __ARCH_HAS_SA_RESTORER
+
+@@ -101,5 +101,5 @@ struct pt_regs;
+
+ #endif /* !__i386__ */
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+ #endif /* _ASM_X86_SIGNAL_H */
+diff --git a/arch/x86/include/asm/smap.h b/arch/x86/include/asm/smap.h
+index 2de1e5a75c573..daea94c2993c5 100644
+--- a/arch/x86/include/asm/smap.h
++++ b/arch/x86/include/asm/smap.h
+@@ -13,7 +13,7 @@
+ #include <asm/cpufeatures.h>
+ #include <asm/alternative.h>
+
+-#ifdef __ASSEMBLY__
++#ifdef __ASSEMBLER__
+
+ #define ASM_CLAC \
+ ALTERNATIVE "", "clac", X86_FEATURE_SMAP
+@@ -21,7 +21,7 @@
+ #define ASM_STAC \
+ ALTERNATIVE "", "stac", X86_FEATURE_SMAP
+
+-#else /* __ASSEMBLY__ */
++#else /* __ASSEMBLER__ */
+
+ static __always_inline void clac(void)
+ {
+@@ -61,6 +61,6 @@ static __always_inline void smap_restore(unsigned long flags)
+ #define ASM_STAC \
+ ALTERNATIVE("", "stac", X86_FEATURE_SMAP)
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ #endif /* _ASM_X86_SMAP_H */
+diff --git a/arch/x86/include/asm/smp.h b/arch/x86/include/asm/smp.h
+index ca073f40698fa..d234a6321c189 100644
+--- a/arch/x86/include/asm/smp.h
++++ b/arch/x86/include/asm/smp.h
+@@ -1,7 +1,7 @@
+ /* SPDX-License-Identifier: GPL-2.0 */
+ #ifndef _ASM_X86_SMP_H
+ #define _ASM_X86_SMP_H
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ #include <linux/cpumask.h>
+
+ #include <asm/cpumask.h>
+@@ -175,7 +175,7 @@ extern void nmi_selftest(void);
+ extern unsigned int smpboot_control;
+ extern unsigned long apic_mmio_base;
+
+-#endif /* !__ASSEMBLY__ */
++#endif /* !__ASSEMBLER__ */
+
+ /* Control bits for startup_64 */
+ #define STARTUP_READ_APICID 0x80000000
+diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h
+index 40f9a97371a90..4a1922ec80cf7 100644
+--- a/arch/x86/include/asm/tdx.h
++++ b/arch/x86/include/asm/tdx.h
+@@ -30,7 +30,7 @@
+ #define TDX_SUCCESS 0ULL
+ #define TDX_RND_NO_ENTROPY 0x8000020300000000ULL
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ #include <uapi/asm/mce.h>
+
+@@ -126,5 +126,5 @@ static inline int tdx_enable(void) { return -ENODEV; }
+ static inline const char *tdx_dump_mce_info(struct mce *m) { return NULL; }
+ #endif /* CONFIG_INTEL_TDX_HOST */
+
+-#endif /* !__ASSEMBLY__ */
++#endif /* !__ASSEMBLER__ */
+ #endif /* _ASM_X86_TDX_H */
+diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h
+index a55c214f3ba64..9282465eea21d 100644
+--- a/arch/x86/include/asm/thread_info.h
++++ b/arch/x86/include/asm/thread_info.h
+@@ -54,7 +54,7 @@
+ * - this struct should fit entirely inside of one cache line
+ * - this struct shares the supervisor stack pages
+ */
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ struct task_struct;
+ #include <asm/cpufeature.h>
+ #include <linux/atomic.h>
+@@ -73,7 +73,7 @@ struct thread_info {
+ .flags = 0, \
+ }
+
+-#else /* !__ASSEMBLY__ */
++#else /* !__ASSEMBLER__ */
+
+ #include <asm/asm-offsets.h>
+
+@@ -161,7 +161,7 @@ struct thread_info {
+ *
+ * preempt_count needs to be 1 initially, until the scheduler is functional.
+ */
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ /*
+ * Walks up the stack frames to make sure that the specified object is
+@@ -213,7 +213,7 @@ static inline int arch_within_stack_frames(const void * const stack,
+ #endif
+ }
+
+-#endif /* !__ASSEMBLY__ */
++#endif /* !__ASSEMBLER__ */
+
+ /*
+ * Thread-synchronous status.
+@@ -224,7 +224,7 @@ static inline int arch_within_stack_frames(const void * const stack,
+ */
+ #define TS_COMPAT 0x0002 /* 32bit syscall active (64BIT)*/
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ #ifdef CONFIG_COMPAT
+ #define TS_I386_REGS_POKED 0x0004 /* regs poked by 32-bit ptracer */
+
+@@ -242,6 +242,6 @@ static inline int arch_within_stack_frames(const void * const stack,
+
+ extern void arch_setup_new_exec(void);
+ #define arch_setup_new_exec arch_setup_new_exec
+-#endif /* !__ASSEMBLY__ */
++#endif /* !__ASSEMBLER__ */
+
+ #endif /* _ASM_X86_THREAD_INFO_H */
+diff --git a/arch/x86/include/asm/unwind_hints.h b/arch/x86/include/asm/unwind_hints.h
+index 85cc57cb65392..8f4579c5a6f8b 100644
+--- a/arch/x86/include/asm/unwind_hints.h
++++ b/arch/x86/include/asm/unwind_hints.h
+@@ -5,7 +5,7 @@
+
+ #include "orc_types.h"
+
+-#ifdef __ASSEMBLY__
++#ifdef __ASSEMBLER__
+
+ .macro UNWIND_HINT_END_OF_STACK
+ UNWIND_HINT type=UNWIND_HINT_TYPE_END_OF_STACK
+@@ -88,6 +88,6 @@
+ #define UNWIND_HINT_RESTORE \
+ UNWIND_HINT(UNWIND_HINT_TYPE_RESTORE, 0, 0, 0)
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ #endif /* _ASM_X86_UNWIND_HINTS_H */
+diff --git a/arch/x86/include/asm/vdso/getrandom.h b/arch/x86/include/asm/vdso/getrandom.h
+index 2bf9c0e970c3e..785f8edcb9c99 100644
+--- a/arch/x86/include/asm/vdso/getrandom.h
++++ b/arch/x86/include/asm/vdso/getrandom.h
+@@ -5,7 +5,7 @@
+ #ifndef __ASM_VDSO_GETRANDOM_H
+ #define __ASM_VDSO_GETRANDOM_H
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ #include <asm/unistd.h>
+
+@@ -37,6 +37,6 @@ static __always_inline const struct vdso_rng_data *__arch_get_vdso_rng_data(void
+ return &vdso_rng_data;
+ }
+
+-#endif /* !__ASSEMBLY__ */
++#endif /* !__ASSEMBLER__ */
+
+ #endif /* __ASM_VDSO_GETRANDOM_H */
+diff --git a/arch/x86/include/asm/vdso/gettimeofday.h b/arch/x86/include/asm/vdso/gettimeofday.h
+index 375a34b0f3657..428f3f4c2235f 100644
+--- a/arch/x86/include/asm/vdso/gettimeofday.h
++++ b/arch/x86/include/asm/vdso/gettimeofday.h
+@@ -10,7 +10,7 @@
+ #ifndef __ASM_VDSO_GETTIMEOFDAY_H
+ #define __ASM_VDSO_GETTIMEOFDAY_H
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ #include <uapi/linux/time.h>
+ #include <asm/vgtod.h>
+@@ -350,6 +350,6 @@ static __always_inline u64 vdso_calc_ns(const struct vdso_data *vd, u64 cycles,
+ }
+ #define vdso_calc_ns vdso_calc_ns
+
+-#endif /* !__ASSEMBLY__ */
++#endif /* !__ASSEMBLER__ */
+
+ #endif /* __ASM_VDSO_GETTIMEOFDAY_H */
+diff --git a/arch/x86/include/asm/vdso/processor.h b/arch/x86/include/asm/vdso/processor.h
+index 2cbce97d29eaf..c9b2ba7a9ec4c 100644
+--- a/arch/x86/include/asm/vdso/processor.h
++++ b/arch/x86/include/asm/vdso/processor.h
+@@ -5,7 +5,7 @@
+ #ifndef __ASM_VDSO_PROCESSOR_H
+ #define __ASM_VDSO_PROCESSOR_H
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ /* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
+ static __always_inline void rep_nop(void)
+@@ -22,6 +22,6 @@ struct getcpu_cache;
+
+ notrace long __vdso_getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *unused);
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ #endif /* __ASM_VDSO_PROCESSOR_H */
+diff --git a/arch/x86/include/asm/vdso/vsyscall.h b/arch/x86/include/asm/vdso/vsyscall.h
+index 88b31d4cdfaf3..6622e0103444e 100644
+--- a/arch/x86/include/asm/vdso/vsyscall.h
++++ b/arch/x86/include/asm/vdso/vsyscall.h
+@@ -10,7 +10,7 @@
+ #define VDSO_PAGE_PVCLOCK_OFFSET 0
+ #define VDSO_PAGE_HVCLOCK_OFFSET 1
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ #include <vdso/datapage.h>
+ #include <asm/vgtod.h>
+@@ -37,6 +37,6 @@ struct vdso_rng_data *__x86_get_k_vdso_rng_data(void)
+ /* The asm-generic header needs to be included after the definitions above */
+ #include <asm-generic/vdso/vsyscall.h>
+
+-#endif /* !__ASSEMBLY__ */
++#endif /* !__ASSEMBLER__ */
+
+ #endif /* __ASM_VDSO_VSYSCALL_H */
+diff --git a/arch/x86/include/asm/xen/interface.h b/arch/x86/include/asm/xen/interface.h
+index baca0b00ef768..a078a2b0f032b 100644
+--- a/arch/x86/include/asm/xen/interface.h
++++ b/arch/x86/include/asm/xen/interface.h
+@@ -72,7 +72,7 @@
+ #endif
+ #endif
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ /* Explicitly size integers that represent pfns in the public interface
+ * with Xen so that on ARM we can have one ABI that works for 32 and 64
+ * bit guests. */
+@@ -137,7 +137,7 @@ DEFINE_GUEST_HANDLE(xen_ulong_t);
+ #define TI_SET_DPL(_ti, _dpl) ((_ti)->flags |= (_dpl))
+ #define TI_SET_IF(_ti, _if) ((_ti)->flags |= ((!!(_if))<<2))
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ struct trap_info {
+ uint8_t vector; /* exception vector */
+ uint8_t flags; /* 0-3: privilege level; 4: clear event enable? */
+@@ -186,7 +186,7 @@ struct arch_shared_info {
+ uint32_t wc_sec_hi;
+ #endif
+ };
+-#endif /* !__ASSEMBLY__ */
++#endif /* !__ASSEMBLER__ */
+
+ #ifdef CONFIG_X86_32
+ #include <asm/xen/interface_32.h>
+@@ -196,7 +196,7 @@ struct arch_shared_info {
+
+ #include <asm/pvclock-abi.h>
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ /*
+ * The following is all CPU context. Note that the fpu_ctxt block is filled
+ * in by FXSAVE if the CPU has feature FXSR; otherwise FSAVE is used.
+@@ -376,7 +376,7 @@ struct xen_pmu_arch {
+ } c;
+ };
+
+-#endif /* !__ASSEMBLY__ */
++#endif /* !__ASSEMBLER__ */
+
+ /*
+ * Prefix forces emulation of some non-trapping instructions.
+diff --git a/arch/x86/include/asm/xen/interface_32.h b/arch/x86/include/asm/xen/interface_32.h
+index dc40578abded7..74d9768a9cf77 100644
+--- a/arch/x86/include/asm/xen/interface_32.h
++++ b/arch/x86/include/asm/xen/interface_32.h
+@@ -44,7 +44,7 @@
+ */
+ #define __HYPERVISOR_VIRT_START 0xF5800000
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ struct cpu_user_regs {
+ uint32_t ebx;
+@@ -85,7 +85,7 @@ typedef struct xen_callback xen_callback_t;
+
+ #define XEN_CALLBACK(__cs, __eip) \
+ ((struct xen_callback){ .cs = (__cs), .eip = (unsigned long)(__eip) })
+-#endif /* !__ASSEMBLY__ */
++#endif /* !__ASSEMBLER__ */
+
+
+ /*
+diff --git a/arch/x86/include/asm/xen/interface_64.h b/arch/x86/include/asm/xen/interface_64.h
+index c10f279aae936..38a19edb81a31 100644
+--- a/arch/x86/include/asm/xen/interface_64.h
++++ b/arch/x86/include/asm/xen/interface_64.h
+@@ -77,7 +77,7 @@
+ #define VGCF_in_syscall (1<<_VGCF_in_syscall)
+ #define VGCF_IN_SYSCALL VGCF_in_syscall
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ struct iret_context {
+ /* Top of stack (%rsp at point of hypercall). */
+@@ -143,7 +143,7 @@ typedef unsigned long xen_callback_t;
+ #define XEN_CALLBACK(__cs, __rip) \
+ ((unsigned long)(__rip))
+
+-#endif /* !__ASSEMBLY__ */
++#endif /* !__ASSEMBLER__ */
+
+
+ #endif /* _ASM_X86_XEN_INTERFACE_64_H */
+diff --git a/arch/x86/math-emu/control_w.h b/arch/x86/math-emu/control_w.h
+index 60f4dcc5edc3c..93cbc89b34e25 100644
+--- a/arch/x86/math-emu/control_w.h
++++ b/arch/x86/math-emu/control_w.h
+@@ -11,7 +11,7 @@
+ #ifndef _CONTROLW_H_
+ #define _CONTROLW_H_
+
+-#ifdef __ASSEMBLY__
++#ifdef __ASSEMBLER__
+ #define _Const_(x) $##x
+ #else
+ #define _Const_(x) x
+diff --git a/arch/x86/math-emu/exception.h b/arch/x86/math-emu/exception.h
+index 75230b9775777..59961d350bc4d 100644
+--- a/arch/x86/math-emu/exception.h
++++ b/arch/x86/math-emu/exception.h
+@@ -10,7 +10,7 @@
+ #ifndef _EXCEPTION_H_
+ #define _EXCEPTION_H_
+
+-#ifdef __ASSEMBLY__
++#ifdef __ASSEMBLER__
+ #define Const_(x) $##x
+ #else
+ #define Const_(x) x
+@@ -37,7 +37,7 @@
+ #define PRECISION_LOST_UP Const_((EX_Precision | SW_C1))
+ #define PRECISION_LOST_DOWN Const_(EX_Precision)
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ #ifdef DEBUG
+ #define EXCEPTION(x) { printk("exception in %s at line %d\n", \
+@@ -46,6 +46,6 @@
+ #define EXCEPTION(x) FPU_exception(x)
+ #endif
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ #endif /* _EXCEPTION_H_ */
+diff --git a/arch/x86/math-emu/fpu_emu.h b/arch/x86/math-emu/fpu_emu.h
+index 0c122226ca56f..def569c50b760 100644
+--- a/arch/x86/math-emu/fpu_emu.h
++++ b/arch/x86/math-emu/fpu_emu.h
+@@ -20,7 +20,7 @@
+ */
+ #define PECULIAR_486
+
+-#ifdef __ASSEMBLY__
++#ifdef __ASSEMBLER__
+ #include "fpu_asm.h"
+ #define Const(x) $##x
+ #else
+@@ -68,7 +68,7 @@
+
+ #define FPU_Exception Const(0x80000000) /* Added to tag returns. */
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ #include "fpu_system.h"
+
+@@ -213,6 +213,6 @@ asmlinkage int FPU_round(FPU_REG *arg, unsigned int extent, int dummy,
+ #include "fpu_proto.h"
+ #endif
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ #endif /* _FPU_EMU_H_ */
+diff --git a/arch/x86/math-emu/status_w.h b/arch/x86/math-emu/status_w.h
+index b77bafec95260..f642957330efc 100644
+--- a/arch/x86/math-emu/status_w.h
++++ b/arch/x86/math-emu/status_w.h
+@@ -13,7 +13,7 @@
+
+ #include "fpu_emu.h" /* for definition of PECULIAR_486 */
+
+-#ifdef __ASSEMBLY__
++#ifdef __ASSEMBLER__
+ #define Const__(x) $##x
+ #else
+ #define Const__(x) x
+@@ -37,7 +37,7 @@
+
+ #define SW_Exc_Mask Const__(0x27f) /* Status word exception bit mask */
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ #define COMP_A_gt_B 1
+ #define COMP_A_eq_B 2
+@@ -63,6 +63,6 @@ static inline void setcc(int cc)
+ # define clear_C1()
+ #endif /* PECULIAR_486 */
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ #endif /* _STATUS_H_ */
+diff --git a/arch/x86/realmode/rm/realmode.h b/arch/x86/realmode/rm/realmode.h
+index c76041a353970..867e55f1d6af4 100644
+--- a/arch/x86/realmode/rm/realmode.h
++++ b/arch/x86/realmode/rm/realmode.h
+@@ -2,7 +2,7 @@
+ #ifndef ARCH_X86_REALMODE_RM_REALMODE_H
+ #define ARCH_X86_REALMODE_RM_REALMODE_H
+
+-#ifdef __ASSEMBLY__
++#ifdef __ASSEMBLER__
+
+ /*
+ * 16-bit ljmpw to the real_mode_seg
+@@ -12,7 +12,7 @@
+ */
+ #define LJMPW_RM(to) .byte 0xea ; .word (to), real_mode_seg
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ /*
+ * Signature at the end of the realmode region
+diff --git a/arch/x86/realmode/rm/wakeup.h b/arch/x86/realmode/rm/wakeup.h
+index 0e4fd08ae4471..3b6d8fa82d3e1 100644
+--- a/arch/x86/realmode/rm/wakeup.h
++++ b/arch/x86/realmode/rm/wakeup.h
+@@ -7,7 +7,7 @@
+ #ifndef ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H
+ #define ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ #include <linux/types.h>
+
+ /* This must match data at wakeup.S */
+diff --git a/tools/arch/x86/include/asm/asm.h b/tools/arch/x86/include/asm/asm.h
+index 3ad3da9a7d974..dbe39b44256ba 100644
+--- a/tools/arch/x86/include/asm/asm.h
++++ b/tools/arch/x86/include/asm/asm.h
+@@ -2,7 +2,7 @@
+ #ifndef _ASM_X86_ASM_H
+ #define _ASM_X86_ASM_H
+
+-#ifdef __ASSEMBLY__
++#ifdef __ASSEMBLER__
+ # define __ASM_FORM(x, ...) x,## __VA_ARGS__
+ # define __ASM_FORM_RAW(x, ...) x,## __VA_ARGS__
+ # define __ASM_FORM_COMMA(x, ...) x,## __VA_ARGS__,
+@@ -123,7 +123,7 @@
+ #ifdef __KERNEL__
+
+ /* Exception table entry */
+-#ifdef __ASSEMBLY__
++#ifdef __ASSEMBLER__
+ # define _ASM_EXTABLE_HANDLE(from, to, handler) \
+ .pushsection "__ex_table","a" ; \
+ .balign 4 ; \
+@@ -154,7 +154,7 @@
+ # define _ASM_NOKPROBE(entry)
+ # endif
+
+-#else /* ! __ASSEMBLY__ */
++#else /* ! __ASSEMBLER__ */
+ # define _EXPAND_EXTABLE_HANDLE(x) #x
+ # define _ASM_EXTABLE_HANDLE(from, to, handler) \
+ " .pushsection \"__ex_table\",\"a\"\n" \
+@@ -186,7 +186,7 @@
+ */
+ register unsigned long current_stack_pointer asm(_ASM_SP);
+ #define ASM_CALL_CONSTRAINT "+r" (current_stack_pointer)
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ #endif /* __KERNEL__ */
+
+diff --git a/tools/arch/x86/include/asm/nops.h b/tools/arch/x86/include/asm/nops.h
+index 1c1b7550fa550..cd94221d83358 100644
+--- a/tools/arch/x86/include/asm/nops.h
++++ b/tools/arch/x86/include/asm/nops.h
+@@ -82,7 +82,7 @@
+ #define ASM_NOP7 _ASM_BYTES(BYTES_NOP7)
+ #define ASM_NOP8 _ASM_BYTES(BYTES_NOP8)
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ extern const unsigned char * const x86_nops[];
+ #endif
+
+diff --git a/tools/arch/x86/include/asm/orc_types.h b/tools/arch/x86/include/asm/orc_types.h
+index 46d7e06763c9f..e0125afa53fb9 100644
+--- a/tools/arch/x86/include/asm/orc_types.h
++++ b/tools/arch/x86/include/asm/orc_types.h
+@@ -45,7 +45,7 @@
+ #define ORC_TYPE_REGS 3
+ #define ORC_TYPE_REGS_PARTIAL 4
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ #include <asm/byteorder.h>
+
+ /*
+@@ -73,6 +73,6 @@ struct orc_entry {
+ #endif
+ } __packed;
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ #endif /* _ORC_TYPES_H */
+diff --git a/tools/arch/x86/include/asm/pvclock-abi.h b/tools/arch/x86/include/asm/pvclock-abi.h
+index 1436226efe3ef..b9fece5fc96d6 100644
+--- a/tools/arch/x86/include/asm/pvclock-abi.h
++++ b/tools/arch/x86/include/asm/pvclock-abi.h
+@@ -1,7 +1,7 @@
+ /* SPDX-License-Identifier: GPL-2.0 */
+ #ifndef _ASM_X86_PVCLOCK_ABI_H
+ #define _ASM_X86_PVCLOCK_ABI_H
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ /*
+ * These structs MUST NOT be changed.
+@@ -44,5 +44,5 @@ struct pvclock_wall_clock {
+ #define PVCLOCK_GUEST_STOPPED (1 << 1)
+ /* PVCLOCK_COUNTS_FROM_ZERO broke ABI and can't be used anymore. */
+ #define PVCLOCK_COUNTS_FROM_ZERO (1 << 2)
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+ #endif /* _ASM_X86_PVCLOCK_ABI_H */
+--
+2.39.5
+
--- /dev/null
+From 7e4799f00592455780de17b2e53c082ff8bb40ac Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 10 Mar 2025 11:42:56 +0100
+Subject: x86/headers: Replace __ASSEMBLY__ with __ASSEMBLER__ in UAPI headers
+
+From: Thomas Huth <thuth@redhat.com>
+
+[ Upstream commit 8a141be3233af7d4f7014ebc44d5452d46b2b1be ]
+
+__ASSEMBLY__ is only defined by the Makefile of the kernel, so
+this is not really useful for UAPI headers (unless the userspace
+Makefile defines it, too). Let's switch to __ASSEMBLER__ which
+gets set automatically by the compiler when compiling assembly
+code.
+
+Signed-off-by: Thomas Huth <thuth@redhat.com>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Cc: "H. Peter Anvin" <hpa@zytor.com>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Kees Cook <keescook@chromium.org>
+Cc: Brian Gerst <brgerst@gmail.com>
+Link: https://lore.kernel.org/r/20250310104256.123527-1-thuth@redhat.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/include/uapi/asm/bootparam.h | 4 ++--
+ arch/x86/include/uapi/asm/e820.h | 4 ++--
+ arch/x86/include/uapi/asm/ldt.h | 4 ++--
+ arch/x86/include/uapi/asm/msr.h | 4 ++--
+ arch/x86/include/uapi/asm/ptrace-abi.h | 6 +++---
+ arch/x86/include/uapi/asm/ptrace.h | 4 ++--
+ arch/x86/include/uapi/asm/setup_data.h | 4 ++--
+ arch/x86/include/uapi/asm/signal.h | 8 ++++----
+ 8 files changed, 19 insertions(+), 19 deletions(-)
+
+diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
+index 9b82eebd7add5..dafbf581c515d 100644
+--- a/arch/x86/include/uapi/asm/bootparam.h
++++ b/arch/x86/include/uapi/asm/bootparam.h
+@@ -26,7 +26,7 @@
+ #define XLF_5LEVEL_ENABLED (1<<6)
+ #define XLF_MEM_ENCRYPTION (1<<7)
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ #include <linux/types.h>
+ #include <linux/screen_info.h>
+@@ -210,6 +210,6 @@ enum x86_hardware_subarch {
+ X86_NR_SUBARCHS,
+ };
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ #endif /* _ASM_X86_BOOTPARAM_H */
+diff --git a/arch/x86/include/uapi/asm/e820.h b/arch/x86/include/uapi/asm/e820.h
+index 2f491efe3a126..55bc668671560 100644
+--- a/arch/x86/include/uapi/asm/e820.h
++++ b/arch/x86/include/uapi/asm/e820.h
+@@ -54,7 +54,7 @@
+ */
+ #define E820_RESERVED_KERN 128
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ #include <linux/types.h>
+ struct e820entry {
+ __u64 addr; /* start of memory segment */
+@@ -76,7 +76,7 @@ struct e820map {
+ #define BIOS_ROM_BASE 0xffe00000
+ #define BIOS_ROM_END 0xffffffff
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+
+ #endif /* _UAPI_ASM_X86_E820_H */
+diff --git a/arch/x86/include/uapi/asm/ldt.h b/arch/x86/include/uapi/asm/ldt.h
+index d62ac5db093b4..a82c039d8e6a7 100644
+--- a/arch/x86/include/uapi/asm/ldt.h
++++ b/arch/x86/include/uapi/asm/ldt.h
+@@ -12,7 +12,7 @@
+ /* The size of each LDT entry. */
+ #define LDT_ENTRY_SIZE 8
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ /*
+ * Note on 64bit base and limit is ignored and you cannot set DS/ES/CS
+ * not to the default values if you still want to do syscalls. This
+@@ -44,5 +44,5 @@ struct user_desc {
+ #define MODIFY_LDT_CONTENTS_STACK 1
+ #define MODIFY_LDT_CONTENTS_CODE 2
+
+-#endif /* !__ASSEMBLY__ */
++#endif /* !__ASSEMBLER__ */
+ #endif /* _ASM_X86_LDT_H */
+diff --git a/arch/x86/include/uapi/asm/msr.h b/arch/x86/include/uapi/asm/msr.h
+index e7516b402a00f..4b8917ca28fe7 100644
+--- a/arch/x86/include/uapi/asm/msr.h
++++ b/arch/x86/include/uapi/asm/msr.h
+@@ -2,7 +2,7 @@
+ #ifndef _UAPI_ASM_X86_MSR_H
+ #define _UAPI_ASM_X86_MSR_H
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ #include <linux/types.h>
+ #include <linux/ioctl.h>
+@@ -10,5 +10,5 @@
+ #define X86_IOC_RDMSR_REGS _IOWR('c', 0xA0, __u32[8])
+ #define X86_IOC_WRMSR_REGS _IOWR('c', 0xA1, __u32[8])
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+ #endif /* _UAPI_ASM_X86_MSR_H */
+diff --git a/arch/x86/include/uapi/asm/ptrace-abi.h b/arch/x86/include/uapi/asm/ptrace-abi.h
+index 16074b9c93bb5..5823584dea132 100644
+--- a/arch/x86/include/uapi/asm/ptrace-abi.h
++++ b/arch/x86/include/uapi/asm/ptrace-abi.h
+@@ -25,7 +25,7 @@
+
+ #else /* __i386__ */
+
+-#if defined(__ASSEMBLY__) || defined(__FRAME_OFFSETS)
++#if defined(__ASSEMBLER__) || defined(__FRAME_OFFSETS)
+ /*
+ * C ABI says these regs are callee-preserved. They aren't saved on kernel entry
+ * unless syscall needs a complete, fully filled "struct pt_regs".
+@@ -57,7 +57,7 @@
+ #define EFLAGS 144
+ #define RSP 152
+ #define SS 160
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ /* top of stack page */
+ #define FRAME_SIZE 168
+@@ -87,7 +87,7 @@
+
+ #define PTRACE_SINGLEBLOCK 33 /* resume execution until next branch */
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ #include <linux/types.h>
+ #endif
+
+diff --git a/arch/x86/include/uapi/asm/ptrace.h b/arch/x86/include/uapi/asm/ptrace.h
+index 85165c0edafc8..e0b5b4f6226b1 100644
+--- a/arch/x86/include/uapi/asm/ptrace.h
++++ b/arch/x86/include/uapi/asm/ptrace.h
+@@ -7,7 +7,7 @@
+ #include <asm/processor-flags.h>
+
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ #ifdef __i386__
+ /* this struct defines the way the registers are stored on the
+@@ -81,6 +81,6 @@ struct pt_regs {
+
+
+
+-#endif /* !__ASSEMBLY__ */
++#endif /* !__ASSEMBLER__ */
+
+ #endif /* _UAPI_ASM_X86_PTRACE_H */
+diff --git a/arch/x86/include/uapi/asm/setup_data.h b/arch/x86/include/uapi/asm/setup_data.h
+index b111b0c185449..50c45ead4e7c9 100644
+--- a/arch/x86/include/uapi/asm/setup_data.h
++++ b/arch/x86/include/uapi/asm/setup_data.h
+@@ -18,7 +18,7 @@
+ #define SETUP_INDIRECT (1<<31)
+ #define SETUP_TYPE_MAX (SETUP_ENUM_MAX | SETUP_INDIRECT)
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+ #include <linux/types.h>
+
+@@ -78,6 +78,6 @@ struct ima_setup_data {
+ __u64 size;
+ } __attribute__((packed));
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ #endif /* _UAPI_ASM_X86_SETUP_DATA_H */
+diff --git a/arch/x86/include/uapi/asm/signal.h b/arch/x86/include/uapi/asm/signal.h
+index f777346450ec3..1067efabf18b5 100644
+--- a/arch/x86/include/uapi/asm/signal.h
++++ b/arch/x86/include/uapi/asm/signal.h
+@@ -2,7 +2,7 @@
+ #ifndef _UAPI_ASM_X86_SIGNAL_H
+ #define _UAPI_ASM_X86_SIGNAL_H
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+ #include <linux/types.h>
+ #include <linux/compiler.h>
+
+@@ -16,7 +16,7 @@ struct siginfo;
+ typedef unsigned long sigset_t;
+
+ #endif /* __KERNEL__ */
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+
+ #define SIGHUP 1
+@@ -68,7 +68,7 @@ typedef unsigned long sigset_t;
+
+ #include <asm-generic/signal-defs.h>
+
+-#ifndef __ASSEMBLY__
++#ifndef __ASSEMBLER__
+
+
+ # ifndef __KERNEL__
+@@ -106,6 +106,6 @@ typedef struct sigaltstack {
+ __kernel_size_t ss_size;
+ } stack_t;
+
+-#endif /* __ASSEMBLY__ */
++#endif /* __ASSEMBLER__ */
+
+ #endif /* _UAPI_ASM_X86_SIGNAL_H */
+--
+2.39.5
+
--- /dev/null
+From 63388f7dbfa5dc2ae6ba7312d68eb0b58e020e9e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 13 Feb 2025 12:45:47 +0100
+Subject: x86/ibt: Handle FineIBT in handle_cfi_failure()
+
+From: Peter Zijlstra <peterz@infradead.org>
+
+[ Upstream commit 882b86fd4e0d49bf91148dbadcdbece19ded40e6 ]
+
+Sami reminded me that FineIBT failure does not hook into the regular
+CFI failure case, and as such CFI_PERMISSIVE does not work.
+
+Reported-by: Sami Tolvanen <samitolvanen@google.com>
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Reviewed-by: Sami Tolvanen <samitolvanen@google.com>
+Link: https://lkml.kernel.org/r/20250214092619.GB21726@noisy.programming.kicks-ass.net
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/include/asm/cfi.h | 11 +++++++++++
+ arch/x86/kernel/alternative.c | 30 ++++++++++++++++++++++++++++++
+ arch/x86/kernel/cfi.c | 22 ++++++++++++++++++----
+ 3 files changed, 59 insertions(+), 4 deletions(-)
+
+diff --git a/arch/x86/include/asm/cfi.h b/arch/x86/include/asm/cfi.h
+index 31d19c815f992..7dd5ab239c87b 100644
+--- a/arch/x86/include/asm/cfi.h
++++ b/arch/x86/include/asm/cfi.h
+@@ -126,6 +126,17 @@ static inline int cfi_get_offset(void)
+
+ extern u32 cfi_get_func_hash(void *func);
+
++#ifdef CONFIG_FINEIBT
++extern bool decode_fineibt_insn(struct pt_regs *regs, unsigned long *target, u32 *type);
++#else
++static inline bool
++decode_fineibt_insn(struct pt_regs *regs, unsigned long *target, u32 *type)
++{
++ return false;
++}
++
++#endif
++
+ #else
+ static inline enum bug_trap_type handle_cfi_failure(struct pt_regs *regs)
+ {
+diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
+index f843fd37cf987..e1913bcb806e2 100644
+--- a/arch/x86/kernel/alternative.c
++++ b/arch/x86/kernel/alternative.c
+@@ -1271,6 +1271,7 @@ asm( ".pushsection .rodata \n"
+ " endbr64 \n"
+ " subl $0x12345678, %r10d \n"
+ " je fineibt_preamble_end \n"
++ "fineibt_preamble_ud2: \n"
+ " ud2 \n"
+ " nop \n"
+ "fineibt_preamble_end: \n"
+@@ -1278,9 +1279,11 @@ asm( ".pushsection .rodata \n"
+ );
+
+ extern u8 fineibt_preamble_start[];
++extern u8 fineibt_preamble_ud2[];
+ extern u8 fineibt_preamble_end[];
+
+ #define fineibt_preamble_size (fineibt_preamble_end - fineibt_preamble_start)
++#define fineibt_preamble_ud2 (fineibt_preamble_ud2 - fineibt_preamble_start)
+ #define fineibt_preamble_hash 7
+
+ asm( ".pushsection .rodata \n"
+@@ -1598,6 +1601,33 @@ static void poison_cfi(void *addr, void *wr_addr)
+ }
+ }
+
++/*
++ * regs->ip points to a UD2 instruction, return true and fill out target and
++ * type when this UD2 is from a FineIBT preamble.
++ *
++ * We check the preamble by checking for the ENDBR instruction relative to the
++ * UD2 instruction.
++ */
++bool decode_fineibt_insn(struct pt_regs *regs, unsigned long *target, u32 *type)
++{
++ unsigned long addr = regs->ip - fineibt_preamble_ud2;
++ u32 endbr, hash;
++
++ __get_kernel_nofault(&endbr, addr, u32, Efault);
++ if (endbr != gen_endbr())
++ return false;
++
++ *target = addr + fineibt_preamble_size;
++
++ __get_kernel_nofault(&hash, addr + fineibt_preamble_hash, u32, Efault);
++ *type = (u32)regs->r10 + hash;
++
++ return true;
++
++Efault:
++ return false;
++}
++
+ #else
+
+ static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
+diff --git a/arch/x86/kernel/cfi.c b/arch/x86/kernel/cfi.c
+index e6bf78fac1462..f6905bef0af84 100644
+--- a/arch/x86/kernel/cfi.c
++++ b/arch/x86/kernel/cfi.c
+@@ -70,11 +70,25 @@ enum bug_trap_type handle_cfi_failure(struct pt_regs *regs)
+ unsigned long target;
+ u32 type;
+
+- if (!is_cfi_trap(regs->ip))
+- return BUG_TRAP_TYPE_NONE;
++ switch (cfi_mode) {
++ case CFI_KCFI:
++ if (!is_cfi_trap(regs->ip))
++ return BUG_TRAP_TYPE_NONE;
++
++ if (!decode_cfi_insn(regs, &target, &type))
++ return report_cfi_failure_noaddr(regs, regs->ip);
++
++ break;
+
+- if (!decode_cfi_insn(regs, &target, &type))
+- return report_cfi_failure_noaddr(regs, regs->ip);
++ case CFI_FINEIBT:
++ if (!decode_fineibt_insn(regs, &target, &type))
++ return BUG_TRAP_TYPE_NONE;
++
++ break;
++
++ default:
++ return BUG_TRAP_TYPE_NONE;
++ }
+
+ return report_cfi_failure(regs, regs->ip, &target, type);
+ }
+--
+2.39.5
+
--- /dev/null
+From ace30a5c8ff752b9ebe8c9066207c638f7a14f0f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 7 Feb 2025 10:42:34 +1100
+Subject: x86/kaslr: Reduce KASLR entropy on most x86 systems
+
+From: Balbir Singh <balbirs@nvidia.com>
+
+[ Upstream commit 7ffb791423c7c518269a9aad35039ef824a40adb ]
+
+When CONFIG_PCI_P2PDMA=y (which is basically enabled on all
+large x86 distros), it maps the PFN's via a ZONE_DEVICE
+mapping using devm_memremap_pages(). The mapped virtual
+address range corresponds to the pci_resource_start()
+of the BAR address and size corresponding to the BAR length.
+
+When KASLR is enabled, the direct map range of the kernel is
+reduced to the size of physical memory plus additional padding.
+If the BAR address is beyond this limit, PCI peer to peer DMA
+mappings fail.
+
+Fix this by not shrinking the size of the direct map when
+CONFIG_PCI_P2PDMA=y.
+
+This reduces the total available entropy, but it's better than
+the current work around of having to disable KASLR completely.
+
+[ mingo: Clarified the changelog to point out the broad impact ... ]
+
+Signed-off-by: Balbir Singh <balbirs@nvidia.com>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Reviewed-by: Kees Cook <kees@kernel.org>
+Acked-by: Bjorn Helgaas <bhelgaas@google.com> # drivers/pci/Kconfig
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Andy Lutomirski <luto@kernel.org>
+Link: https://lore.kernel.org/lkml/20250206023201.1481957-1-balbirs@nvidia.com/
+Link: https://lore.kernel.org/r/20250206234234.1912585-1-balbirs@nvidia.com
+--
+ arch/x86/mm/kaslr.c | 10 ++++++++--
+ drivers/pci/Kconfig | 6 ++++++
+ 2 files changed, 14 insertions(+), 2 deletions(-)
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/mm/kaslr.c | 10 ++++++++--
+ drivers/pci/Kconfig | 6 ++++++
+ 2 files changed, 14 insertions(+), 2 deletions(-)
+
+diff --git a/arch/x86/mm/kaslr.c b/arch/x86/mm/kaslr.c
+index 11a93542d1983..3c306de52fd4d 100644
+--- a/arch/x86/mm/kaslr.c
++++ b/arch/x86/mm/kaslr.c
+@@ -113,8 +113,14 @@ void __init kernel_randomize_memory(void)
+ memory_tb = DIV_ROUND_UP(max_pfn << PAGE_SHIFT, 1UL << TB_SHIFT) +
+ CONFIG_RANDOMIZE_MEMORY_PHYSICAL_PADDING;
+
+- /* Adapt physical memory region size based on available memory */
+- if (memory_tb < kaslr_regions[0].size_tb)
++ /*
++ * Adapt physical memory region size based on available memory,
++ * except when CONFIG_PCI_P2PDMA is enabled. P2PDMA exposes the
++ * device BAR space assuming the direct map space is large enough
++ * for creating a ZONE_DEVICE mapping in the direct map corresponding
++ * to the physical BAR address.
++ */
++ if (!IS_ENABLED(CONFIG_PCI_P2PDMA) && (memory_tb < kaslr_regions[0].size_tb))
+ kaslr_regions[0].size_tb = memory_tb;
+
+ /*
+diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
+index 2fbd379923fd1..5c3054aaec8c1 100644
+--- a/drivers/pci/Kconfig
++++ b/drivers/pci/Kconfig
+@@ -203,6 +203,12 @@ config PCI_P2PDMA
+ P2P DMA transactions must be between devices behind the same root
+ port.
+
++ Enabling this option will reduce the entropy of x86 KASLR memory
++ regions. For example - on a 46 bit system, the entropy goes down
++ from 16 bits to 15 bits. The actual reduction in entropy depends
++ on the physical address bits, on processor features, kernel config
++ (5 level page table) and physical memory present on the system.
++
+ If unsure, say N.
+
+ config PCI_LABEL
+--
+2.39.5
+
--- /dev/null
+From 7a8614dc5f7fb0795b75ae9d77c870d28dc6c506 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 10 Apr 2025 11:54:20 +0000
+Subject: x86/Kconfig: make CFI_AUTO_DEFAULT depend on !RUST or Rust >= 1.88
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Paweł Anikiel <panikiel@google.com>
+
+[ Upstream commit 5595c31c370957aabe739ac3996aedba8267603f ]
+
+Calling core::fmt::write() from rust code while FineIBT is enabled
+results in a kernel panic:
+
+[ 4614.199779] kernel BUG at arch/x86/kernel/cet.c:132!
+[ 4614.205343] Oops: invalid opcode: 0000 [#1] PREEMPT SMP NOPTI
+[ 4614.211781] CPU: 2 UID: 0 PID: 6057 Comm: dmabuf_dump Tainted: G U O 6.12.17-android16-0-g6ab38c534a43 #1 9da040f27673ec3945e23b998a0f8bd64c846599
+[ 4614.227832] Tainted: [U]=USER, [O]=OOT_MODULE
+[ 4614.241247] RIP: 0010:do_kernel_cp_fault+0xea/0xf0
+...
+[ 4614.398144] RIP: 0010:_RNvXs5_NtNtNtCs3o2tGsuHyou_4core3fmt3num3impyNtB9_7Display3fmt+0x0/0x20
+[ 4614.407792] Code: 48 f7 df 48 0f 48 f9 48 89 f2 89 c6 5d e9 18 fd ff ff 0f 1f 84 00 00 00 00 00 f3 0f 1e fa 41 81 ea 14 61 af 2c 74 03 0f 0b 90 <66> 0f 1f 00 55 48 89 e5 48 89 f2 48 8b 3f be 01 00 00 00 5d e9 e7
+[ 4614.428775] RSP: 0018:ffffb95acfa4ba68 EFLAGS: 00010246
+[ 4614.434609] RAX: 0000000000000000 RBX: 0000000000000010 RCX: 0000000000000000
+[ 4614.442587] RDX: 0000000000000007 RSI: ffffb95acfa4ba70 RDI: ffffb95acfa4bc88
+[ 4614.450557] RBP: ffffb95acfa4bae0 R08: ffff0a00ffffff05 R09: 0000000000000070
+[ 4614.458527] R10: 0000000000000000 R11: ffffffffab67eaf0 R12: ffffb95acfa4bcc8
+[ 4614.466493] R13: ffffffffac5d50f0 R14: 0000000000000000 R15: 0000000000000000
+[ 4614.474473] ? __cfi__RNvXs5_NtNtNtCs3o2tGsuHyou_4core3fmt3num3impyNtB9_7Display3fmt+0x10/0x10
+[ 4614.484118] ? _RNvNtCs3o2tGsuHyou_4core3fmt5write+0x1d2/0x250
+
+This happens because core::fmt::write() calls
+core::fmt::rt::Argument::fmt(), which currently has CFI disabled:
+
+library/core/src/fmt/rt.rs:
+171 // FIXME: Transmuting formatter in new and indirectly branching to/calling
+172 // it here is an explicit CFI violation.
+173 #[allow(inline_no_sanitize)]
+174 #[no_sanitize(cfi, kcfi)]
+175 #[inline]
+176 pub(super) unsafe fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+
+This causes a Control Protection exception, because FineIBT has sealed
+off the original function's endbr64.
+
+This makes rust currently incompatible with FineIBT. Add a Kconfig
+dependency that prevents FineIBT from getting turned on by default
+if rust is enabled.
+
+[ Rust 1.88.0 (scheduled for 2025-06-26) should have this fixed [1],
+ and thus we relaxed the condition with Rust >= 1.88.
+
+ When `objtool` lands checking for this with e.g. [2], the plan is
+ to ideally run that in upstream Rust's CI to prevent regressions
+ early [3], since we do not control `core`'s source code.
+
+ Alice tested the Rust PR backported to an older compiler.
+
+ Peter would like that Rust provides a stable `core` which can be
+ pulled into the kernel: "Relying on that much out of tree code is
+ 'unfortunate'".
+
+ - Miguel ]
+
+Signed-off-by: Paweł Anikiel <panikiel@google.com>
+Reviewed-by: Alice Ryhl <aliceryhl@google.com>
+Acked-by: Peter Zijlstra <peterz@infradead.org>
+Link: https://github.com/rust-lang/rust/pull/139632 [1]
+Link: https://lore.kernel.org/rust-for-linux/20250410154556.GB9003@noisy.programming.kicks-ass.net/ [2]
+Link: https://github.com/rust-lang/rust/pull/139632#issuecomment-2801950873 [3]
+Link: https://lore.kernel.org/r/20250410115420.366349-1-panikiel@google.com
+Link: https://lore.kernel.org/r/att0-CANiq72kjDM0cKALVy4POEzhfdT4nO7tqz0Pm7xM+3=_0+L1t=A@mail.gmail.com
+[ Reduced splat. - Miguel ]
+Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/Kconfig | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
+index 473364353bd96..5439bff8850a9 100644
+--- a/arch/x86/Kconfig
++++ b/arch/x86/Kconfig
+@@ -2430,6 +2430,7 @@ config STRICT_SIGALTSTACK_SIZE
+ config CFI_AUTO_DEFAULT
+ bool "Attempt to use FineIBT by default at boot time"
+ depends on FINEIBT
++ depends on !RUST || RUSTC_VERSION >= 108800
+ default y
+ help
+ Attempt to use FineIBT by default at boot time. If enabled,
+--
+2.39.5
+
--- /dev/null
+From 1d6c55ace126ffc44b8aeae8297837b61b0f0f98 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 14 Feb 2025 16:07:46 +0100
+Subject: x86/locking: Use ALT_OUTPUT_SP() for
+ percpu_{,try_}cmpxchg{64,128}_op()
+
+From: Uros Bizjak <ubizjak@gmail.com>
+
+[ Upstream commit 4087e16b033140cf2ce509ec23503bddec818a16 ]
+
+percpu_{,try_}cmpxchg{64,128}() macros use CALL instruction inside
+asm statement in one of their alternatives. Use ALT_OUTPUT_SP()
+macro to add required dependence on %esp register.
+
+ALT_OUTPUT_SP() implements the above dependence by adding
+ASM_CALL_CONSTRAINT to its arguments. This constraint should be used
+for any inline asm which has a CALL instruction, otherwise the
+compiler may schedule the asm before the frame pointer gets set up
+by the containing function, causing objtool to print a "call without
+frame pointer save/setup" warning.
+
+Signed-off-by: Uros Bizjak <ubizjak@gmail.com>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Link: https://lore.kernel.org/r/20250214150929.5780-1-ubizjak@gmail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/include/asm/percpu.h | 28 ++++++++++++++--------------
+ 1 file changed, 14 insertions(+), 14 deletions(-)
+
+diff --git a/arch/x86/include/asm/percpu.h b/arch/x86/include/asm/percpu.h
+index afb9099fba9fc..9c47da5b0a2a2 100644
+--- a/arch/x86/include/asm/percpu.h
++++ b/arch/x86/include/asm/percpu.h
+@@ -350,9 +350,9 @@ do { \
+ \
+ asm qual (ALTERNATIVE("call this_cpu_cmpxchg8b_emu", \
+ "cmpxchg8b " __percpu_arg([var]), X86_FEATURE_CX8) \
+- : [var] "+m" (__my_cpu_var(_var)), \
+- "+a" (old__.low), \
+- "+d" (old__.high) \
++ : ALT_OUTPUT_SP([var] "+m" (__my_cpu_var(_var)), \
++ "+a" (old__.low), \
++ "+d" (old__.high)) \
+ : "b" (new__.low), \
+ "c" (new__.high), \
+ "S" (&(_var)) \
+@@ -381,10 +381,10 @@ do { \
+ asm qual (ALTERNATIVE("call this_cpu_cmpxchg8b_emu", \
+ "cmpxchg8b " __percpu_arg([var]), X86_FEATURE_CX8) \
+ CC_SET(z) \
+- : CC_OUT(z) (success), \
+- [var] "+m" (__my_cpu_var(_var)), \
+- "+a" (old__.low), \
+- "+d" (old__.high) \
++ : ALT_OUTPUT_SP(CC_OUT(z) (success), \
++ [var] "+m" (__my_cpu_var(_var)), \
++ "+a" (old__.low), \
++ "+d" (old__.high)) \
+ : "b" (new__.low), \
+ "c" (new__.high), \
+ "S" (&(_var)) \
+@@ -421,9 +421,9 @@ do { \
+ \
+ asm qual (ALTERNATIVE("call this_cpu_cmpxchg16b_emu", \
+ "cmpxchg16b " __percpu_arg([var]), X86_FEATURE_CX16) \
+- : [var] "+m" (__my_cpu_var(_var)), \
+- "+a" (old__.low), \
+- "+d" (old__.high) \
++ : ALT_OUTPUT_SP([var] "+m" (__my_cpu_var(_var)), \
++ "+a" (old__.low), \
++ "+d" (old__.high)) \
+ : "b" (new__.low), \
+ "c" (new__.high), \
+ "S" (&(_var)) \
+@@ -452,10 +452,10 @@ do { \
+ asm qual (ALTERNATIVE("call this_cpu_cmpxchg16b_emu", \
+ "cmpxchg16b " __percpu_arg([var]), X86_FEATURE_CX16) \
+ CC_SET(z) \
+- : CC_OUT(z) (success), \
+- [var] "+m" (__my_cpu_var(_var)), \
+- "+a" (old__.low), \
+- "+d" (old__.high) \
++ : ALT_OUTPUT_SP(CC_OUT(z) (success), \
++ [var] "+m" (__my_cpu_var(_var)), \
++ "+a" (old__.low), \
++ "+d" (old__.high)) \
+ : "b" (new__.low), \
+ "c" (new__.high), \
+ "S" (&(_var)) \
+--
+2.39.5
+
--- /dev/null
+From 2488d3a1c852dab405e0aaab2372b99ccf634d21 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 19 Feb 2025 18:41:21 +0000
+Subject: x86/microcode: Update the Intel processor flag scan check
+
+From: Sohil Mehta <sohil.mehta@intel.com>
+
+[ Upstream commit 7e6b0a2e4152f4046af95eeb46f8b4f9b2a7398d ]
+
+The Family model check to read the processor flag MSR is misleading and
+potentially incorrect. It doesn't consider Family while comparing the
+model number. The original check did have a Family number but it got
+lost/moved during refactoring.
+
+intel_collect_cpu_info() is called through multiple paths such as early
+initialization, CPU hotplug as well as IFS image load. Some of these
+flows would be error prone due to the ambiguous check.
+
+Correct the processor flag scan check to use a Family number and update
+it to a VFM based one to make it more readable.
+
+Signed-off-by: Sohil Mehta <sohil.mehta@intel.com>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Acked-by: Dave Hansen <dave.hansen@linux.intel.com>
+Link: https://lore.kernel.org/r/20250219184133.816753-4-sohil.mehta@intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/include/asm/intel-family.h | 1 +
+ arch/x86/kernel/cpu/microcode/intel.c | 2 +-
+ 2 files changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/arch/x86/include/asm/intel-family.h b/arch/x86/include/asm/intel-family.h
+index ef5a06ddf0287..44fe88d6cf5c0 100644
+--- a/arch/x86/include/asm/intel-family.h
++++ b/arch/x86/include/asm/intel-family.h
+@@ -46,6 +46,7 @@
+ #define INTEL_ANY IFM(X86_FAMILY_ANY, X86_MODEL_ANY)
+
+ #define INTEL_PENTIUM_PRO IFM(6, 0x01)
++#define INTEL_PENTIUM_III_DESCHUTES IFM(6, 0x05)
+
+ #define INTEL_CORE_YONAH IFM(6, 0x0E)
+
+diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c
+index 9309468c8d2c1..2a397da43923b 100644
+--- a/arch/x86/kernel/cpu/microcode/intel.c
++++ b/arch/x86/kernel/cpu/microcode/intel.c
+@@ -74,7 +74,7 @@ void intel_collect_cpu_info(struct cpu_signature *sig)
+ sig->pf = 0;
+ sig->rev = intel_get_microcode_revision();
+
+- if (x86_model(sig->sig) >= 5 || x86_family(sig->sig) > 6) {
++ if (IFM(x86_family(sig->sig), x86_model(sig->sig)) >= INTEL_PENTIUM_III_DESCHUTES) {
+ unsigned int val[2];
+
+ /* get processor flags from MSR 0x17 */
+--
+2.39.5
+
--- /dev/null
+From d6bbb9e87c67c4c3ad1a10c95fdc38eeb79b770b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 15 Nov 2024 20:36:59 +0300
+Subject: x86/mm: Check return value from memblock_phys_alloc_range()
+
+From: Philip Redkin <me@rarity.fan>
+
+[ Upstream commit 631ca8909fd5c62b9fda9edda93924311a78a9c4 ]
+
+At least with CONFIG_PHYSICAL_START=0x100000, if there is < 4 MiB of
+contiguous free memory available at this point, the kernel will crash
+and burn because memblock_phys_alloc_range() returns 0 on failure,
+which leads memblock_phys_free() to throw the first 4 MiB of physical
+memory to the wolves.
+
+At a minimum it should fail gracefully with a meaningful diagnostic,
+but in fact everything seems to work fine without the weird reserve
+allocation.
+
+Signed-off-by: Philip Redkin <me@rarity.fan>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Cc: Dave Hansen <dave.hansen@linux.intel.com>
+Cc: Rik van Riel <riel@surriel.com>
+Cc: "H. Peter Anvin" <hpa@zytor.com>
+Link: https://lore.kernel.org/r/94b3e98f-96a7-3560-1f76-349eb95ccf7f@rarity.fan
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/mm/init.c | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
+index 62aa4d66a032d..bfa444a7dbb04 100644
+--- a/arch/x86/mm/init.c
++++ b/arch/x86/mm/init.c
+@@ -645,8 +645,13 @@ static void __init memory_map_top_down(unsigned long map_start,
+ */
+ addr = memblock_phys_alloc_range(PMD_SIZE, PMD_SIZE, map_start,
+ map_end);
+- memblock_phys_free(addr, PMD_SIZE);
+- real_end = addr + PMD_SIZE;
++ if (!addr) {
++ pr_warn("Failed to release memory for alloc_low_pages()");
++ real_end = max(map_start, ALIGN_DOWN(map_end, PMD_SIZE));
++ } else {
++ memblock_phys_free(addr, PMD_SIZE);
++ real_end = addr + PMD_SIZE;
++ }
+
+ /* step_size need to be small so pgt_buf from BRK could cover it */
+ step_size = PMD_SIZE;
+--
+2.39.5
+
--- /dev/null
+From d47c6fdcfa4fe3b4b55c9eb6a938bda8be128ff1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 1 Apr 2025 11:07:52 +1100
+Subject: x86/mm/init: Handle the special case of device private pages in
+ add_pages(), to not increase max_pfn and trigger dma_addressing_limited()
+ bounce buffers
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Balbir Singh <balbirs@nvidia.com>
+
+[ Upstream commit 7170130e4c72ce0caa0cb42a1627c635cc262821 ]
+
+As Bert Karwatzki reported, the following recent commit causes a
+performance regression on AMD iGPU and dGPU systems:
+
+ 7ffb791423c7 ("x86/kaslr: Reduce KASLR entropy on most x86 systems")
+
+It exposed a bug with nokaslr and zone device interaction.
+
+The root cause of the bug is that, the GPU driver registers a zone
+device private memory region. When KASLR is disabled or the above commit
+is applied, the direct_map_physmem_end is set to much higher than 10 TiB
+typically to the 64TiB address. When zone device private memory is added
+to the system via add_pages(), it bumps up the max_pfn to the same
+value. This causes dma_addressing_limited() to return true, since the
+device cannot address memory all the way up to max_pfn.
+
+This caused a regression for games played on the iGPU, as it resulted in
+the DMA32 zone being used for GPU allocations.
+
+Fix this by not bumping up max_pfn on x86 systems, when pgmap is passed
+into add_pages(). The presence of pgmap is used to determine if device
+private memory is being added via add_pages().
+
+More details:
+
+devm_request_mem_region() and request_free_mem_region() request for
+device private memory. iomem_resource is passed as the base resource
+with start and end parameters. iomem_resource's end depends on several
+factors, including the platform and virtualization. On x86 for example
+on bare metal, this value is set to boot_cpu_data.x86_phys_bits.
+boot_cpu_data.x86_phys_bits can change depending on support for MKTME.
+By default it is set to the same as log2(direct_map_physmem_end) which
+is 46 to 52 bits depending on the number of levels in the page table.
+The allocation routines used iomem_resource's end and
+direct_map_physmem_end to figure out where to allocate the region.
+
+[ arch/powerpc is also impacted by this problem, but this patch does not fix
+ the issue for PowerPC. ]
+
+Testing:
+
+ 1. Tested on a virtual machine with test_hmm for zone device inseration
+
+ 2. A previous version of this patch was tested by Bert, please see:
+ https://lore.kernel.org/lkml/d87680bab997fdc9fb4e638983132af235d9a03a.camel@web.de/
+
+[ mingo: Clarified the comments and the changelog. ]
+
+Reported-by: Bert Karwatzki <spasswolf@web.de>
+Tested-by: Bert Karwatzki <spasswolf@web.de>
+Fixes: 7ffb791423c7 ("x86/kaslr: Reduce KASLR entropy on most x86 systems")
+Signed-off-by: Balbir Singh <balbirs@nvidia.com>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Cc: Brian Gerst <brgerst@gmail.com>
+Cc: Juergen Gross <jgross@suse.com>
+Cc: H. Peter Anvin <hpa@zytor.com>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Andrew Morton <akpm@linux-foundation.org>
+Cc: Christoph Hellwig <hch@lst.de>
+Cc: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>
+Cc: Alex Deucher <alexander.deucher@amd.com>
+Cc: Christian König <christian.koenig@amd.com>
+Cc: David Airlie <airlied@gmail.com>
+Cc: Simona Vetter <simona@ffwll.ch>
+Link: https://lore.kernel.org/r/20250401000752.249348-1-balbirs@nvidia.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/mm/init_64.c | 15 ++++++++++++---
+ 1 file changed, 12 insertions(+), 3 deletions(-)
+
+diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
+index 01ea7c6df3036..17c89dad4f7ff 100644
+--- a/arch/x86/mm/init_64.c
++++ b/arch/x86/mm/init_64.c
+@@ -967,9 +967,18 @@ int add_pages(int nid, unsigned long start_pfn, unsigned long nr_pages,
+ ret = __add_pages(nid, start_pfn, nr_pages, params);
+ WARN_ON_ONCE(ret);
+
+- /* update max_pfn, max_low_pfn and high_memory */
+- update_end_of_memory_vars(start_pfn << PAGE_SHIFT,
+- nr_pages << PAGE_SHIFT);
++ /*
++ * Special case: add_pages() is called by memremap_pages() for adding device
++ * private pages. Do not bump up max_pfn in the device private path,
++ * because max_pfn changes affect dma_addressing_limited().
++ *
++ * dma_addressing_limited() returning true when max_pfn is the device's
++ * addressable memory can force device drivers to use bounce buffers
++ * and impact their performance negatively:
++ */
++ if (!params->pgmap)
++ /* update max_pfn, max_low_pfn and high_memory */
++ update_end_of_memory_vars(start_pfn << PAGE_SHIFT, nr_pages << PAGE_SHIFT);
+
+ return ret;
+ }
+--
+2.39.5
+
--- /dev/null
+From 8461e188cca93e70eb8f4eb1930ad736ada1461a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 13 Feb 2025 11:13:52 -0500
+Subject: x86/mm: Make MMU_GATHER_RCU_TABLE_FREE unconditional
+
+From: Rik van Riel <riel@surriel.com>
+
+[ Upstream commit a37259732a7dc33047fa1e4f9a338088f452e017 ]
+
+Currently x86 uses CONFIG_MMU_GATHER_TABLE_FREE when using
+paravirt, and not when running on bare metal.
+
+There is no real good reason to do things differently for
+each setup. Make them all the same.
+
+Currently get_user_pages_fast synchronizes against page table
+freeing in two different ways:
+
+ - on bare metal, by blocking IRQs, which block TLB flush IPIs
+ - on paravirt, with MMU_GATHER_RCU_TABLE_FREE
+
+This is done because some paravirt TLB flush implementations
+handle the TLB flush in the hypervisor, and will do the flush
+even when the target CPU has interrupts disabled.
+
+Always handle page table freeing with MMU_GATHER_RCU_TABLE_FREE.
+Using RCU synchronization between page table freeing and get_user_pages_fast()
+allows bare metal to also do TLB flushing while interrupts are disabled.
+
+Various places in the mm do still block IRQs or disable preemption
+as an implicit way to block RCU frees.
+
+That makes it safe to use INVLPGB on AMD CPUs.
+
+Suggested-by: Peter Zijlstra <peterz@infradead.org>
+Signed-off-by: Rik van Riel <riel@surriel.com>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Tested-by: Manali Shukla <Manali.Shukla@amd.com>
+Tested-by: Brendan Jackman <jackmanb@google.com>
+Tested-by: Michael Kelley <mhklinux@outlook.com>
+Link: https://lore.kernel.org/r/20250213161423.449435-2-riel@surriel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/Kconfig | 2 +-
+ arch/x86/kernel/paravirt.c | 17 +----------------
+ arch/x86/mm/pgtable.c | 27 ++++-----------------------
+ 3 files changed, 6 insertions(+), 40 deletions(-)
+
+diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
+index f86e7072a5ba3..473364353bd96 100644
+--- a/arch/x86/Kconfig
++++ b/arch/x86/Kconfig
+@@ -277,7 +277,7 @@ config X86
+ select HAVE_PCI
+ select HAVE_PERF_REGS
+ select HAVE_PERF_USER_STACK_DUMP
+- select MMU_GATHER_RCU_TABLE_FREE if PARAVIRT
++ select MMU_GATHER_RCU_TABLE_FREE
+ select MMU_GATHER_MERGE_VMAS
+ select HAVE_POSIX_CPU_TIMERS_TASK_WORK
+ select HAVE_REGS_AND_STACK_ACCESS_API
+diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c
+index c5bb980b8a673..6669d251c4f75 100644
+--- a/arch/x86/kernel/paravirt.c
++++ b/arch/x86/kernel/paravirt.c
+@@ -59,21 +59,6 @@ void __init native_pv_lock_init(void)
+ static_branch_enable(&virt_spin_lock_key);
+ }
+
+-#ifndef CONFIG_PT_RECLAIM
+-static void native_tlb_remove_table(struct mmu_gather *tlb, void *table)
+-{
+- struct ptdesc *ptdesc = (struct ptdesc *)table;
+-
+- pagetable_dtor(ptdesc);
+- tlb_remove_page(tlb, ptdesc_page(ptdesc));
+-}
+-#else
+-static void native_tlb_remove_table(struct mmu_gather *tlb, void *table)
+-{
+- tlb_remove_table(tlb, table);
+-}
+-#endif
+-
+ struct static_key paravirt_steal_enabled;
+ struct static_key paravirt_steal_rq_enabled;
+
+@@ -197,7 +182,7 @@ struct paravirt_patch_template pv_ops = {
+ .mmu.flush_tlb_kernel = native_flush_tlb_global,
+ .mmu.flush_tlb_one_user = native_flush_tlb_one_user,
+ .mmu.flush_tlb_multi = native_flush_tlb_multi,
+- .mmu.tlb_remove_table = native_tlb_remove_table,
++ .mmu.tlb_remove_table = tlb_remove_table,
+
+ .mmu.exit_mmap = paravirt_nop,
+ .mmu.notify_page_enc_status_changed = paravirt_nop,
+diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c
+index 9b0ee41b545c7..1ddbd799acdf5 100644
+--- a/arch/x86/mm/pgtable.c
++++ b/arch/x86/mm/pgtable.c
+@@ -18,25 +18,6 @@ EXPORT_SYMBOL(physical_mask);
+ #define PGTABLE_HIGHMEM 0
+ #endif
+
+-#ifndef CONFIG_PARAVIRT
+-#ifndef CONFIG_PT_RECLAIM
+-static inline
+-void paravirt_tlb_remove_table(struct mmu_gather *tlb, void *table)
+-{
+- struct ptdesc *ptdesc = (struct ptdesc *)table;
+-
+- pagetable_dtor(ptdesc);
+- tlb_remove_page(tlb, ptdesc_page(ptdesc));
+-}
+-#else
+-static inline
+-void paravirt_tlb_remove_table(struct mmu_gather *tlb, void *table)
+-{
+- tlb_remove_table(tlb, table);
+-}
+-#endif /* !CONFIG_PT_RECLAIM */
+-#endif /* !CONFIG_PARAVIRT */
+-
+ gfp_t __userpte_alloc_gfp = GFP_PGTABLE_USER | PGTABLE_HIGHMEM;
+
+ pgtable_t pte_alloc_one(struct mm_struct *mm)
+@@ -64,7 +45,7 @@ early_param("userpte", setup_userpte);
+ void ___pte_free_tlb(struct mmu_gather *tlb, struct page *pte)
+ {
+ paravirt_release_pte(page_to_pfn(pte));
+- paravirt_tlb_remove_table(tlb, page_ptdesc(pte));
++ tlb_remove_table(tlb, page_ptdesc(pte));
+ }
+
+ #if CONFIG_PGTABLE_LEVELS > 2
+@@ -78,21 +59,21 @@ void ___pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd)
+ #ifdef CONFIG_X86_PAE
+ tlb->need_flush_all = 1;
+ #endif
+- paravirt_tlb_remove_table(tlb, virt_to_ptdesc(pmd));
++ tlb_remove_table(tlb, virt_to_ptdesc(pmd));
+ }
+
+ #if CONFIG_PGTABLE_LEVELS > 3
+ void ___pud_free_tlb(struct mmu_gather *tlb, pud_t *pud)
+ {
+ paravirt_release_pud(__pa(pud) >> PAGE_SHIFT);
+- paravirt_tlb_remove_table(tlb, virt_to_ptdesc(pud));
++ tlb_remove_table(tlb, virt_to_ptdesc(pud));
+ }
+
+ #if CONFIG_PGTABLE_LEVELS > 4
+ void ___p4d_free_tlb(struct mmu_gather *tlb, p4d_t *p4d)
+ {
+ paravirt_release_p4d(__pa(p4d) >> PAGE_SHIFT);
+- paravirt_tlb_remove_table(tlb, virt_to_ptdesc(p4d));
++ tlb_remove_table(tlb, virt_to_ptdesc(p4d));
+ }
+ #endif /* CONFIG_PGTABLE_LEVELS > 4 */
+ #endif /* CONFIG_PGTABLE_LEVELS > 3 */
+--
+2.39.5
+
--- /dev/null
+From dc16939bcbe3e8d9eb7ff803d48390e3aee56af0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Feb 2025 14:18:44 -0500
+Subject: x86/nmi: Add an emergency handler in nmi_desc & use it in
+ nmi_shootdown_cpus()
+
+From: Waiman Long <longman@redhat.com>
+
+[ Upstream commit fe37c699ae3eed6e02ee55fbf5cb9ceb7fcfd76c ]
+
+Depending on the type of panics, it was found that the
+__register_nmi_handler() function can be called in NMI context from
+nmi_shootdown_cpus() leading to a lockdep splat:
+
+ WARNING: inconsistent lock state
+ inconsistent {INITIAL USE} -> {IN-NMI} usage.
+
+ lock(&nmi_desc[0].lock);
+ <Interrupt>
+ lock(&nmi_desc[0].lock);
+
+ Call Trace:
+ _raw_spin_lock_irqsave
+ __register_nmi_handler
+ nmi_shootdown_cpus
+ kdump_nmi_shootdown_cpus
+ native_machine_crash_shutdown
+ __crash_kexec
+
+In this particular case, the following panic message was printed before:
+
+ Kernel panic - not syncing: Fatal hardware error!
+
+This message seemed to be given out from __ghes_panic() running in
+NMI context.
+
+The __register_nmi_handler() function which takes the nmi_desc lock
+with irq disabled shouldn't be called from NMI context as this can
+lead to deadlock.
+
+The nmi_shootdown_cpus() function can only be invoked once. After the
+first invocation, all other CPUs should be stuck in the newly added
+crash_nmi_callback() and cannot respond to a second NMI.
+
+Fix it by adding a new emergency NMI handler to the nmi_desc
+structure and provide a new set_emergency_nmi_handler() helper to set
+crash_nmi_callback() in any context. The new emergency handler will
+preempt other handlers in the linked list. That will eliminate the need
+to take any lock and serve the panic in NMI use case.
+
+Signed-off-by: Waiman Long <longman@redhat.com>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Acked-by: Rik van Riel <riel@surriel.com>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Link: https://lore.kernel.org/r/20250206191844.131700-1-longman@redhat.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/include/asm/nmi.h | 2 ++
+ arch/x86/kernel/nmi.c | 42 ++++++++++++++++++++++++++++++++++++++
+ arch/x86/kernel/reboot.c | 10 +++------
+ 3 files changed, 47 insertions(+), 7 deletions(-)
+
+diff --git a/arch/x86/include/asm/nmi.h b/arch/x86/include/asm/nmi.h
+index 41a0ebb699ec6..f677382093f36 100644
+--- a/arch/x86/include/asm/nmi.h
++++ b/arch/x86/include/asm/nmi.h
+@@ -56,6 +56,8 @@ int __register_nmi_handler(unsigned int, struct nmiaction *);
+
+ void unregister_nmi_handler(unsigned int, const char *);
+
++void set_emergency_nmi_handler(unsigned int type, nmi_handler_t handler);
++
+ void stop_nmi(void);
+ void restart_nmi(void);
+ void local_touch_nmi(void);
+diff --git a/arch/x86/kernel/nmi.c b/arch/x86/kernel/nmi.c
+index ed163c8c8604e..9a95d00f14233 100644
+--- a/arch/x86/kernel/nmi.c
++++ b/arch/x86/kernel/nmi.c
+@@ -40,8 +40,12 @@
+ #define CREATE_TRACE_POINTS
+ #include <trace/events/nmi.h>
+
++/*
++ * An emergency handler can be set in any context including NMI
++ */
+ struct nmi_desc {
+ raw_spinlock_t lock;
++ nmi_handler_t emerg_handler;
+ struct list_head head;
+ };
+
+@@ -132,9 +136,22 @@ static void nmi_check_duration(struct nmiaction *action, u64 duration)
+ static int nmi_handle(unsigned int type, struct pt_regs *regs)
+ {
+ struct nmi_desc *desc = nmi_to_desc(type);
++ nmi_handler_t ehandler;
+ struct nmiaction *a;
+ int handled=0;
+
++ /*
++ * Call the emergency handler, if set
++ *
++ * In the case of crash_nmi_callback() emergency handler, it will
++ * return in the case of the crashing CPU to enable it to complete
++ * other necessary crashing actions ASAP. Other handlers in the
++ * linked list won't need to be run.
++ */
++ ehandler = desc->emerg_handler;
++ if (ehandler)
++ return ehandler(type, regs);
++
+ rcu_read_lock();
+
+ /*
+@@ -224,6 +241,31 @@ void unregister_nmi_handler(unsigned int type, const char *name)
+ }
+ EXPORT_SYMBOL_GPL(unregister_nmi_handler);
+
++/**
++ * set_emergency_nmi_handler - Set emergency handler
++ * @type: NMI type
++ * @handler: the emergency handler to be stored
++ *
++ * Set an emergency NMI handler which, if set, will preempt all the other
++ * handlers in the linked list. If a NULL handler is passed in, it will clear
++ * it. It is expected that concurrent calls to this function will not happen
++ * or the system is screwed beyond repair.
++ */
++void set_emergency_nmi_handler(unsigned int type, nmi_handler_t handler)
++{
++ struct nmi_desc *desc = nmi_to_desc(type);
++
++ if (WARN_ON_ONCE(desc->emerg_handler == handler))
++ return;
++ desc->emerg_handler = handler;
++
++ /*
++ * Ensure the emergency handler is visible to other CPUs before
++ * function return
++ */
++ smp_wmb();
++}
++
+ static void
+ pci_serr_error(unsigned char reason, struct pt_regs *regs)
+ {
+diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
+index dc1dd3f3e67fc..9aaac1f9f45b5 100644
+--- a/arch/x86/kernel/reboot.c
++++ b/arch/x86/kernel/reboot.c
+@@ -926,15 +926,11 @@ void nmi_shootdown_cpus(nmi_shootdown_cb callback)
+ shootdown_callback = callback;
+
+ atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
+- /* Would it be better to replace the trap vector here? */
+- if (register_nmi_handler(NMI_LOCAL, crash_nmi_callback,
+- NMI_FLAG_FIRST, "crash"))
+- return; /* Return what? */
++
+ /*
+- * Ensure the new callback function is set before sending
+- * out the NMI
++ * Set emergency handler to preempt other handlers.
+ */
+- wmb();
++ set_emergency_nmi_handler(NMI_LOCAL, crash_nmi_callback);
+
+ apic_send_IPI_allbutself(NMI_VECTOR);
+
+--
+2.39.5
+
--- /dev/null
+From d8e603969259e50aa632d1a3fde8883f41e26150 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 23 Jan 2025 14:07:37 -0500
+Subject: x86/relocs: Handle R_X86_64_REX_GOTPCRELX relocations
+
+From: Brian Gerst <brgerst@gmail.com>
+
+[ Upstream commit cb7927fda002ca49ae62e2782c1692acc7b80c67 ]
+
+Clang may produce R_X86_64_REX_GOTPCRELX relocations when redefining the
+stack protector location. Treat them as another type of PC-relative
+relocation.
+
+Signed-off-by: Brian Gerst <brgerst@gmail.com>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Link: https://lore.kernel.org/r/20250123190747.745588-6-brgerst@gmail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/tools/relocs.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c
+index e937be979ec86..92a1e503305ef 100644
+--- a/arch/x86/tools/relocs.c
++++ b/arch/x86/tools/relocs.c
+@@ -32,6 +32,11 @@ static struct relocs relocs32;
+ static struct relocs relocs32neg;
+ static struct relocs relocs64;
+ # define FMT PRIu64
++
++#ifndef R_X86_64_REX_GOTPCRELX
++# define R_X86_64_REX_GOTPCRELX 42
++#endif
++
+ #else
+ # define FMT PRIu32
+ #endif
+@@ -227,6 +232,7 @@ static const char *rel_type(unsigned type)
+ REL_TYPE(R_X86_64_PC16),
+ REL_TYPE(R_X86_64_8),
+ REL_TYPE(R_X86_64_PC8),
++ REL_TYPE(R_X86_64_REX_GOTPCRELX),
+ #else
+ REL_TYPE(R_386_NONE),
+ REL_TYPE(R_386_32),
+@@ -861,6 +867,7 @@ static int do_reloc64(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym,
+
+ case R_X86_64_PC32:
+ case R_X86_64_PLT32:
++ case R_X86_64_REX_GOTPCRELX:
+ /*
+ * PC relative relocations don't need to be adjusted unless
+ * referencing a percpu symbol.
+--
+2.39.5
+
--- /dev/null
+From c41a8b2954d722d3f52e36d9930f5ebbe99ceaa1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 19 Feb 2025 18:41:28 +0000
+Subject: x86/smpboot: Fix INIT delay assignment for extended Intel Families
+
+From: Sohil Mehta <sohil.mehta@intel.com>
+
+[ Upstream commit 7a2ad752746bfb13e89a83984ecc52a48bae4969 ]
+
+Some old crusty CPUs need an extra delay that slows down booting. See
+the comment above 'init_udelay' for details. Newer CPUs don't need the
+delay.
+
+Right now, for Intel, Family 6 and only Family 6 skips the delay. That
+leaves out both the Family 15 (Pentium 4s) and brand new Family 18/19
+models.
+
+The omission of Family 15 (Pentium 4s) seems like an oversight and 18/19
+do not need the delay.
+
+Skip the delay on all Intel processors Family 6 and beyond.
+
+Signed-off-by: Sohil Mehta <sohil.mehta@intel.com>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Link: https://lore.kernel.org/r/20250219184133.816753-11-sohil.mehta@intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/kernel/smpboot.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
+index c10850ae6f094..3d5069ee297bf 100644
+--- a/arch/x86/kernel/smpboot.c
++++ b/arch/x86/kernel/smpboot.c
+@@ -676,9 +676,9 @@ static void __init smp_quirk_init_udelay(void)
+ return;
+
+ /* if modern processor, use no delay */
+- if (((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) && (boot_cpu_data.x86 == 6)) ||
+- ((boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) && (boot_cpu_data.x86 >= 0x18)) ||
+- ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) && (boot_cpu_data.x86 >= 0xF))) {
++ if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && boot_cpu_data.x86_vfm >= INTEL_PENTIUM_PRO) ||
++ (boot_cpu_data.x86_vendor == X86_VENDOR_HYGON && boot_cpu_data.x86 >= 0x18) ||
++ (boot_cpu_data.x86_vendor == X86_VENDOR_AMD && boot_cpu_data.x86 >= 0xF)) {
+ init_udelay = 0;
+ return;
+ }
+--
+2.39.5
+
--- /dev/null
+From fb5cdc710092ea8865c74899e5cc017068a9e39e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 12 Mar 2025 12:48:49 +0100
+Subject: x86/stackprotector/64: Only export __ref_stack_chk_guard on
+ CONFIG_SMP
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Ingo Molnar <mingo@kernel.org>
+
+[ Upstream commit 91d5451d97ce35cbd510277fa3b7abf9caa4e34d ]
+
+The __ref_stack_chk_guard symbol doesn't exist on UP:
+
+ <stdin>:4:15: error: ‘__ref_stack_chk_guard’ undeclared here (not in a function)
+
+Fix the #ifdef around the entry.S export.
+
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Cc: Brian Gerst <brgerst@gmail.com>
+Cc: Ard Biesheuvel <ardb@kernel.org>
+Cc: Uros Bizjak <ubizjak@gmail.com>
+Link: https://lore.kernel.org/r/20250123190747.745588-8-brgerst@gmail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/entry/entry.S | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/arch/x86/entry/entry.S b/arch/x86/entry/entry.S
+index 58e3124ee2b42..5b96249734ada 100644
+--- a/arch/x86/entry/entry.S
++++ b/arch/x86/entry/entry.S
+@@ -63,7 +63,7 @@ THUNK warn_thunk_thunk, __warn_thunk
+ * entirely in the C code, and use an alias emitted by the linker script
+ * instead.
+ */
+-#ifdef CONFIG_STACKPROTECTOR
++#if defined(CONFIG_STACKPROTECTOR) && defined(CONFIG_SMP)
+ EXPORT_SYMBOL(__ref_stack_chk_guard);
+ #endif
+ #endif
+--
+2.39.5
+
--- /dev/null
+From b141cfe5571a915d4a27ac40e2687a7a2c5e93fb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 7 Feb 2025 13:15:36 +0100
+Subject: x86/traps: Cleanup and robustify decode_bug()
+
+From: Peter Zijlstra <peterz@infradead.org>
+
+[ Upstream commit c20ad96c9a8f0aeaf4e4057730a22de2657ad0c2 ]
+
+Notably, don't attempt to decode an immediate when MOD == 3.
+
+Additionally have it return the instruction length, such that WARN
+like bugs can more reliably skip to the correct instruction.
+
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Reviewed-by: Sami Tolvanen <samitolvanen@google.com>
+Link: https://lore.kernel.org/r/20250207122546.721120726@infradead.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/include/asm/bug.h | 5 ++-
+ arch/x86/include/asm/ibt.h | 4 +-
+ arch/x86/kernel/traps.c | 82 ++++++++++++++++++++++++++++----------
+ 3 files changed, 65 insertions(+), 26 deletions(-)
+
+diff --git a/arch/x86/include/asm/bug.h b/arch/x86/include/asm/bug.h
+index e85ac0c7c039e..1a5e4b3726940 100644
+--- a/arch/x86/include/asm/bug.h
++++ b/arch/x86/include/asm/bug.h
+@@ -22,8 +22,9 @@
+ #define SECOND_BYTE_OPCODE_UD2 0x0b
+
+ #define BUG_NONE 0xffff
+-#define BUG_UD1 0xfffe
+-#define BUG_UD2 0xfffd
++#define BUG_UD2 0xfffe
++#define BUG_UD1 0xfffd
++#define BUG_UD1_UBSAN 0xfffc
+
+ #ifdef CONFIG_GENERIC_BUG
+
+diff --git a/arch/x86/include/asm/ibt.h b/arch/x86/include/asm/ibt.h
+index e7f4caa42839a..b04bcbb1a14ef 100644
+--- a/arch/x86/include/asm/ibt.h
++++ b/arch/x86/include/asm/ibt.h
+@@ -41,7 +41,7 @@
+ _ASM_PTR fname "\n\t" \
+ ".popsection\n\t"
+
+-static inline __attribute_const__ u32 gen_endbr(void)
++static __always_inline __attribute_const__ u32 gen_endbr(void)
+ {
+ u32 endbr;
+
+@@ -56,7 +56,7 @@ static inline __attribute_const__ u32 gen_endbr(void)
+ return endbr;
+ }
+
+-static inline __attribute_const__ u32 gen_endbr_poison(void)
++static __always_inline __attribute_const__ u32 gen_endbr_poison(void)
+ {
+ /*
+ * 4 byte NOP that isn't NOP4 (in fact it is OSP NOP3), such that it
+diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
+index 5e3e036e6e537..b18fc7539b8d7 100644
+--- a/arch/x86/kernel/traps.c
++++ b/arch/x86/kernel/traps.c
+@@ -94,10 +94,17 @@ __always_inline int is_valid_bugaddr(unsigned long addr)
+
+ /*
+ * Check for UD1 or UD2, accounting for Address Size Override Prefixes.
+- * If it's a UD1, get the ModRM byte to pass along to UBSan.
++ * If it's a UD1, further decode to determine its use:
++ *
++ * UBSan{0}: 67 0f b9 00 ud1 (%eax),%eax
++ * UBSan{10}: 67 0f b9 40 10 ud1 0x10(%eax),%eax
++ * static_call: 0f b9 cc ud1 %esp,%ecx
++ *
++ * Notably UBSAN uses EAX, static_call uses ECX.
+ */
+-__always_inline int decode_bug(unsigned long addr, u32 *imm)
++__always_inline int decode_bug(unsigned long addr, s32 *imm, int *len)
+ {
++ unsigned long start = addr;
+ u8 v;
+
+ if (addr < TASK_SIZE_MAX)
+@@ -110,24 +117,42 @@ __always_inline int decode_bug(unsigned long addr, u32 *imm)
+ return BUG_NONE;
+
+ v = *(u8 *)(addr++);
+- if (v == SECOND_BYTE_OPCODE_UD2)
++ if (v == SECOND_BYTE_OPCODE_UD2) {
++ *len = addr - start;
+ return BUG_UD2;
++ }
+
+- if (!IS_ENABLED(CONFIG_UBSAN_TRAP) || v != SECOND_BYTE_OPCODE_UD1)
++ if (v != SECOND_BYTE_OPCODE_UD1)
+ return BUG_NONE;
+
+- /* Retrieve the immediate (type value) for the UBSAN UD1 */
+- v = *(u8 *)(addr++);
+- if (X86_MODRM_RM(v) == 4)
+- addr++;
+-
+ *imm = 0;
+- if (X86_MODRM_MOD(v) == 1)
+- *imm = *(u8 *)addr;
+- else if (X86_MODRM_MOD(v) == 2)
+- *imm = *(u32 *)addr;
+- else
+- WARN_ONCE(1, "Unexpected MODRM_MOD: %u\n", X86_MODRM_MOD(v));
++ v = *(u8 *)(addr++); /* ModRM */
++
++ if (X86_MODRM_MOD(v) != 3 && X86_MODRM_RM(v) == 4)
++ addr++; /* SIB */
++
++ /* Decode immediate, if present */
++ switch (X86_MODRM_MOD(v)) {
++ case 0: if (X86_MODRM_RM(v) == 5)
++ addr += 4; /* RIP + disp32 */
++ break;
++
++ case 1: *imm = *(s8 *)addr;
++ addr += 1;
++ break;
++
++ case 2: *imm = *(s32 *)addr;
++ addr += 4;
++ break;
++
++ case 3: break;
++ }
++
++ /* record instruction length */
++ *len = addr - start;
++
++ if (X86_MODRM_REG(v) == 0) /* EAX */
++ return BUG_UD1_UBSAN;
+
+ return BUG_UD1;
+ }
+@@ -258,10 +283,10 @@ static inline void handle_invalid_op(struct pt_regs *regs)
+ static noinstr bool handle_bug(struct pt_regs *regs)
+ {
+ bool handled = false;
+- int ud_type;
+- u32 imm;
++ int ud_type, ud_len;
++ s32 ud_imm;
+
+- ud_type = decode_bug(regs->ip, &imm);
++ ud_type = decode_bug(regs->ip, &ud_imm, &ud_len);
+ if (ud_type == BUG_NONE)
+ return handled;
+
+@@ -281,15 +306,28 @@ static noinstr bool handle_bug(struct pt_regs *regs)
+ */
+ if (regs->flags & X86_EFLAGS_IF)
+ raw_local_irq_enable();
+- if (ud_type == BUG_UD2) {
++
++ switch (ud_type) {
++ case BUG_UD2:
+ if (report_bug(regs->ip, regs) == BUG_TRAP_TYPE_WARN ||
+ handle_cfi_failure(regs) == BUG_TRAP_TYPE_WARN) {
+- regs->ip += LEN_UD2;
++ regs->ip += ud_len;
+ handled = true;
+ }
+- } else if (IS_ENABLED(CONFIG_UBSAN_TRAP)) {
+- pr_crit("%s at %pS\n", report_ubsan_failure(regs, imm), (void *)regs->ip);
++ break;
++
++ case BUG_UD1_UBSAN:
++ if (IS_ENABLED(CONFIG_UBSAN_TRAP)) {
++ pr_crit("%s at %pS\n",
++ report_ubsan_failure(regs, ud_imm),
++ (void *)regs->ip);
++ }
++ break;
++
++ default:
++ break;
+ }
++
+ if (regs->flags & X86_EFLAGS_IF)
+ raw_local_irq_disable();
+ instrumentation_end();
+--
+2.39.5
+
--- /dev/null
+From 86e188ad56b9086716c7119310c7c5bcdafe468e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Feb 2025 14:50:15 +0000
+Subject: xen: Add support for XenServer 6.1 platform device
+
+From: Frediano Ziglio <frediano.ziglio@cloud.com>
+
+[ Upstream commit 2356f15caefc0cc63d9cc5122641754f76ef9b25 ]
+
+On XenServer on Windows machine a platform device with ID 2 instead of
+1 is used.
+
+This device is mainly identical to device 1 but due to some Windows
+update behaviour it was decided to use a device with a different ID.
+
+This causes compatibility issues with Linux which expects, if Xen
+is detected, to find a Xen platform device (5853:0001) otherwise code
+will crash due to some missing initialization (specifically grant
+tables). Specifically from dmesg
+
+ RIP: 0010:gnttab_expand+0x29/0x210
+ Code: 90 0f 1f 44 00 00 55 31 d2 48 89 e5 41 57 41 56 41 55 41 89 fd
+ 41 54 53 48 83 ec 10 48 8b 05 7e 9a 49 02 44 8b 35 a7 9a 49 02
+ <8b> 48 04 8d 44 39 ff f7 f1 45 8d 24 06 89 c3 e8 43 fe ff ff
+ 44 39
+ RSP: 0000:ffffba34c01fbc88 EFLAGS: 00010086
+ ...
+
+The device 2 is presented by Xapi adding device specification to
+Qemu command line.
+
+Signed-off-by: Frediano Ziglio <frediano.ziglio@cloud.com>
+Acked-by: Juergen Gross <jgross@suse.com>
+Message-ID: <20250227145016.25350-1-frediano.ziglio@cloud.com>
+Signed-off-by: Juergen Gross <jgross@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/xen/platform-pci.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/xen/platform-pci.c b/drivers/xen/platform-pci.c
+index 544d3f9010b92..1db82da56db62 100644
+--- a/drivers/xen/platform-pci.c
++++ b/drivers/xen/platform-pci.c
+@@ -26,6 +26,8 @@
+
+ #define DRV_NAME "xen-platform-pci"
+
++#define PCI_DEVICE_ID_XEN_PLATFORM_XS61 0x0002
++
+ static unsigned long platform_mmio;
+ static unsigned long platform_mmio_alloc;
+ static unsigned long platform_mmiolen;
+@@ -174,6 +176,8 @@ static int platform_pci_probe(struct pci_dev *pdev,
+ static const struct pci_device_id platform_pci_tbl[] = {
+ {PCI_VENDOR_ID_XEN, PCI_DEVICE_ID_XEN_PLATFORM,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
++ {PCI_VENDOR_ID_XEN, PCI_DEVICE_ID_XEN_PLATFORM_XS61,
++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0,}
+ };
+
+--
+2.39.5
+
--- /dev/null
+From abcb17d547cb47a00cbb94366e77746e0fd0f0cd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 19 Feb 2025 10:20:55 +0100
+Subject: xen/pci: Do not register devices with segments >= 0x10000
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Roger Pau Monne <roger.pau@citrix.com>
+
+[ Upstream commit 5ccf1b8ae76ddf348e02a0d1564ff9baf8b6c415 ]
+
+The current hypercall interface for doing PCI device operations always uses
+a segment field that has a 16 bit width. However on Linux there are buses
+like VMD that hook up devices into the PCI hierarchy at segment >= 0x10000,
+after the maximum possible segment enumerated in ACPI.
+
+Attempting to register or manage those devices with Xen would result in
+errors at best, or overlaps with existing devices living on the truncated
+equivalent segment values. Note also that the VMD segment numbers are
+arbitrarily assigned by the OS, and hence there would need to be some
+negotiation between Xen and the OS to agree on how to enumerate VMD
+segments and devices behind them.
+
+Skip notifying Xen about those devices. Given how VMD bridges can
+multiplex interrupts on behalf of devices behind them there's no need for
+Xen to be aware of such devices for them to be usable by Linux.
+
+Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
+Acked-by: Juergen Gross <jgross@suse.com>
+Message-ID: <20250219092059.90850-2-roger.pau@citrix.com>
+Signed-off-by: Juergen Gross <jgross@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/xen/pci.c | 32 ++++++++++++++++++++++++++++++++
+ 1 file changed, 32 insertions(+)
+
+diff --git a/drivers/xen/pci.c b/drivers/xen/pci.c
+index 416f231809cb6..bfe07adb3e3a6 100644
+--- a/drivers/xen/pci.c
++++ b/drivers/xen/pci.c
+@@ -43,6 +43,18 @@ static int xen_add_device(struct device *dev)
+ pci_mcfg_reserved = true;
+ }
+ #endif
++
++ if (pci_domain_nr(pci_dev->bus) >> 16) {
++ /*
++ * The hypercall interface is limited to 16bit PCI segment
++ * values, do not attempt to register devices with Xen in
++ * segments greater or equal than 0x10000.
++ */
++ dev_info(dev,
++ "not registering with Xen: invalid PCI segment\n");
++ return 0;
++ }
++
+ if (pci_seg_supported) {
+ DEFINE_RAW_FLEX(struct physdev_pci_device_add, add, optarr, 1);
+
+@@ -149,6 +161,16 @@ static int xen_remove_device(struct device *dev)
+ int r;
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+
++ if (pci_domain_nr(pci_dev->bus) >> 16) {
++ /*
++ * The hypercall interface is limited to 16bit PCI segment
++ * values.
++ */
++ dev_info(dev,
++ "not unregistering with Xen: invalid PCI segment\n");
++ return 0;
++ }
++
+ if (pci_seg_supported) {
+ struct physdev_pci_device device = {
+ .seg = pci_domain_nr(pci_dev->bus),
+@@ -182,6 +204,16 @@ int xen_reset_device(const struct pci_dev *dev)
+ .flags = PCI_DEVICE_RESET_FLR,
+ };
+
++ if (pci_domain_nr(dev->bus) >> 16) {
++ /*
++ * The hypercall interface is limited to 16bit PCI segment
++ * values.
++ */
++ dev_info(&dev->dev,
++ "unable to notify Xen of device reset: invalid PCI segment\n");
++ return 0;
++ }
++
+ return HYPERVISOR_physdev_op(PHYSDEVOP_pci_device_reset, &device);
+ }
+ EXPORT_SYMBOL_GPL(xen_reset_device);
+--
+2.39.5
+
--- /dev/null
+From 9c6d54ccd05c0b1a7509a95d412e75a13ae90e20 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 6 May 2025 16:44:56 -0400
+Subject: xenbus: Allow PVH dom0 a non-local xenstore
+
+From: Jason Andryuk <jason.andryuk@amd.com>
+
+[ Upstream commit 90989869baae47ee2aa3bcb6f6eb9fbbe4287958 ]
+
+Make xenbus_init() allow a non-local xenstore for a PVH dom0 - it is
+currently forced to XS_LOCAL. With Hyperlaunch booting dom0 and a
+xenstore stubdom, dom0 can be handled as a regular XS_HVM following the
+late init path.
+
+Ideally we'd drop the use of xen_initial_domain() and just check for the
+event channel instead. However, ARM has a xen,enhanced no-xenstore
+mode, where the event channel and PFN would both be 0. Retain the
+xen_initial_domain() check, and use that for an additional check when
+the event channel is 0.
+
+Check the full 64bit HVM_PARAM_STORE_EVTCHN value to catch the off
+chance that high bits are set for the 32bit event channel.
+
+Signed-off-by: Jason Andryuk <jason.andryuk@amd.com>
+Change-Id: I5506da42e4c6b8e85079fefb2f193c8de17c7437
+Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>
+Signed-off-by: Juergen Gross <jgross@suse.com>
+Message-ID: <20250506204456.5220-1-jason.andryuk@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/xen/xenbus/xenbus_probe.c | 14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c
+index 6d32ffb011365..86fe6e7790566 100644
+--- a/drivers/xen/xenbus/xenbus_probe.c
++++ b/drivers/xen/xenbus/xenbus_probe.c
+@@ -966,9 +966,15 @@ static int __init xenbus_init(void)
+ if (xen_pv_domain())
+ xen_store_domain_type = XS_PV;
+ if (xen_hvm_domain())
++ {
+ xen_store_domain_type = XS_HVM;
+- if (xen_hvm_domain() && xen_initial_domain())
+- xen_store_domain_type = XS_LOCAL;
++ err = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN, &v);
++ if (err)
++ goto out_error;
++ xen_store_evtchn = (int)v;
++ if (!v && xen_initial_domain())
++ xen_store_domain_type = XS_LOCAL;
++ }
+ if (xen_pv_domain() && !xen_start_info->store_evtchn)
+ xen_store_domain_type = XS_LOCAL;
+ if (xen_pv_domain() && xen_start_info->store_evtchn)
+@@ -987,10 +993,6 @@ static int __init xenbus_init(void)
+ xen_store_interface = gfn_to_virt(xen_store_gfn);
+ break;
+ case XS_HVM:
+- err = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN, &v);
+- if (err)
+- goto out_error;
+- xen_store_evtchn = (int)v;
+ err = hvm_get_parameter(HVM_PARAM_STORE_PFN, &v);
+ if (err)
+ goto out_error;
+--
+2.39.5
+
--- /dev/null
+From 413c86f30f373395052d2694e75386c20444b087 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Feb 2025 20:27:49 +0200
+Subject: xfrm: prevent high SEQ input in non-ESN mode
+
+From: Leon Romanovsky <leonro@nvidia.com>
+
+[ Upstream commit e3aa43a50a6455831e3c32dabc7ece38d9cd9d05 ]
+
+In non-ESN mode, the SEQ numbers are limited to 32 bits and seq_hi/oseq_hi
+are not used. So make sure that user gets proper error message, in case
+such assignment occurred.
+
+Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
+Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/xfrm/xfrm_user.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
+index 82a768500999b..b5266e0848e82 100644
+--- a/net/xfrm/xfrm_user.c
++++ b/net/xfrm/xfrm_user.c
+@@ -178,6 +178,12 @@ static inline int verify_replay(struct xfrm_usersa_info *p,
+ "Replay seq and seq_hi should be 0 for output SA");
+ return -EINVAL;
+ }
++ if (rs->oseq_hi && !(p->flags & XFRM_STATE_ESN)) {
++ NL_SET_ERR_MSG(
++ extack,
++ "Replay oseq_hi should be 0 in non-ESN mode for output SA");
++ return -EINVAL;
++ }
+ if (rs->bmp_len) {
+ NL_SET_ERR_MSG(extack, "Replay bmp_len should 0 for output SA");
+ return -EINVAL;
+@@ -190,6 +196,12 @@ static inline int verify_replay(struct xfrm_usersa_info *p,
+ "Replay oseq and oseq_hi should be 0 for input SA");
+ return -EINVAL;
+ }
++ if (rs->seq_hi && !(p->flags & XFRM_STATE_ESN)) {
++ NL_SET_ERR_MSG(
++ extack,
++ "Replay seq_hi should be 0 in non-ESN mode for input SA");
++ return -EINVAL;
++ }
+ }
+
+ return 0;
+--
+2.39.5
+