--- /dev/null
+From 37388a81aab1a4c4fcf870fc68df3fb28291c49e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 9 Sep 2024 22:15:24 -0500
+Subject: ACPI: CPPC: Add support for setting EPP register in FFH
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Mario Limonciello <mario.limonciello@amd.com>
+
+[ Upstream commit aaf21ac93909e08a12931173336bdb52ac8499f1 ]
+
+Some Asus AMD systems are reported to not be able to change EPP values
+because the BIOS doesn't advertise support for the CPPC MSR and the PCC
+region is not configured.
+
+However the ACPI 6.2 specification allows CPC registers to be declared
+in FFH:
+```
+Starting with ACPI Specification 6.2, all _CPC registers can be in
+PCC, System Memory, System IO, or Functional Fixed Hardware address
+spaces. OSPM support for this more flexible register space scheme
+is indicated by the “Flexible Address Space for CPPC Registers” _OSC
+bit.
+```
+
+If this _OSC has been set allow using FFH to configure EPP.
+
+Reported-by: al0uette@outlook.com
+Closes: https://bugzilla.kernel.org/show_bug.cgi?id=218686
+Suggested-by: al0uette@outlook.com
+Tested-by: vderp@icloud.com
+Tested-by: al0uette@outlook.com
+Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
+Link: https://patch.msgid.link/20240910031524.106387-1-superm1@kernel.org
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/acpi/cppc_acpi.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
+index 2a588e4ed4af4..6a048d44fbcf6 100644
+--- a/drivers/acpi/cppc_acpi.c
++++ b/drivers/acpi/cppc_acpi.c
+@@ -103,6 +103,11 @@ static DEFINE_PER_CPU(struct cpc_desc *, cpc_desc_ptr);
+ (cpc)->cpc_entry.reg.space_id == \
+ ACPI_ADR_SPACE_PLATFORM_COMM)
+
++/* Check if a CPC register is in FFH */
++#define CPC_IN_FFH(cpc) ((cpc)->type == ACPI_TYPE_BUFFER && \
++ (cpc)->cpc_entry.reg.space_id == \
++ ACPI_ADR_SPACE_FIXED_HARDWARE)
++
+ /* Check if a CPC register is in SystemMemory */
+ #define CPC_IN_SYSTEM_MEMORY(cpc) ((cpc)->type == ACPI_TYPE_BUFFER && \
+ (cpc)->cpc_entry.reg.space_id == \
+@@ -1519,9 +1524,12 @@ int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool enable)
+ /* after writing CPC, transfer the ownership of PCC to platform */
+ ret = send_pcc_cmd(pcc_ss_id, CMD_WRITE);
+ up_write(&pcc_ss_data->pcc_lock);
++ } else if (osc_cpc_flexible_adr_space_confirmed &&
++ CPC_SUPPORTED(epp_set_reg) && CPC_IN_FFH(epp_set_reg)) {
++ ret = cpc_write(cpu, epp_set_reg, perf_ctrls->energy_perf);
+ } else {
+ ret = -ENOTSUPP;
+- pr_debug("_CPC in PCC is not supported\n");
++ pr_debug("_CPC in PCC and _CPC in FFH are not supported\n");
+ }
+
+ return ret;
+--
+2.43.0
+
--- /dev/null
+From 076c028fbcdc9eb276b319b82f74e1d62c54d959 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 4 Jul 2024 18:26:54 +0200
+Subject: ACPI: EC: Do not release locks during operation region accesses
+
+From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+
+[ Upstream commit dc171114926ec390ab90f46534545420ec03e458 ]
+
+It is not particularly useful to release locks (the EC mutex and the
+ACPI global lock, if present) and re-acquire them immediately thereafter
+during EC address space accesses in acpi_ec_space_handler().
+
+First, releasing them for a while before grabbing them again does not
+really help anyone because there may not be enough time for another
+thread to acquire them.
+
+Second, if another thread successfully acquires them and carries out
+a new EC write or read in the middle if an operation region access in
+progress, it may confuse the EC firmware, especially after the burst
+mode has been enabled.
+
+Finally, manipulating the locks after writing or reading every single
+byte of data is overhead that it is better to avoid.
+
+Accordingly, modify the code to carry out EC address space accesses
+entirely without releasing the locks.
+
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
+Link: https://patch.msgid.link/12473338.O9o76ZdvQC@rjwysocki.net
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/acpi/ec.c | 55 +++++++++++++++++++++++++++++++++++++++++------
+ 1 file changed, 49 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
+index 38d2f6e6b12b4..25399f6dde7e2 100644
+--- a/drivers/acpi/ec.c
++++ b/drivers/acpi/ec.c
+@@ -783,6 +783,9 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
+ unsigned long tmp;
+ int ret = 0;
+
++ if (t->rdata)
++ memset(t->rdata, 0, t->rlen);
++
+ /* start transaction */
+ spin_lock_irqsave(&ec->lock, tmp);
+ /* Enable GPE for command processing (IBF=0/OBF=1) */
+@@ -819,8 +822,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
+
+ if (!ec || (!t) || (t->wlen && !t->wdata) || (t->rlen && !t->rdata))
+ return -EINVAL;
+- if (t->rdata)
+- memset(t->rdata, 0, t->rlen);
+
+ mutex_lock(&ec->mutex);
+ if (ec->global_lock) {
+@@ -847,7 +848,7 @@ static int acpi_ec_burst_enable(struct acpi_ec *ec)
+ .wdata = NULL, .rdata = &d,
+ .wlen = 0, .rlen = 1};
+
+- return acpi_ec_transaction(ec, &t);
++ return acpi_ec_transaction_unlocked(ec, &t);
+ }
+
+ static int acpi_ec_burst_disable(struct acpi_ec *ec)
+@@ -857,7 +858,7 @@ static int acpi_ec_burst_disable(struct acpi_ec *ec)
+ .wlen = 0, .rlen = 0};
+
+ return (acpi_ec_read_status(ec) & ACPI_EC_FLAG_BURST) ?
+- acpi_ec_transaction(ec, &t) : 0;
++ acpi_ec_transaction_unlocked(ec, &t) : 0;
+ }
+
+ static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 *data)
+@@ -873,6 +874,19 @@ static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 *data)
+ return result;
+ }
+
++static int acpi_ec_read_unlocked(struct acpi_ec *ec, u8 address, u8 *data)
++{
++ int result;
++ u8 d;
++ struct transaction t = {.command = ACPI_EC_COMMAND_READ,
++ .wdata = &address, .rdata = &d,
++ .wlen = 1, .rlen = 1};
++
++ result = acpi_ec_transaction_unlocked(ec, &t);
++ *data = d;
++ return result;
++}
++
+ static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data)
+ {
+ u8 wdata[2] = { address, data };
+@@ -883,6 +897,16 @@ static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data)
+ return acpi_ec_transaction(ec, &t);
+ }
+
++static int acpi_ec_write_unlocked(struct acpi_ec *ec, u8 address, u8 data)
++{
++ u8 wdata[2] = { address, data };
++ struct transaction t = {.command = ACPI_EC_COMMAND_WRITE,
++ .wdata = wdata, .rdata = NULL,
++ .wlen = 2, .rlen = 0};
++
++ return acpi_ec_transaction_unlocked(ec, &t);
++}
++
+ int ec_read(u8 addr, u8 *val)
+ {
+ int err;
+@@ -1323,6 +1347,7 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
+ struct acpi_ec *ec = handler_context;
+ int result = 0, i, bytes = bits / 8;
+ u8 *value = (u8 *)value64;
++ u32 glk;
+
+ if ((address > 0xFF) || !value || !handler_context)
+ return AE_BAD_PARAMETER;
+@@ -1330,13 +1355,25 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
+ if (function != ACPI_READ && function != ACPI_WRITE)
+ return AE_BAD_PARAMETER;
+
++ mutex_lock(&ec->mutex);
++
++ if (ec->global_lock) {
++ acpi_status status;
++
++ status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
++ if (ACPI_FAILURE(status)) {
++ result = -ENODEV;
++ goto unlock;
++ }
++ }
++
+ if (ec->busy_polling || bits > 8)
+ acpi_ec_burst_enable(ec);
+
+ for (i = 0; i < bytes; ++i, ++address, ++value) {
+ result = (function == ACPI_READ) ?
+- acpi_ec_read(ec, address, value) :
+- acpi_ec_write(ec, address, *value);
++ acpi_ec_read_unlocked(ec, address, value) :
++ acpi_ec_write_unlocked(ec, address, *value);
+ if (result < 0)
+ break;
+ }
+@@ -1344,6 +1381,12 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
+ if (ec->busy_polling || bits > 8)
+ acpi_ec_burst_disable(ec);
+
++ if (ec->global_lock)
++ acpi_release_global_lock(glk);
++
++unlock:
++ mutex_unlock(&ec->mutex);
++
+ switch (result) {
+ case -EINVAL:
+ return AE_BAD_PARAMETER;
+--
+2.43.0
+
--- /dev/null
+From c82a268eeb0d10b9b08ebd401ff7243df48358d5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 25 Aug 2024 23:13:52 +0900
+Subject: ACPI: PAD: fix crash in exit_round_robin()
+
+From: Seiji Nishikawa <snishika@redhat.com>
+
+[ Upstream commit 0a2ed70a549e61c5181bad5db418d223b68ae932 ]
+
+The kernel occasionally crashes in cpumask_clear_cpu(), which is called
+within exit_round_robin(), because when executing clear_bit(nr, addr) with
+nr set to 0xffffffff, the address calculation may cause misalignment within
+the memory, leading to access to an invalid memory address.
+
+----------
+BUG: unable to handle kernel paging request at ffffffffe0740618
+ ...
+CPU: 3 PID: 2919323 Comm: acpi_pad/14 Kdump: loaded Tainted: G OE X --------- - - 4.18.0-425.19.2.el8_7.x86_64 #1
+ ...
+RIP: 0010:power_saving_thread+0x313/0x411 [acpi_pad]
+Code: 89 cd 48 89 d3 eb d1 48 c7 c7 55 70 72 c0 e8 64 86 b0 e4 c6 05 0d a1 02 00 01 e9 bc fd ff ff 45 89 e4 42 8b 04 a5 20 82 72 c0 <f0> 48 0f b3 05 f4 9c 01 00 42 c7 04 a5 20 82 72 c0 ff ff ff ff 31
+RSP: 0018:ff72a5d51fa77ec8 EFLAGS: 00010202
+RAX: 00000000ffffffff RBX: ff462981e5d8cb80 RCX: 0000000000000000
+RDX: 0000000000000000 RSI: 0000000000000246 RDI: 0000000000000246
+RBP: ff46297556959d80 R08: 0000000000000382 R09: ff46297c8d0f38d8
+R10: 0000000000000000 R11: 0000000000000001 R12: 000000000000000e
+R13: 0000000000000000 R14: ffffffffffffffff R15: 000000000000000e
+FS: 0000000000000000(0000) GS:ff46297a800c0000(0000) knlGS:0000000000000000
+CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+CR2: ffffffffe0740618 CR3: 0000007e20410004 CR4: 0000000000771ee0
+DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
+DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
+PKRU: 55555554
+Call Trace:
+ ? acpi_pad_add+0x120/0x120 [acpi_pad]
+ kthread+0x10b/0x130
+ ? set_kthread_struct+0x50/0x50
+ ret_from_fork+0x1f/0x40
+ ...
+CR2: ffffffffe0740618
+
+crash> dis -lr ffffffffc0726923
+ ...
+/usr/src/debug/kernel-4.18.0-425.19.2.el8_7/linux-4.18.0-425.19.2.el8_7.x86_64/./include/linux/cpumask.h: 114
+0xffffffffc0726918 <power_saving_thread+776>: mov %r12d,%r12d
+/usr/src/debug/kernel-4.18.0-425.19.2.el8_7/linux-4.18.0-425.19.2.el8_7.x86_64/./include/linux/cpumask.h: 325
+0xffffffffc072691b <power_saving_thread+779>: mov -0x3f8d7de0(,%r12,4),%eax
+/usr/src/debug/kernel-4.18.0-425.19.2.el8_7/linux-4.18.0-425.19.2.el8_7.x86_64/./arch/x86/include/asm/bitops.h: 80
+0xffffffffc0726923 <power_saving_thread+787>: lock btr %rax,0x19cf4(%rip) # 0xffffffffc0740620 <pad_busy_cpus_bits>
+
+crash> px tsk_in_cpu[14]
+$66 = 0xffffffff
+
+crash> px 0xffffffffc072692c+0x19cf4
+$99 = 0xffffffffc0740620
+
+crash> sym 0xffffffffc0740620
+ffffffffc0740620 (b) pad_busy_cpus_bits [acpi_pad]
+
+crash> px pad_busy_cpus_bits[0]
+$42 = 0xfffc0
+----------
+
+To fix this, ensure that tsk_in_cpu[tsk_index] != -1 before calling
+cpumask_clear_cpu() in exit_round_robin(), just as it is done in
+round_robin_cpu().
+
+Signed-off-by: Seiji Nishikawa <snishika@redhat.com>
+Link: https://patch.msgid.link/20240825141352.25280-1-snishika@redhat.com
+[ rjw: Subject edit, avoid updates to the same value ]
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/acpi/acpi_pad.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c
+index bd1ad07f02907..e84509b19f94d 100644
+--- a/drivers/acpi/acpi_pad.c
++++ b/drivers/acpi/acpi_pad.c
+@@ -132,8 +132,10 @@ static void exit_round_robin(unsigned int tsk_index)
+ {
+ struct cpumask *pad_busy_cpus = to_cpumask(pad_busy_cpus_bits);
+
+- cpumask_clear_cpu(tsk_in_cpu[tsk_index], pad_busy_cpus);
+- tsk_in_cpu[tsk_index] = -1;
++ if (tsk_in_cpu[tsk_index] != -1) {
++ cpumask_clear_cpu(tsk_in_cpu[tsk_index], pad_busy_cpus);
++ tsk_in_cpu[tsk_index] = -1;
++ }
+ }
+
+ static unsigned int idle_pct = 5; /* percentage */
+--
+2.43.0
+
--- /dev/null
+From f40ceea36548d65154cbf4e71a6133f4fdc428c6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 2 Sep 2024 21:43:05 -0400
+Subject: ACPI: resource: Skip IRQ override on Asus Vivobook Go E1404GAB
+
+From: Tamim Khan <tamim@fusetak.com>
+
+[ Upstream commit 49e9cc315604972cc14868cb67831e3e8c3f1470 ]
+
+Like other Asus Vivobooks, the Asus Vivobook Go E1404GAB has a DSDT
+that describes IRQ 1 as ActiveLow, while the kernel overrides to Edge_High.
+
+This override prevents the internal keyboard from working.
+
+Fix the problem by adding this laptop to the table that prevents the kernel
+from overriding the IRQ.
+
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=219212
+Signed-off-by: Tamim Khan <tamim@fusetak.com>
+Link: https://patch.msgid.link/20240903014317.38858-1-tamim@fusetak.com
+[ rjw: Changelog edits ]
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/acpi/resource.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c
+index cb2aacbb93357..8a4726e2eb693 100644
+--- a/drivers/acpi/resource.c
++++ b/drivers/acpi/resource.c
+@@ -503,6 +503,13 @@ static const struct dmi_system_id irq1_level_low_skip_override[] = {
+ DMI_MATCH(DMI_BOARD_NAME, "B2502FBA"),
+ },
+ },
++ {
++ /* Asus Vivobook Go E1404GAB */
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
++ DMI_MATCH(DMI_BOARD_NAME, "E1404GAB"),
++ },
++ },
+ {
+ /* Asus Vivobook E1504GA */
+ .matches = {
+--
+2.43.0
+
--- /dev/null
+From 868c366b71d3a9eddc22f45b52a14a0ce2dd4c36 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 7 Sep 2024 14:44:19 +0200
+Subject: ACPI: video: Add force_vendor quirk for Panasonic Toughbook CF-18
+
+From: Hans de Goede <hdegoede@redhat.com>
+
+[ Upstream commit eb7b0f12e13ba99e64e3a690c2166895ed63b437 ]
+
+The Panasonic Toughbook CF-18 advertises both native and vendor backlight
+control interfaces. But only the vendor one actually works.
+
+acpi_video_get_backlight_type() will pick the non working native backlight
+by default, add a quirk to select the working vendor backlight instead.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Link: https://patch.msgid.link/20240907124419.21195-1-hdegoede@redhat.com
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/acpi/video_detect.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
+index 75a5f559402f8..428a7399fe04a 100644
+--- a/drivers/acpi/video_detect.c
++++ b/drivers/acpi/video_detect.c
+@@ -254,6 +254,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "PCG-FRV35"),
+ },
+ },
++ {
++ .callback = video_detect_force_vendor,
++ /* Panasonic Toughbook CF-18 */
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "Matsushita Electric Industrial"),
++ DMI_MATCH(DMI_PRODUCT_NAME, "CF-18"),
++ },
++ },
+
+ /*
+ * Toshiba models with Transflective display, these need to use
+--
+2.43.0
+
--- /dev/null
+From 145ecb817f92512d9578d61098adddcaae580434 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 18 Jul 2024 14:05:48 +0800
+Subject: ACPICA: check null return of ACPI_ALLOCATE_ZEROED() in
+ acpi_db_convert_to_package()
+
+From: Pei Xiao <xiaopei01@kylinos.cn>
+
+[ Upstream commit a5242874488eba2b9062985bf13743c029821330 ]
+
+ACPICA commit 4d4547cf13cca820ff7e0f859ba83e1a610b9fd0
+
+ACPI_ALLOCATE_ZEROED() may fail, elements might be NULL and will cause
+NULL pointer dereference later.
+
+Link: https://github.com/acpica/acpica/commit/4d4547cf
+Signed-off-by: Pei Xiao <xiaopei01@kylinos.cn>
+Link: https://patch.msgid.link/tencent_4A21A2865B8B0A0D12CAEBEB84708EDDB505@qq.com
+[ rjw: Subject and changelog edits ]
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/acpi/acpica/dbconvert.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/acpi/acpica/dbconvert.c b/drivers/acpi/acpica/dbconvert.c
+index 2b84ac093698a..8dbab69320499 100644
+--- a/drivers/acpi/acpica/dbconvert.c
++++ b/drivers/acpi/acpica/dbconvert.c
+@@ -174,6 +174,8 @@ acpi_status acpi_db_convert_to_package(char *string, union acpi_object *object)
+ elements =
+ ACPI_ALLOCATE_ZEROED(DB_DEFAULT_PKG_ELEMENTS *
+ sizeof(union acpi_object));
++ if (!elements)
++ return (AE_NO_MEMORY);
+
+ this = string;
+ for (i = 0; i < (DB_DEFAULT_PKG_ELEMENTS - 1); i++) {
+--
+2.43.0
+
--- /dev/null
+From c0c6bf048a70b21942f7ec237237ebe80fdfe5ff Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 14 Apr 2024 21:50:33 +0200
+Subject: ACPICA: Fix memory leak if acpi_ps_get_next_field() fails
+
+From: Armin Wolf <W_Armin@gmx.de>
+
+[ Upstream commit e6169a8ffee8a012badd8c703716e761ce851b15 ]
+
+ACPICA commit 1280045754264841b119a5ede96cd005bc09b5a7
+
+If acpi_ps_get_next_field() fails, the previously created field list
+needs to be properly disposed before returning the status code.
+
+Link: https://github.com/acpica/acpica/commit/12800457
+Signed-off-by: Armin Wolf <W_Armin@gmx.de>
+[ rjw: Rename local variable to avoid compiler confusion ]
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/acpi/acpica/psargs.c | 39 ++++++++++++++++++++++++++++++++++++
+ 1 file changed, 39 insertions(+)
+
+diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c
+index 7debfd5ce0d86..28582adfc0aca 100644
+--- a/drivers/acpi/acpica/psargs.c
++++ b/drivers/acpi/acpica/psargs.c
+@@ -25,6 +25,8 @@ acpi_ps_get_next_package_length(struct acpi_parse_state *parser_state);
+ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state
+ *parser_state);
+
++static void acpi_ps_free_field_list(union acpi_parse_object *start);
++
+ /*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_get_next_package_length
+@@ -683,6 +685,39 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state
+ return_PTR(field);
+ }
+
++/*******************************************************************************
++ *
++ * FUNCTION: acpi_ps_free_field_list
++ *
++ * PARAMETERS: start - First Op in field list
++ *
++ * RETURN: None.
++ *
++ * DESCRIPTION: Free all Op objects inside a field list.
++ *
++ ******************************************************************************/
++
++static void acpi_ps_free_field_list(union acpi_parse_object *start)
++{
++ union acpi_parse_object *cur = start;
++ union acpi_parse_object *next;
++ union acpi_parse_object *arg;
++
++ while (cur) {
++ next = cur->common.next;
++
++ /* AML_INT_CONNECTION_OP can have a single argument */
++
++ arg = acpi_ps_get_arg(cur, 0);
++ if (arg) {
++ acpi_ps_free_op(arg);
++ }
++
++ acpi_ps_free_op(cur);
++ cur = next;
++ }
++}
++
+ /*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_get_next_arg
+@@ -751,6 +786,10 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
+ while (parser_state->aml < parser_state->pkg_end) {
+ field = acpi_ps_get_next_field(parser_state);
+ if (!field) {
++ if (arg) {
++ acpi_ps_free_field_list(arg);
++ }
++
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+--
+2.43.0
+
--- /dev/null
+From 6c76b2d767d19ba6b7644b9c63968e96feba1472 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 3 Apr 2024 20:50:11 +0200
+Subject: ACPICA: Fix memory leak if acpi_ps_get_next_namepath() fails
+
+From: Armin Wolf <W_Armin@gmx.de>
+
+[ Upstream commit 5accb265f7a1b23e52b0ec42313d1e12895552f4 ]
+
+ACPICA commit 2802af722bbde7bf1a7ac68df68e179e2555d361
+
+If acpi_ps_get_next_namepath() fails, the previously allocated
+union acpi_parse_object needs to be freed before returning the
+status code.
+
+The issue was first being reported on the Linux ACPI mailing list:
+
+Link: https://lore.kernel.org/linux-acpi/56f94776-484f-48c0-8855-dba8e6a7793b@yandex.ru/T/
+Link: https://github.com/acpica/acpica/commit/2802af72
+Signed-off-by: Armin Wolf <W_Armin@gmx.de>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/acpi/acpica/psargs.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c
+index 422c074ed2897..7debfd5ce0d86 100644
+--- a/drivers/acpi/acpica/psargs.c
++++ b/drivers/acpi/acpica/psargs.c
+@@ -820,6 +820,10 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
+ acpi_ps_get_next_namepath(walk_state, parser_state,
+ arg,
+ ACPI_NOT_METHOD_CALL);
++ if (ACPI_FAILURE(status)) {
++ acpi_ps_free_op(arg);
++ return_ACPI_STATUS(status);
++ }
+ } else {
+ /* Single complex argument, nothing returned */
+
+@@ -854,6 +858,10 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
+ acpi_ps_get_next_namepath(walk_state, parser_state,
+ arg,
+ ACPI_POSSIBLE_METHOD_CALL);
++ if (ACPI_FAILURE(status)) {
++ acpi_ps_free_op(arg);
++ return_ACPI_STATUS(status);
++ }
+
+ if (arg->common.aml_opcode == AML_INT_METHODCALL_OP) {
+
+--
+2.43.0
+
--- /dev/null
+From 8d31bfb08347557b6f35c81e0321ac81209bc1f9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 11 Aug 2024 23:33:44 +0200
+Subject: ACPICA: iasl: handle empty connection_node
+
+From: Aleksandrs Vinarskis <alex.vinarskis@gmail.com>
+
+[ Upstream commit a0a2459b79414584af6c46dd8c6f866d8f1aa421 ]
+
+ACPICA commit 6c551e2c9487067d4b085333e7fe97e965a11625
+
+Link: https://github.com/acpica/acpica/commit/6c551e2c
+Signed-off-by: Aleksandrs Vinarskis <alex.vinarskis@gmail.com>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/acpi/acpica/exprep.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/acpi/acpica/exprep.c b/drivers/acpi/acpica/exprep.c
+index 08196fa17080e..82b1fa2d201fe 100644
+--- a/drivers/acpi/acpica/exprep.c
++++ b/drivers/acpi/acpica/exprep.c
+@@ -437,6 +437,9 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
+
+ if (info->connection_node) {
+ second_desc = info->connection_node->object;
++ if (second_desc == NULL) {
++ break;
++ }
+ if (!(second_desc->common.flags & AOPOBJ_DATA_VALID)) {
+ status =
+ acpi_ds_get_buffer_arguments(second_desc);
+--
+2.43.0
+
--- /dev/null
+From 6e53134a0222a3ea9a9f849421ac8bf6c2f65abe Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 8 Aug 2024 11:14:42 +0200
+Subject: ALSA: asihpi: Fix potential OOB array access
+
+From: Takashi Iwai <tiwai@suse.de>
+
+[ Upstream commit 7b986c7430a6bb68d523dac7bfc74cbd5b44ef96 ]
+
+ASIHPI driver stores some values in the static array upon a response
+from the driver, and its index depends on the firmware. We shouldn't
+trust it blindly.
+
+This patch adds a sanity check of the array index to fit in the array
+size.
+
+Link: https://patch.msgid.link/20240808091454.30846-1-tiwai@suse.de
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/pci/asihpi/hpimsgx.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/sound/pci/asihpi/hpimsgx.c b/sound/pci/asihpi/hpimsgx.c
+index d0caef2994818..b68e6bfbbfbab 100644
+--- a/sound/pci/asihpi/hpimsgx.c
++++ b/sound/pci/asihpi/hpimsgx.c
+@@ -708,7 +708,7 @@ static u16 HPIMSGX__init(struct hpi_message *phm,
+ phr->error = HPI_ERROR_PROCESSING_MESSAGE;
+ return phr->error;
+ }
+- if (hr.error == 0) {
++ if (hr.error == 0 && hr.u.s.adapter_index < HPI_MAX_ADAPTERS) {
+ /* the adapter was created successfully
+ save the mapping for future use */
+ hpi_entry_points[hr.u.s.adapter_index] = entry_point_func;
+--
+2.43.0
+
--- /dev/null
+From 4331b02c39d70d8410d61ee148e9343fe8017cc9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 29 Jul 2024 18:06:58 +0200
+Subject: ALSA: control: Take power_ref lock primarily
+
+From: Takashi Iwai <tiwai@suse.de>
+
+[ Upstream commit fcc62b19104a67b9a2941513771e09389b75bd95 ]
+
+The code path for kcontrol accesses have often nested locks of both
+card's controls_rwsem and power_ref, and applies in that order.
+However, what could take much longer is the latter, power_ref; it
+waits for the power state of the device, and it pretty much depends on
+the user's action.
+
+This patch swaps the locking order of those locks to a more natural
+way, namely, power_ref -> controls_rwsem, in order to shorten the time
+of possible nested locks. For consistency, power_ref is taken always
+in the top-level caller side (that is, *_user() functions and the
+ioctl handler itself).
+
+Link: https://patch.msgid.link/20240729160659.4516-1-tiwai@suse.de
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/core/control.c | 54 ++++++++++++++++++++++++++++----------------
+ 1 file changed, 34 insertions(+), 20 deletions(-)
+
+diff --git a/sound/core/control.c b/sound/core/control.c
+index 1dd2337e29300..2151f19b432fd 100644
+--- a/sound/core/control.c
++++ b/sound/core/control.c
+@@ -1164,9 +1164,7 @@ static int __snd_ctl_elem_info(struct snd_card *card,
+ #ifdef CONFIG_SND_DEBUG
+ info->access = 0;
+ #endif
+- result = snd_power_ref_and_wait(card);
+- if (!result)
+- result = kctl->info(kctl, info);
++ result = kctl->info(kctl, info);
+ snd_power_unref(card);
+ if (result >= 0) {
+ snd_BUG_ON(info->access);
+@@ -1205,12 +1203,17 @@ static int snd_ctl_elem_info(struct snd_ctl_file *ctl,
+ static int snd_ctl_elem_info_user(struct snd_ctl_file *ctl,
+ struct snd_ctl_elem_info __user *_info)
+ {
++ struct snd_card *card = ctl->card;
+ struct snd_ctl_elem_info info;
+ int result;
+
+ if (copy_from_user(&info, _info, sizeof(info)))
+ return -EFAULT;
++ result = snd_power_ref_and_wait(card);
++ if (result)
++ return result;
+ result = snd_ctl_elem_info(ctl, &info);
++ snd_power_unref(card);
+ if (result < 0)
+ return result;
+ /* drop internal access flags */
+@@ -1254,10 +1257,7 @@ static int snd_ctl_elem_read(struct snd_card *card,
+
+ if (!snd_ctl_skip_validation(&info))
+ fill_remaining_elem_value(control, &info, pattern);
+- ret = snd_power_ref_and_wait(card);
+- if (!ret)
+- ret = kctl->get(kctl, control);
+- snd_power_unref(card);
++ ret = kctl->get(kctl, control);
+ if (ret < 0)
+ return ret;
+ if (!snd_ctl_skip_validation(&info) &&
+@@ -1282,7 +1282,11 @@ static int snd_ctl_elem_read_user(struct snd_card *card,
+ if (IS_ERR(control))
+ return PTR_ERR(no_free_ptr(control));
+
++ result = snd_power_ref_and_wait(card);
++ if (result)
++ return result;
+ result = snd_ctl_elem_read(card, control);
++ snd_power_unref(card);
+ if (result < 0)
+ return result;
+
+@@ -1297,7 +1301,7 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
+ struct snd_kcontrol *kctl;
+ struct snd_kcontrol_volatile *vd;
+ unsigned int index_offset;
+- int result;
++ int result = 0;
+
+ down_write(&card->controls_rwsem);
+ kctl = snd_ctl_find_id_locked(card, &control->id);
+@@ -1315,9 +1319,8 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
+ }
+
+ snd_ctl_build_ioff(&control->id, kctl, index_offset);
+- result = snd_power_ref_and_wait(card);
+ /* validate input values */
+- if (IS_ENABLED(CONFIG_SND_CTL_INPUT_VALIDATION) && !result) {
++ if (IS_ENABLED(CONFIG_SND_CTL_INPUT_VALIDATION)) {
+ struct snd_ctl_elem_info info;
+
+ memset(&info, 0, sizeof(info));
+@@ -1329,7 +1332,6 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
+ }
+ if (!result)
+ result = kctl->put(kctl, control);
+- snd_power_unref(card);
+ if (result < 0) {
+ up_write(&card->controls_rwsem);
+ return result;
+@@ -1358,7 +1360,11 @@ static int snd_ctl_elem_write_user(struct snd_ctl_file *file,
+ return PTR_ERR(no_free_ptr(control));
+
+ card = file->card;
++ result = snd_power_ref_and_wait(card);
++ if (result < 0)
++ return result;
+ result = snd_ctl_elem_write(card, file, control);
++ snd_power_unref(card);
+ if (result < 0)
+ return result;
+
+@@ -1827,7 +1833,7 @@ static int call_tlv_handler(struct snd_ctl_file *file, int op_flag,
+ {SNDRV_CTL_TLV_OP_CMD, SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND},
+ };
+ struct snd_kcontrol_volatile *vd = &kctl->vd[snd_ctl_get_ioff(kctl, id)];
+- int i, ret;
++ int i;
+
+ /* Check support of the request for this element. */
+ for (i = 0; i < ARRAY_SIZE(pairs); ++i) {
+@@ -1845,11 +1851,7 @@ static int call_tlv_handler(struct snd_ctl_file *file, int op_flag,
+ vd->owner != NULL && vd->owner != file)
+ return -EPERM;
+
+- ret = snd_power_ref_and_wait(file->card);
+- if (!ret)
+- ret = kctl->tlv.c(kctl, op_flag, size, buf);
+- snd_power_unref(file->card);
+- return ret;
++ return kctl->tlv.c(kctl, op_flag, size, buf);
+ }
+
+ static int read_tlv_buf(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id,
+@@ -1962,16 +1964,28 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
+ case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
+ return snd_ctl_subscribe_events(ctl, ip);
+ case SNDRV_CTL_IOCTL_TLV_READ:
+- scoped_guard(rwsem_read, &ctl->card->controls_rwsem)
++ err = snd_power_ref_and_wait(card);
++ if (err < 0)
++ return err;
++ scoped_guard(rwsem_read, &card->controls_rwsem)
+ err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_READ);
++ snd_power_unref(card);
+ return err;
+ case SNDRV_CTL_IOCTL_TLV_WRITE:
+- scoped_guard(rwsem_write, &ctl->card->controls_rwsem)
++ err = snd_power_ref_and_wait(card);
++ if (err < 0)
++ return err;
++ scoped_guard(rwsem_write, &card->controls_rwsem)
+ err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_WRITE);
++ snd_power_unref(card);
+ return err;
+ case SNDRV_CTL_IOCTL_TLV_COMMAND:
+- scoped_guard(rwsem_write, &ctl->card->controls_rwsem)
++ err = snd_power_ref_and_wait(card);
++ if (err < 0)
++ return err;
++ scoped_guard(rwsem_write, &card->controls_rwsem)
+ err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_CMD);
++ snd_power_unref(card);
+ return err;
+ case SNDRV_CTL_IOCTL_POWER:
+ return -ENOPROTOOPT;
+--
+2.43.0
+
--- /dev/null
+From 59c6dfe6c79473990fab82e1f9fd34e57548d407 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 8 Aug 2024 11:15:12 +0200
+Subject: ALSA: hdsp: Break infinite MIDI input flush loop
+
+From: Takashi Iwai <tiwai@suse.de>
+
+[ Upstream commit c01f3815453e2d5f699ccd8c8c1f93a5b8669e59 ]
+
+The current MIDI input flush on HDSP and HDSPM drivers relies on the
+hardware reporting the right value. If the hardware doesn't give the
+proper value but returns -1, it may be stuck at an infinite loop.
+
+Add a counter and break if the loop is unexpectedly too long.
+
+Link: https://patch.msgid.link/20240808091513.31380-1-tiwai@suse.de
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/pci/rme9652/hdsp.c | 6 ++++--
+ sound/pci/rme9652/hdspm.c | 6 ++++--
+ 2 files changed, 8 insertions(+), 4 deletions(-)
+
+diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
+index e7d1b43471a29..713ca262a0e97 100644
+--- a/sound/pci/rme9652/hdsp.c
++++ b/sound/pci/rme9652/hdsp.c
+@@ -1298,8 +1298,10 @@ static int snd_hdsp_midi_output_possible (struct hdsp *hdsp, int id)
+
+ static void snd_hdsp_flush_midi_input (struct hdsp *hdsp, int id)
+ {
+- while (snd_hdsp_midi_input_available (hdsp, id))
+- snd_hdsp_midi_read_byte (hdsp, id);
++ int count = 256;
++
++ while (snd_hdsp_midi_input_available(hdsp, id) && --count)
++ snd_hdsp_midi_read_byte(hdsp, id);
+ }
+
+ static int snd_hdsp_midi_output_write (struct hdsp_midi *hmidi)
+diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
+index 267c7848974ae..74215f57f4fc9 100644
+--- a/sound/pci/rme9652/hdspm.c
++++ b/sound/pci/rme9652/hdspm.c
+@@ -1838,8 +1838,10 @@ static inline int snd_hdspm_midi_output_possible (struct hdspm *hdspm, int id)
+
+ static void snd_hdspm_flush_midi_input(struct hdspm *hdspm, int id)
+ {
+- while (snd_hdspm_midi_input_available (hdspm, id))
+- snd_hdspm_midi_read_byte (hdspm, id);
++ int count = 256;
++
++ while (snd_hdspm_midi_input_available(hdspm, id) && --count)
++ snd_hdspm_midi_read_byte(hdspm, id);
+ }
+
+ static int snd_hdspm_midi_output_write (struct hdspm_midi *hmidi)
+--
+2.43.0
+
--- /dev/null
+From 183c49ca6224fed8501ca0589452922d15c7520b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 6 Aug 2024 14:46:50 +0200
+Subject: ALSA: usb-audio: Add input value sanity checks for standard types
+
+From: Takashi Iwai <tiwai@suse.de>
+
+[ Upstream commit 901e85677ec0bb9a69fb9eab1feafe0c4eb7d07e ]
+
+For an invalid input value that is out of the given range, currently
+USB-audio driver corrects the value silently and accepts without
+errors. This is no wrong behavior, per se, but the recent kselftest
+rather wants to have an error in such a case, hence a different
+behavior is expected now.
+
+This patch adds a sanity check at each control put for the standard
+mixer types and returns an error if an invalid value is given.
+
+Note that this covers only the standard mixer types. The mixer quirks
+that have own control callbacks would need different coverage.
+
+Link: https://patch.msgid.link/20240806124651.28203-1-tiwai@suse.de
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/usb/mixer.c | 35 +++++++++++++++++++++++++++--------
+ sound/usb/mixer.h | 1 +
+ 2 files changed, 28 insertions(+), 8 deletions(-)
+
+diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
+index 8cc2d4937f340..197fd07e69edd 100644
+--- a/sound/usb/mixer.c
++++ b/sound/usb/mixer.c
+@@ -1377,6 +1377,19 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
+
+ #define get_min_max(cval, def) get_min_max_with_quirks(cval, def, NULL)
+
++/* get the max value advertised via control API */
++static int get_max_exposed(struct usb_mixer_elem_info *cval)
++{
++ if (!cval->max_exposed) {
++ if (cval->res)
++ cval->max_exposed =
++ DIV_ROUND_UP(cval->max - cval->min, cval->res);
++ else
++ cval->max_exposed = cval->max - cval->min;
++ }
++ return cval->max_exposed;
++}
++
+ /* get a feature/mixer unit info */
+ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+@@ -1389,11 +1402,8 @@ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol,
+ else
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = cval->channels;
+- if (cval->val_type == USB_MIXER_BOOLEAN ||
+- cval->val_type == USB_MIXER_INV_BOOLEAN) {
+- uinfo->value.integer.min = 0;
+- uinfo->value.integer.max = 1;
+- } else {
++ if (cval->val_type != USB_MIXER_BOOLEAN &&
++ cval->val_type != USB_MIXER_INV_BOOLEAN) {
+ if (!cval->initialized) {
+ get_min_max_with_quirks(cval, 0, kcontrol);
+ if (cval->initialized && cval->dBmin >= cval->dBmax) {
+@@ -1405,10 +1415,10 @@ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol,
+ &kcontrol->id);
+ }
+ }
+- uinfo->value.integer.min = 0;
+- uinfo->value.integer.max =
+- DIV_ROUND_UP(cval->max - cval->min, cval->res);
+ }
++
++ uinfo->value.integer.min = 0;
++ uinfo->value.integer.max = get_max_exposed(cval);
+ return 0;
+ }
+
+@@ -1449,6 +1459,7 @@ static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+ {
+ struct usb_mixer_elem_info *cval = kcontrol->private_data;
++ int max_val = get_max_exposed(cval);
+ int c, cnt, val, oval, err;
+ int changed = 0;
+
+@@ -1461,6 +1472,8 @@ static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol,
+ if (err < 0)
+ return filter_error(cval, err);
+ val = ucontrol->value.integer.value[cnt];
++ if (val < 0 || val > max_val)
++ return -EINVAL;
+ val = get_abs_value(cval, val);
+ if (oval != val) {
+ snd_usb_set_cur_mix_value(cval, c + 1, cnt, val);
+@@ -1474,6 +1487,8 @@ static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol,
+ if (err < 0)
+ return filter_error(cval, err);
+ val = ucontrol->value.integer.value[0];
++ if (val < 0 || val > max_val)
++ return -EINVAL;
+ val = get_abs_value(cval, val);
+ if (val != oval) {
+ snd_usb_set_cur_mix_value(cval, 0, 0, val);
+@@ -2337,6 +2352,8 @@ static int mixer_ctl_procunit_put(struct snd_kcontrol *kcontrol,
+ if (err < 0)
+ return filter_error(cval, err);
+ val = ucontrol->value.integer.value[0];
++ if (val < 0 || val > get_max_exposed(cval))
++ return -EINVAL;
+ val = get_abs_value(cval, val);
+ if (val != oval) {
+ set_cur_ctl_value(cval, cval->control << 8, val);
+@@ -2699,6 +2716,8 @@ static int mixer_ctl_selector_put(struct snd_kcontrol *kcontrol,
+ if (err < 0)
+ return filter_error(cval, err);
+ val = ucontrol->value.enumerated.item[0];
++ if (val < 0 || val >= cval->max) /* here cval->max = # elements */
++ return -EINVAL;
+ val = get_abs_value(cval, val);
+ if (val != oval) {
+ set_cur_ctl_value(cval, cval->control << 8, val);
+diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h
+index d43895c1ae5c6..167fbfcf01ace 100644
+--- a/sound/usb/mixer.h
++++ b/sound/usb/mixer.h
+@@ -88,6 +88,7 @@ struct usb_mixer_elem_info {
+ int channels;
+ int val_type;
+ int min, max, res;
++ int max_exposed; /* control API exposes the value in 0..max_exposed */
+ int dBmin, dBmax;
+ int cached;
+ int cache_val[MAX_CHANNELS];
+--
+2.43.0
+
--- /dev/null
+From bfdd49be2ca1e406f156915b8f69438a78b96362 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 12 Sep 2024 15:26:28 +0000
+Subject: ALSA: usb-audio: Add logitech Audio profile quirk
+
+From: Joshua Pius <joshuapius@chromium.org>
+
+[ Upstream commit a51c925c11d7b855167e64b63eb4378e5adfc11d ]
+
+Specify shortnames for the following Logitech Devices: Rally bar, Rally
+bar mini, Tap, MeetUp and Huddle.
+
+Signed-off-by: Joshua Pius <joshuapius@chromium.org>
+Link: https://patch.msgid.link/20240912152635.1859737-1-joshuapius@google.com
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/usb/card.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/sound/usb/card.c b/sound/usb/card.c
+index 778de9244f1e7..9c411b82a218d 100644
+--- a/sound/usb/card.c
++++ b/sound/usb/card.c
+@@ -384,6 +384,12 @@ static const struct usb_audio_device_name usb_audio_names[] = {
+ /* Creative/Toshiba Multimedia Center SB-0500 */
+ DEVICE_NAME(0x041e, 0x3048, "Toshiba", "SB-0500"),
+
++ /* Logitech Audio Devices */
++ DEVICE_NAME(0x046d, 0x0867, "Logitech, Inc.", "Logi-MeetUp"),
++ DEVICE_NAME(0x046d, 0x0874, "Logitech, Inc.", "Logi-Tap-Audio"),
++ DEVICE_NAME(0x046d, 0x087c, "Logitech, Inc.", "Logi-Huddle"),
++ DEVICE_NAME(0x046d, 0x0898, "Logitech, Inc.", "Logi-RB-Audio"),
++ DEVICE_NAME(0x046d, 0x08d2, "Logitech, Inc.", "Logi-RBM-Audio"),
+ DEVICE_NAME(0x046d, 0x0990, "Logitech, Inc.", "QuickCam Pro 9000"),
+
+ DEVICE_NAME(0x05e1, 0x0408, "Syntek", "STK1160"),
+--
+2.43.0
+
--- /dev/null
+From de5b52dd026d18af99bc8be132e464dba5c4a716 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Sep 2024 19:52:30 +0900
+Subject: ALSA: usb-audio: Add mixer quirk for RME Digiface USB
+
+From: Asahi Lina <lina@asahilina.net>
+
+[ Upstream commit 611a96f6acf2e74fe28cb90908a9c183862348ce ]
+
+Implement sync, output format, and input status mixer controls, to allow
+the interface to be used as a straight ADAT/SPDIF (+ Headphones) I/O
+interface.
+
+This does not implement the matrix mixer, output gain controls, or input
+level meter feedback. The full mixer interface is only really usable
+using a dedicated userspace control app (there are too many mixer nodes
+for alsamixer to be usable), so for now we leave it up to userspace to
+directly control these features using raw USB control messages. This is
+similar to how it's done with some FireWire interfaces (ffado-mixer).
+
+Signed-off-by: Asahi Lina <lina@asahilina.net>
+Link: https://patch.msgid.link/20240903-rme-digiface-v2-2-71b06c912e97@asahilina.net
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/usb/mixer_quirks.c | 413 +++++++++++++++++++++++++++++++++++++++
+ sound/usb/quirks-table.h | 1 +
+ 2 files changed, 414 insertions(+)
+
+diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
+index 1d8bf1ecfed44..3727dbd123597 100644
+--- a/sound/usb/mixer_quirks.c
++++ b/sound/usb/mixer_quirks.c
+@@ -14,6 +14,7 @@
+ * Przemek Rudy (prudy1@o2.pl)
+ */
+
++#include <linux/bitfield.h>
+ #include <linux/hid.h>
+ #include <linux/init.h>
+ #include <linux/math64.h>
+@@ -2926,6 +2927,415 @@ static int snd_bbfpro_controls_create(struct usb_mixer_interface *mixer)
+ return 0;
+ }
+
++/*
++ * RME Digiface USB
++ */
++
++#define RME_DIGIFACE_READ_STATUS 17
++#define RME_DIGIFACE_STATUS_REG0L 0
++#define RME_DIGIFACE_STATUS_REG0H 1
++#define RME_DIGIFACE_STATUS_REG1L 2
++#define RME_DIGIFACE_STATUS_REG1H 3
++#define RME_DIGIFACE_STATUS_REG2L 4
++#define RME_DIGIFACE_STATUS_REG2H 5
++#define RME_DIGIFACE_STATUS_REG3L 6
++#define RME_DIGIFACE_STATUS_REG3H 7
++
++#define RME_DIGIFACE_CTL_REG1 16
++#define RME_DIGIFACE_CTL_REG2 18
++
++/* Reg is overloaded, 0-7 for status halfwords or 16 or 18 for control registers */
++#define RME_DIGIFACE_REGISTER(reg, mask) (((reg) << 16) | (mask))
++#define RME_DIGIFACE_INVERT BIT(31)
++
++/* Nonconst helpers */
++#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1))
++#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask))
++
++static int snd_rme_digiface_write_reg(struct snd_kcontrol *kcontrol, int item, u16 mask, u16 val)
++{
++ struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol);
++ struct snd_usb_audio *chip = list->mixer->chip;
++ struct usb_device *dev = chip->dev;
++ int err;
++
++ err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
++ item,
++ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
++ val, mask, NULL, 0);
++ if (err < 0)
++ dev_err(&dev->dev,
++ "unable to issue control set request %d (ret = %d)",
++ item, err);
++ return err;
++}
++
++static int snd_rme_digiface_read_status(struct snd_kcontrol *kcontrol, u32 status[4])
++{
++ struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol);
++ struct snd_usb_audio *chip = list->mixer->chip;
++ struct usb_device *dev = chip->dev;
++ __le32 buf[4];
++ int err;
++
++ err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0),
++ RME_DIGIFACE_READ_STATUS,
++ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
++ 0, 0,
++ buf, sizeof(buf));
++ if (err < 0) {
++ dev_err(&dev->dev,
++ "unable to issue status read request (ret = %d)",
++ err);
++ } else {
++ for (int i = 0; i < ARRAY_SIZE(buf); i++)
++ status[i] = le32_to_cpu(buf[i]);
++ }
++ return err;
++}
++
++static int snd_rme_digiface_get_status_val(struct snd_kcontrol *kcontrol)
++{
++ int err;
++ u32 status[4];
++ bool invert = kcontrol->private_value & RME_DIGIFACE_INVERT;
++ u8 reg = (kcontrol->private_value >> 16) & 0xff;
++ u16 mask = kcontrol->private_value & 0xffff;
++ u16 val;
++
++ err = snd_rme_digiface_read_status(kcontrol, status);
++ if (err < 0)
++ return err;
++
++ switch (reg) {
++ /* Status register halfwords */
++ case RME_DIGIFACE_STATUS_REG0L ... RME_DIGIFACE_STATUS_REG3H:
++ break;
++ case RME_DIGIFACE_CTL_REG1: /* Control register 1, present in halfword 3L */
++ reg = RME_DIGIFACE_STATUS_REG3L;
++ break;
++ case RME_DIGIFACE_CTL_REG2: /* Control register 2, present in halfword 3H */
++ reg = RME_DIGIFACE_STATUS_REG3H;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ if (reg & 1)
++ val = status[reg >> 1] >> 16;
++ else
++ val = status[reg >> 1] & 0xffff;
++
++ if (invert)
++ val ^= mask;
++
++ return field_get(mask, val);
++}
++
++static int snd_rme_digiface_rate_get(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ int freq = snd_rme_digiface_get_status_val(kcontrol);
++
++ if (freq < 0)
++ return freq;
++ if (freq >= ARRAY_SIZE(snd_rme_rate_table))
++ return -EIO;
++
++ ucontrol->value.integer.value[0] = snd_rme_rate_table[freq];
++ return 0;
++}
++
++static int snd_rme_digiface_enum_get(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ int val = snd_rme_digiface_get_status_val(kcontrol);
++
++ if (val < 0)
++ return val;
++
++ ucontrol->value.enumerated.item[0] = val;
++ return 0;
++}
++
++static int snd_rme_digiface_enum_put(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ bool invert = kcontrol->private_value & RME_DIGIFACE_INVERT;
++ u8 reg = (kcontrol->private_value >> 16) & 0xff;
++ u16 mask = kcontrol->private_value & 0xffff;
++ u16 val = field_prep(mask, ucontrol->value.enumerated.item[0]);
++
++ if (invert)
++ val ^= mask;
++
++ return snd_rme_digiface_write_reg(kcontrol, reg, mask, val);
++}
++
++static int snd_rme_digiface_current_sync_get(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ int ret = snd_rme_digiface_enum_get(kcontrol, ucontrol);
++
++ /* 7 means internal for current sync */
++ if (ucontrol->value.enumerated.item[0] == 7)
++ ucontrol->value.enumerated.item[0] = 0;
++
++ return ret;
++}
++
++static int snd_rme_digiface_sync_state_get(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ u32 status[4];
++ int err;
++ bool valid, sync;
++
++ err = snd_rme_digiface_read_status(kcontrol, status);
++ if (err < 0)
++ return err;
++
++ valid = status[0] & BIT(kcontrol->private_value);
++ sync = status[0] & BIT(5 + kcontrol->private_value);
++
++ if (!valid)
++ ucontrol->value.enumerated.item[0] = SND_RME_CLOCK_NOLOCK;
++ else if (!sync)
++ ucontrol->value.enumerated.item[0] = SND_RME_CLOCK_LOCK;
++ else
++ ucontrol->value.enumerated.item[0] = SND_RME_CLOCK_SYNC;
++ return 0;
++}
++
++
++static int snd_rme_digiface_format_info(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_info *uinfo)
++{
++ static const char *const format[] = {
++ "ADAT", "S/PDIF"
++ };
++
++ return snd_ctl_enum_info(uinfo, 1,
++ ARRAY_SIZE(format), format);
++}
++
++
++static int snd_rme_digiface_sync_source_info(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_info *uinfo)
++{
++ static const char *const sync_sources[] = {
++ "Internal", "Input 1", "Input 2", "Input 3", "Input 4"
++ };
++
++ return snd_ctl_enum_info(uinfo, 1,
++ ARRAY_SIZE(sync_sources), sync_sources);
++}
++
++static int snd_rme_digiface_rate_info(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_info *uinfo)
++{
++ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
++ uinfo->count = 1;
++ uinfo->value.integer.min = 0;
++ uinfo->value.integer.max = 200000;
++ uinfo->value.integer.step = 0;
++ return 0;
++}
++
++static const struct snd_kcontrol_new snd_rme_digiface_controls[] = {
++ {
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .name = "Input 1 Sync",
++ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
++ .info = snd_rme_sync_state_info,
++ .get = snd_rme_digiface_sync_state_get,
++ .private_value = 0,
++ },
++ {
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .name = "Input 1 Format",
++ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
++ .info = snd_rme_digiface_format_info,
++ .get = snd_rme_digiface_enum_get,
++ .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG0H, BIT(0)) |
++ RME_DIGIFACE_INVERT,
++ },
++ {
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .name = "Input 1 Rate",
++ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
++ .info = snd_rme_digiface_rate_info,
++ .get = snd_rme_digiface_rate_get,
++ .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG1L, GENMASK(3, 0)),
++ },
++ {
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .name = "Input 2 Sync",
++ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
++ .info = snd_rme_sync_state_info,
++ .get = snd_rme_digiface_sync_state_get,
++ .private_value = 1,
++ },
++ {
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .name = "Input 2 Format",
++ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
++ .info = snd_rme_digiface_format_info,
++ .get = snd_rme_digiface_enum_get,
++ .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG0L, BIT(13)) |
++ RME_DIGIFACE_INVERT,
++ },
++ {
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .name = "Input 2 Rate",
++ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
++ .info = snd_rme_digiface_rate_info,
++ .get = snd_rme_digiface_rate_get,
++ .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG1L, GENMASK(7, 4)),
++ },
++ {
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .name = "Input 3 Sync",
++ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
++ .info = snd_rme_sync_state_info,
++ .get = snd_rme_digiface_sync_state_get,
++ .private_value = 2,
++ },
++ {
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .name = "Input 3 Format",
++ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
++ .info = snd_rme_digiface_format_info,
++ .get = snd_rme_digiface_enum_get,
++ .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG0L, BIT(14)) |
++ RME_DIGIFACE_INVERT,
++ },
++ {
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .name = "Input 3 Rate",
++ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
++ .info = snd_rme_digiface_rate_info,
++ .get = snd_rme_digiface_rate_get,
++ .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG1L, GENMASK(11, 8)),
++ },
++ {
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .name = "Input 4 Sync",
++ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
++ .info = snd_rme_sync_state_info,
++ .get = snd_rme_digiface_sync_state_get,
++ .private_value = 3,
++ },
++ {
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .name = "Input 4 Format",
++ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
++ .info = snd_rme_digiface_format_info,
++ .get = snd_rme_digiface_enum_get,
++ .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG0L, GENMASK(15, 12)) |
++ RME_DIGIFACE_INVERT,
++ },
++ {
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .name = "Input 4 Rate",
++ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
++ .info = snd_rme_digiface_rate_info,
++ .get = snd_rme_digiface_rate_get,
++ .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG1L, GENMASK(3, 0)),
++ },
++ {
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .name = "Output 1 Format",
++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
++ .info = snd_rme_digiface_format_info,
++ .get = snd_rme_digiface_enum_get,
++ .put = snd_rme_digiface_enum_put,
++ .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_CTL_REG2, BIT(0)),
++ },
++ {
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .name = "Output 2 Format",
++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
++ .info = snd_rme_digiface_format_info,
++ .get = snd_rme_digiface_enum_get,
++ .put = snd_rme_digiface_enum_put,
++ .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_CTL_REG2, BIT(1)),
++ },
++ {
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .name = "Output 3 Format",
++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
++ .info = snd_rme_digiface_format_info,
++ .get = snd_rme_digiface_enum_get,
++ .put = snd_rme_digiface_enum_put,
++ .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_CTL_REG2, BIT(3)),
++ },
++ {
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .name = "Output 4 Format",
++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
++ .info = snd_rme_digiface_format_info,
++ .get = snd_rme_digiface_enum_get,
++ .put = snd_rme_digiface_enum_put,
++ .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_CTL_REG2, BIT(4)),
++ },
++ {
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .name = "Sync Source",
++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
++ .info = snd_rme_digiface_sync_source_info,
++ .get = snd_rme_digiface_enum_get,
++ .put = snd_rme_digiface_enum_put,
++ .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_CTL_REG1, GENMASK(2, 0)),
++ },
++ {
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .name = "Current Sync Source",
++ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
++ .info = snd_rme_digiface_sync_source_info,
++ .get = snd_rme_digiface_current_sync_get,
++ .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG0L, GENMASK(12, 10)),
++ },
++ {
++ /*
++ * This is writeable, but it is only set by the PCM rate.
++ * Mixer apps currently need to drive the mixer using raw USB requests,
++ * so they can also change this that way to configure the rate for
++ * stand-alone operation when the PCM is closed.
++ */
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .name = "System Rate",
++ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
++ .info = snd_rme_rate_info,
++ .get = snd_rme_digiface_rate_get,
++ .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_CTL_REG1, GENMASK(6, 3)),
++ },
++ {
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .name = "Current Rate",
++ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
++ .info = snd_rme_rate_info,
++ .get = snd_rme_digiface_rate_get,
++ .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG1H, GENMASK(7, 4)),
++ }
++};
++
++static int snd_rme_digiface_controls_create(struct usb_mixer_interface *mixer)
++{
++ int err, i;
++
++ for (i = 0; i < ARRAY_SIZE(snd_rme_digiface_controls); ++i) {
++ err = add_single_ctl_with_resume(mixer, 0,
++ NULL,
++ &snd_rme_digiface_controls[i],
++ NULL);
++ if (err < 0)
++ return err;
++ }
++
++ return 0;
++}
++
+ /*
+ * Pioneer DJ DJM Mixers
+ *
+@@ -3484,6 +3894,9 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
+ case USB_ID(0x2a39, 0x3fb0): /* RME Babyface Pro FS */
+ err = snd_bbfpro_controls_create(mixer);
+ break;
++ case USB_ID(0x2a39, 0x3f8c): /* RME Digiface USB */
++ err = snd_rme_digiface_controls_create(mixer);
++ break;
+ case USB_ID(0x2b73, 0x0017): /* Pioneer DJ DJM-250MK2 */
+ err = snd_djm_controls_create(mixer, SND_DJM_250MK2_IDX);
+ break;
+diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
+index 631b9ab80f6cd..24c981c9b2405 100644
+--- a/sound/usb/quirks-table.h
++++ b/sound/usb/quirks-table.h
+@@ -3620,6 +3620,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ * Three modes depending on sample rate band,
+ * with different channel counts for in/out
+ */
++ { QUIRK_DATA_STANDARD_MIXER(0) },
+ {
+ QUIRK_DATA_AUDIOFORMAT(0) {
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+--
+2.43.0
+
--- /dev/null
+From 0143f91d92e77cf7132c159380e7ff756b555bf0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Sep 2024 19:52:29 +0900
+Subject: ALSA: usb-audio: Add quirk for RME Digiface USB
+
+From: Cyan Nyan <cyan.vtb@gmail.com>
+
+[ Upstream commit c032044e9672408c534d64a6df2b1ba14449e948 ]
+
+Add trivial support for audio streaming on the RME Digiface USB. Binds
+only to the first interface to allow userspace to directly drive the
+complex I/O and matrix mixer controls.
+
+Signed-off-by: Cyan Nyan <cyan.vtb@gmail.com>
+[Lina: Added 2x/4x sample rate support & boot/format quirks]
+Co-developed-by: Asahi Lina <lina@asahilina.net>
+Signed-off-by: Asahi Lina <lina@asahilina.net>
+Link: https://patch.msgid.link/20240903-rme-digiface-v2-1-71b06c912e97@asahilina.net
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/usb/quirks-table.h | 171 ++++++++++++++++++++++++++++++++++++++-
+ sound/usb/quirks.c | 58 +++++++++++++
+ 2 files changed, 228 insertions(+), 1 deletion(-)
+
+diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
+index 8d22de8bc2a96..631b9ab80f6cd 100644
+--- a/sound/usb/quirks-table.h
++++ b/sound/usb/quirks-table.h
+@@ -3604,6 +3604,175 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ }
+ },
+-
++{
++ /* Only claim interface 0 */
++ .match_flags = USB_DEVICE_ID_MATCH_VENDOR |
++ USB_DEVICE_ID_MATCH_PRODUCT |
++ USB_DEVICE_ID_MATCH_INT_CLASS |
++ USB_DEVICE_ID_MATCH_INT_NUMBER,
++ .idVendor = 0x2a39,
++ .idProduct = 0x3f8c,
++ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
++ .bInterfaceNumber = 0,
++ QUIRK_DRIVER_INFO {
++ QUIRK_DATA_COMPOSITE {
++ /*
++ * Three modes depending on sample rate band,
++ * with different channel counts for in/out
++ */
++ {
++ QUIRK_DATA_AUDIOFORMAT(0) {
++ .formats = SNDRV_PCM_FMTBIT_S32_LE,
++ .channels = 34, // outputs
++ .fmt_bits = 24,
++ .iface = 0,
++ .altsetting = 1,
++ .altset_idx = 1,
++ .endpoint = 0x02,
++ .ep_idx = 1,
++ .ep_attr = USB_ENDPOINT_XFER_ISOC |
++ USB_ENDPOINT_SYNC_ASYNC,
++ .rates = SNDRV_PCM_RATE_32000 |
++ SNDRV_PCM_RATE_44100 |
++ SNDRV_PCM_RATE_48000,
++ .rate_min = 32000,
++ .rate_max = 48000,
++ .nr_rates = 3,
++ .rate_table = (unsigned int[]) {
++ 32000, 44100, 48000,
++ },
++ .sync_ep = 0x81,
++ .sync_iface = 0,
++ .sync_altsetting = 1,
++ .sync_ep_idx = 0,
++ .implicit_fb = 1,
++ },
++ },
++ {
++ QUIRK_DATA_AUDIOFORMAT(0) {
++ .formats = SNDRV_PCM_FMTBIT_S32_LE,
++ .channels = 18, // outputs
++ .fmt_bits = 24,
++ .iface = 0,
++ .altsetting = 1,
++ .altset_idx = 1,
++ .endpoint = 0x02,
++ .ep_idx = 1,
++ .ep_attr = USB_ENDPOINT_XFER_ISOC |
++ USB_ENDPOINT_SYNC_ASYNC,
++ .rates = SNDRV_PCM_RATE_64000 |
++ SNDRV_PCM_RATE_88200 |
++ SNDRV_PCM_RATE_96000,
++ .rate_min = 64000,
++ .rate_max = 96000,
++ .nr_rates = 3,
++ .rate_table = (unsigned int[]) {
++ 64000, 88200, 96000,
++ },
++ .sync_ep = 0x81,
++ .sync_iface = 0,
++ .sync_altsetting = 1,
++ .sync_ep_idx = 0,
++ .implicit_fb = 1,
++ },
++ },
++ {
++ QUIRK_DATA_AUDIOFORMAT(0) {
++ .formats = SNDRV_PCM_FMTBIT_S32_LE,
++ .channels = 10, // outputs
++ .fmt_bits = 24,
++ .iface = 0,
++ .altsetting = 1,
++ .altset_idx = 1,
++ .endpoint = 0x02,
++ .ep_idx = 1,
++ .ep_attr = USB_ENDPOINT_XFER_ISOC |
++ USB_ENDPOINT_SYNC_ASYNC,
++ .rates = SNDRV_PCM_RATE_KNOT |
++ SNDRV_PCM_RATE_176400 |
++ SNDRV_PCM_RATE_192000,
++ .rate_min = 128000,
++ .rate_max = 192000,
++ .nr_rates = 3,
++ .rate_table = (unsigned int[]) {
++ 128000, 176400, 192000,
++ },
++ .sync_ep = 0x81,
++ .sync_iface = 0,
++ .sync_altsetting = 1,
++ .sync_ep_idx = 0,
++ .implicit_fb = 1,
++ },
++ },
++ {
++ QUIRK_DATA_AUDIOFORMAT(0) {
++ .formats = SNDRV_PCM_FMTBIT_S32_LE,
++ .channels = 32, // inputs
++ .fmt_bits = 24,
++ .iface = 0,
++ .altsetting = 1,
++ .altset_idx = 1,
++ .endpoint = 0x81,
++ .ep_attr = USB_ENDPOINT_XFER_ISOC |
++ USB_ENDPOINT_SYNC_ASYNC,
++ .rates = SNDRV_PCM_RATE_32000 |
++ SNDRV_PCM_RATE_44100 |
++ SNDRV_PCM_RATE_48000,
++ .rate_min = 32000,
++ .rate_max = 48000,
++ .nr_rates = 3,
++ .rate_table = (unsigned int[]) {
++ 32000, 44100, 48000,
++ }
++ }
++ },
++ {
++ QUIRK_DATA_AUDIOFORMAT(0) {
++ .formats = SNDRV_PCM_FMTBIT_S32_LE,
++ .channels = 16, // inputs
++ .fmt_bits = 24,
++ .iface = 0,
++ .altsetting = 1,
++ .altset_idx = 1,
++ .endpoint = 0x81,
++ .ep_attr = USB_ENDPOINT_XFER_ISOC |
++ USB_ENDPOINT_SYNC_ASYNC,
++ .rates = SNDRV_PCM_RATE_64000 |
++ SNDRV_PCM_RATE_88200 |
++ SNDRV_PCM_RATE_96000,
++ .rate_min = 64000,
++ .rate_max = 96000,
++ .nr_rates = 3,
++ .rate_table = (unsigned int[]) {
++ 64000, 88200, 96000,
++ }
++ }
++ },
++ {
++ QUIRK_DATA_AUDIOFORMAT(0) {
++ .formats = SNDRV_PCM_FMTBIT_S32_LE,
++ .channels = 8, // inputs
++ .fmt_bits = 24,
++ .iface = 0,
++ .altsetting = 1,
++ .altset_idx = 1,
++ .endpoint = 0x81,
++ .ep_attr = USB_ENDPOINT_XFER_ISOC |
++ USB_ENDPOINT_SYNC_ASYNC,
++ .rates = SNDRV_PCM_RATE_KNOT |
++ SNDRV_PCM_RATE_176400 |
++ SNDRV_PCM_RATE_192000,
++ .rate_min = 128000,
++ .rate_max = 192000,
++ .nr_rates = 3,
++ .rate_table = (unsigned int[]) {
++ 128000, 176400, 192000,
++ }
++ }
++ },
++ QUIRK_COMPOSITE_END
++ }
++ }
++},
+ #undef USB_DEVICE_VENDOR_SPEC
+ #undef USB_AUDIO_DEVICE
+diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
+index e7b68c67852e9..73da862a012c6 100644
+--- a/sound/usb/quirks.c
++++ b/sound/usb/quirks.c
+@@ -1389,6 +1389,27 @@ static int snd_usb_motu_m_series_boot_quirk(struct usb_device *dev)
+ return 0;
+ }
+
++static int snd_usb_rme_digiface_boot_quirk(struct usb_device *dev)
++{
++ /* Disable mixer, internal clock, all outputs ADAT, 48kHz, TMS off */
++ snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
++ 16, 0x40, 0x2410, 0x7fff, NULL, 0);
++ snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
++ 18, 0x40, 0x0104, 0xffff, NULL, 0);
++
++ /* Disable loopback for all inputs */
++ for (int ch = 0; ch < 32; ch++)
++ snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
++ 22, 0x40, 0x400, ch, NULL, 0);
++
++ /* Unity gain for all outputs */
++ for (int ch = 0; ch < 34; ch++)
++ snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
++ 21, 0x40, 0x9000, 0x100 + ch, NULL, 0);
++
++ return 0;
++}
++
+ /*
+ * Setup quirks
+ */
+@@ -1616,6 +1637,8 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev,
+ get_iface_desc(intf->altsetting)->bInterfaceNumber < 3)
+ return snd_usb_motu_microbookii_boot_quirk(dev);
+ break;
++ case USB_ID(0x2a39, 0x3f8c): /* RME Digiface USB */
++ return snd_usb_rme_digiface_boot_quirk(dev);
+ }
+
+ return 0;
+@@ -1771,6 +1794,38 @@ static void mbox3_set_format_quirk(struct snd_usb_substream *subs,
+ dev_warn(&subs->dev->dev, "MBOX3: Couldn't set the sample rate");
+ }
+
++static const int rme_digiface_rate_table[] = {
++ 32000, 44100, 48000, 0,
++ 64000, 88200, 96000, 0,
++ 128000, 176400, 192000, 0,
++};
++
++static int rme_digiface_set_format_quirk(struct snd_usb_substream *subs)
++{
++ unsigned int cur_rate = subs->data_endpoint->cur_rate;
++ u16 val;
++ int speed_mode;
++ int id;
++
++ for (id = 0; id < ARRAY_SIZE(rme_digiface_rate_table); id++) {
++ if (rme_digiface_rate_table[id] == cur_rate)
++ break;
++ }
++
++ if (id >= ARRAY_SIZE(rme_digiface_rate_table))
++ return -EINVAL;
++
++ /* 2, 3, 4 for 1x, 2x, 4x */
++ speed_mode = (id >> 2) + 2;
++ val = (id << 3) | (speed_mode << 12);
++
++ /* Set the sample rate */
++ snd_usb_ctl_msg(subs->stream->chip->dev,
++ usb_sndctrlpipe(subs->stream->chip->dev, 0),
++ 16, 0x40, val, 0x7078, NULL, 0);
++ return 0;
++}
++
+ void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
+ const struct audioformat *fmt)
+ {
+@@ -1795,6 +1850,9 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
+ case USB_ID(0x0dba, 0x5000):
+ mbox3_set_format_quirk(subs, fmt); /* Digidesign Mbox 3 */
+ break;
++ case USB_ID(0x2a39, 0x3f8c): /* RME Digiface USB */
++ rme_digiface_set_format_quirk(subs);
++ break;
+ }
+ }
+
+--
+2.43.0
+
--- /dev/null
+From f10c85ec1807c1cdb4f9e04fb650aa8f14fbbca0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 14 Aug 2024 15:48:41 +0200
+Subject: ALSA: usb-audio: Define macros for quirk table entries
+
+From: Takashi Iwai <tiwai@suse.de>
+
+[ Upstream commit 0c3ad39b791c2ecf718afcaca30e5ceafa939d5c ]
+
+Many entries in the USB-audio quirk tables have relatively complex
+expressions. For improving the readability, introduce a few macros.
+Those are applied in the following patch.
+
+Link: https://patch.msgid.link/20240814134844.2726-2-tiwai@suse.de
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/usb/quirks-table.h | 77 ++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 77 insertions(+)
+
+diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
+index aaa6a515d0f8a..e3a25f4f68792 100644
+--- a/sound/usb/quirks-table.h
++++ b/sound/usb/quirks-table.h
+@@ -35,6 +35,83 @@
+ .bInterfaceClass = USB_CLASS_AUDIO, \
+ .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL
+
++/* Quirk .driver_info, followed by the definition of the quirk entry;
++ * put like QUIRK_DRIVER_INFO { ... } in each entry of the quirk table
++ */
++#define QUIRK_DRIVER_INFO \
++ .driver_info = (unsigned long)&(const struct snd_usb_audio_quirk)
++
++/*
++ * Macros for quirk data entries
++ */
++
++/* Quirk data entry for ignoring the interface */
++#define QUIRK_DATA_IGNORE(_ifno) \
++ .ifnum = (_ifno), .type = QUIRK_IGNORE_INTERFACE
++/* Quirk data entry for a standard audio interface */
++#define QUIRK_DATA_STANDARD_AUDIO(_ifno) \
++ .ifnum = (_ifno), .type = QUIRK_AUDIO_STANDARD_INTERFACE
++/* Quirk data entry for a standard MIDI interface */
++#define QUIRK_DATA_STANDARD_MIDI(_ifno) \
++ .ifnum = (_ifno), .type = QUIRK_MIDI_STANDARD_INTERFACE
++/* Quirk data entry for a standard mixer interface */
++#define QUIRK_DATA_STANDARD_MIXER(_ifno) \
++ .ifnum = (_ifno), .type = QUIRK_AUDIO_STANDARD_MIXER
++
++/* Quirk data entry for Yamaha MIDI */
++#define QUIRK_DATA_MIDI_YAMAHA(_ifno) \
++ .ifnum = (_ifno), .type = QUIRK_MIDI_YAMAHA
++/* Quirk data entry for Edirol UAxx */
++#define QUIRK_DATA_EDIROL_UAXX(_ifno) \
++ .ifnum = (_ifno), .type = QUIRK_AUDIO_EDIROL_UAXX
++/* Quirk data entry for raw bytes interface */
++#define QUIRK_DATA_RAW_BYTES(_ifno) \
++ .ifnum = (_ifno), .type = QUIRK_MIDI_RAW_BYTES
++
++/* Quirk composite array terminator */
++#define QUIRK_COMPOSITE_END { .ifnum = -1 }
++
++/* Quirk data entry for composite quirks;
++ * followed by the quirk array that is terminated with QUIRK_COMPOSITE_END
++ * e.g. QUIRK_DATA_COMPOSITE { { quirk1 }, { quirk2 },..., QUIRK_COMPOSITE_END }
++ */
++#define QUIRK_DATA_COMPOSITE \
++ .ifnum = QUIRK_ANY_INTERFACE, \
++ .type = QUIRK_COMPOSITE, \
++ .data = &(const struct snd_usb_audio_quirk[])
++
++/* Quirk data entry for a fixed audio endpoint;
++ * followed by audioformat definition
++ * e.g. QUIRK_DATA_AUDIOFORMAT(n) { .formats = xxx, ... }
++ */
++#define QUIRK_DATA_AUDIOFORMAT(_ifno) \
++ .ifnum = (_ifno), \
++ .type = QUIRK_AUDIO_FIXED_ENDPOINT, \
++ .data = &(const struct audioformat)
++
++/* Quirk data entry for a fixed MIDI endpoint;
++ * followed by snd_usb_midi_endpoint_info definition
++ * e.g. QUIRK_DATA_MIDI_FIXED_ENDPOINT(n) { .out_cables = x, .in_cables = y }
++ */
++#define QUIRK_DATA_MIDI_FIXED_ENDPOINT(_ifno) \
++ .ifnum = (_ifno), \
++ .type = QUIRK_MIDI_FIXED_ENDPOINT, \
++ .data = &(const struct snd_usb_midi_endpoint_info)
++/* Quirk data entry for a MIDIMAN MIDI endpoint */
++#define QUIRK_DATA_MIDI_MIDIMAN(_ifno) \
++ .ifnum = (_ifno), \
++ .type = QUIRK_MIDI_MIDIMAN, \
++ .data = &(const struct snd_usb_midi_endpoint_info)
++/* Quirk data entry for a EMAGIC MIDI endpoint */
++#define QUIRK_DATA_MIDI_EMAGIC(_ifno) \
++ .ifnum = (_ifno), \
++ .type = QUIRK_MIDI_EMAGIC, \
++ .data = &(const struct snd_usb_midi_endpoint_info)
++
++/*
++ * Here we go... the quirk table definition begins:
++ */
++
+ /* FTDI devices */
+ {
+ USB_DEVICE(0x0403, 0xb8d8),
+--
+2.43.0
+
--- /dev/null
+From c6df1184fbe038fcae1a393857c9bdab1fd95cf9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 14 Aug 2024 15:48:42 +0200
+Subject: ALSA: usb-audio: Replace complex quirk lines with macros
+
+From: Takashi Iwai <tiwai@suse.de>
+
+[ Upstream commit d79e13f8e8abb5cd3a2a0f9fc9bc3fc750c5b06f ]
+
+Apply the newly introduced macros for reduce the complex expressions
+and cast in the quirk table definitions. It results in a significant
+code reduction, too.
+
+There should be no functional changes.
+
+Link: https://patch.msgid.link/20240814134844.2726-3-tiwai@suse.de
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/usb/quirks-table.h | 2210 ++++++++++----------------------------
+ 1 file changed, 593 insertions(+), 1617 deletions(-)
+
+diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
+index e3a25f4f68792..8d22de8bc2a96 100644
+--- a/sound/usb/quirks-table.h
++++ b/sound/usb/quirks-table.h
+@@ -115,7 +115,7 @@
+ /* FTDI devices */
+ {
+ USB_DEVICE(0x0403, 0xb8d8),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ /* .vendor_name = "STARR LABS", */
+ /* .product_name = "Starr Labs MIDI USB device", */
+ .ifnum = 0,
+@@ -126,10 +126,8 @@
+ {
+ /* Creative BT-D1 */
+ USB_DEVICE(0x041e, 0x0005),
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DRIVER_INFO {
++ QUIRK_DATA_AUDIOFORMAT(1) {
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels = 2,
+ .iface = 1,
+@@ -164,18 +162,11 @@
+ */
+ {
+ USB_AUDIO_DEVICE(0x041e, 0x4095),
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = &(const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 2,
+- .type = QUIRK_AUDIO_STANDARD_MIXER,
+- },
++ QUIRK_DRIVER_INFO {
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_STANDARD_MIXER(2) },
+ {
+- .ifnum = 3,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(3) {
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels = 2,
+ .fmt_bits = 16,
+@@ -191,9 +182,7 @@
+ .rate_table = (unsigned int[]) { 48000 },
+ },
+ },
+- {
+- .ifnum = -1
+- },
++ QUIRK_COMPOSITE_END
+ },
+ },
+ },
+@@ -205,31 +194,18 @@
+ */
+ {
+ USB_DEVICE(0x0424, 0xb832),
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Standard Microsystems Corp.",
+ .product_name = "HP Wireless Audio",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
++ QUIRK_DATA_COMPOSITE {
+ /* Mixer */
+- {
+- .ifnum = 0,
+- .type = QUIRK_IGNORE_INTERFACE,
+- },
++ { QUIRK_DATA_IGNORE(0) },
+ /* Playback */
+- {
+- .ifnum = 1,
+- .type = QUIRK_IGNORE_INTERFACE,
+- },
++ { QUIRK_DATA_IGNORE(1) },
+ /* Capture */
+- {
+- .ifnum = 2,
+- .type = QUIRK_IGNORE_INTERFACE,
+- },
++ { QUIRK_DATA_IGNORE(2) },
+ /* HID Device, .ifnum = 3 */
+- {
+- .ifnum = -1,
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -252,20 +228,18 @@
+
+ #define YAMAHA_DEVICE(id, name) { \
+ USB_DEVICE(0x0499, id), \
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { \
++ QUIRK_DRIVER_INFO { \
+ .vendor_name = "Yamaha", \
+ .product_name = name, \
+- .ifnum = QUIRK_ANY_INTERFACE, \
+- .type = QUIRK_MIDI_YAMAHA \
++ QUIRK_DATA_MIDI_YAMAHA(QUIRK_ANY_INTERFACE) \
+ } \
+ }
+ #define YAMAHA_INTERFACE(id, intf, name) { \
+ USB_DEVICE_VENDOR_SPEC(0x0499, id), \
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { \
++ QUIRK_DRIVER_INFO { \
+ .vendor_name = "Yamaha", \
+ .product_name = name, \
+- .ifnum = intf, \
+- .type = QUIRK_MIDI_YAMAHA \
++ QUIRK_DATA_MIDI_YAMAHA(intf) \
+ } \
+ }
+ YAMAHA_DEVICE(0x1000, "UX256"),
+@@ -353,135 +327,67 @@ YAMAHA_DEVICE(0x105d, NULL),
+ YAMAHA_DEVICE(0x1718, "P-125"),
+ {
+ USB_DEVICE(0x0499, 0x1503),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ /* .vendor_name = "Yamaha", */
+ /* .product_name = "MOX6/MOX8", */
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 2,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 3,
+- .type = QUIRK_MIDI_YAMAHA
+- },
+- {
+- .ifnum = -1
+- }
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_STANDARD_AUDIO(1) },
++ { QUIRK_DATA_STANDARD_AUDIO(2) },
++ { QUIRK_DATA_MIDI_YAMAHA(3) },
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ {
+ USB_DEVICE(0x0499, 0x1507),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ /* .vendor_name = "Yamaha", */
+ /* .product_name = "THR10", */
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 2,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 3,
+- .type = QUIRK_MIDI_YAMAHA
+- },
+- {
+- .ifnum = -1
+- }
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_STANDARD_AUDIO(1) },
++ { QUIRK_DATA_STANDARD_AUDIO(2) },
++ { QUIRK_DATA_MIDI_YAMAHA(3) },
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ {
+ USB_DEVICE(0x0499, 0x1509),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ /* .vendor_name = "Yamaha", */
+ /* .product_name = "Steinberg UR22", */
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 2,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 3,
+- .type = QUIRK_MIDI_YAMAHA
+- },
+- {
+- .ifnum = 4,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
+- {
+- .ifnum = -1
+- }
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_STANDARD_AUDIO(1) },
++ { QUIRK_DATA_STANDARD_AUDIO(2) },
++ { QUIRK_DATA_MIDI_YAMAHA(3) },
++ { QUIRK_DATA_IGNORE(4) },
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ {
+ USB_DEVICE(0x0499, 0x150a),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ /* .vendor_name = "Yamaha", */
+ /* .product_name = "THR5A", */
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 2,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 3,
+- .type = QUIRK_MIDI_YAMAHA
+- },
+- {
+- .ifnum = -1
+- }
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_STANDARD_AUDIO(1) },
++ { QUIRK_DATA_STANDARD_AUDIO(2) },
++ { QUIRK_DATA_MIDI_YAMAHA(3) },
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ {
+ USB_DEVICE(0x0499, 0x150c),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ /* .vendor_name = "Yamaha", */
+ /* .product_name = "THR10C", */
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 2,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 3,
+- .type = QUIRK_MIDI_YAMAHA
+- },
+- {
+- .ifnum = -1
+- }
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_STANDARD_AUDIO(1) },
++ { QUIRK_DATA_STANDARD_AUDIO(2) },
++ { QUIRK_DATA_MIDI_YAMAHA(3) },
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -515,7 +421,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ USB_DEVICE_ID_MATCH_INT_CLASS,
+ .idVendor = 0x0499,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_AUTODETECT
+ }
+@@ -526,16 +432,12 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ */
+ {
+ USB_DEVICE(0x0582, 0x0000),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Roland",
+ .product_name = "UA-100",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
++ QUIRK_DATA_COMPOSITE {
+ {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = & (const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(0) {
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels = 4,
+ .iface = 0,
+@@ -550,9 +452,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ },
+ {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = & (const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(1) {
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels = 2,
+ .iface = 1,
+@@ -567,106 +467,66 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ },
+ {
+- .ifnum = 2,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) {
+ .out_cables = 0x0007,
+ .in_cables = 0x0007
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ {
+ USB_DEVICE(0x0582, 0x0002),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "EDIROL",
+ .product_name = "UM-4",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 0,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
+- {
+- .ifnum = 1,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_IGNORE(0) },
++ { QUIRK_DATA_IGNORE(1) },
+ {
+- .ifnum = 2,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) {
+ .out_cables = 0x000f,
+ .in_cables = 0x000f
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ {
+ USB_DEVICE(0x0582, 0x0003),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Roland",
+ .product_name = "SC-8850",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 0,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_IGNORE(0) },
++ { QUIRK_DATA_IGNORE(1) },
+ {
+- .ifnum = 1,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
+- {
+- .ifnum = 2,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) {
+ .out_cables = 0x003f,
+ .in_cables = 0x003f
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ {
+ USB_DEVICE(0x0582, 0x0004),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Roland",
+ .product_name = "U-8",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_IGNORE(0) },
++ { QUIRK_DATA_IGNORE(1) },
+ {
+- .ifnum = 0,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
+- {
+- .ifnum = 1,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
+- {
+- .ifnum = 2,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) {
+ .out_cables = 0x0005,
+ .in_cables = 0x0005
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -674,152 +534,92 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ /* Has ID 0x0099 when not in "Advanced Driver" mode.
+ * The UM-2EX has only one input, but we cannot detect this. */
+ USB_DEVICE(0x0582, 0x0005),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "EDIROL",
+ .product_name = "UM-2",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 0,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_IGNORE(0) },
++ { QUIRK_DATA_IGNORE(1) },
+ {
+- .ifnum = 1,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
+- {
+- .ifnum = 2,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) {
+ .out_cables = 0x0003,
+ .in_cables = 0x0003
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ {
+ USB_DEVICE(0x0582, 0x0007),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Roland",
+ .product_name = "SC-8820",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 0,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
+- {
+- .ifnum = 1,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_IGNORE(0) },
++ { QUIRK_DATA_IGNORE(1) },
+ {
+- .ifnum = 2,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) {
+ .out_cables = 0x0013,
+ .in_cables = 0x0013
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ {
+ USB_DEVICE(0x0582, 0x0008),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Roland",
+ .product_name = "PC-300",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 0,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_IGNORE(0) },
++ { QUIRK_DATA_IGNORE(1) },
+ {
+- .ifnum = 1,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
+- {
+- .ifnum = 2,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ {
+ /* has ID 0x009d when not in "Advanced Driver" mode */
+ USB_DEVICE(0x0582, 0x0009),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "EDIROL",
+ .product_name = "UM-1",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_IGNORE(0) },
++ { QUIRK_DATA_IGNORE(1) },
+ {
+- .ifnum = 0,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
+- {
+- .ifnum = 1,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
+- {
+- .ifnum = 2,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ {
+ USB_DEVICE(0x0582, 0x000b),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Roland",
+ .product_name = "SK-500",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 0,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_IGNORE(0) },
++ { QUIRK_DATA_IGNORE(1) },
+ {
+- .ifnum = 1,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
+- {
+- .ifnum = 2,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) {
+ .out_cables = 0x0013,
+ .in_cables = 0x0013
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -827,31 +627,19 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ /* thanks to Emiliano Grilli <emillo@libero.it>
+ * for helping researching this data */
+ USB_DEVICE(0x0582, 0x000c),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Roland",
+ .product_name = "SC-D70",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_STANDARD_AUDIO(0) },
++ { QUIRK_DATA_STANDARD_AUDIO(1) },
+ {
+- .ifnum = 2,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) {
+ .out_cables = 0x0007,
+ .in_cables = 0x0007
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -865,35 +653,23 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ * the 96kHz sample rate.
+ */
+ USB_DEVICE(0x0582, 0x0010),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "EDIROL",
+ .product_name = "UA-5",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 2,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = -1
+- }
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_STANDARD_AUDIO(1) },
++ { QUIRK_DATA_STANDARD_AUDIO(2) },
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ {
+ /* has ID 0x0013 when not in "Advanced Driver" mode */
+ USB_DEVICE(0x0582, 0x0012),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Roland",
+ .product_name = "XV-5050",
+- .ifnum = 0,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+@@ -902,12 +678,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+ /* has ID 0x0015 when not in "Advanced Driver" mode */
+ USB_DEVICE(0x0582, 0x0014),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "EDIROL",
+ .product_name = "UM-880",
+- .ifnum = 0,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+ .out_cables = 0x01ff,
+ .in_cables = 0x01ff
+ }
+@@ -916,74 +690,48 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+ /* has ID 0x0017 when not in "Advanced Driver" mode */
+ USB_DEVICE(0x0582, 0x0016),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "EDIROL",
+ .product_name = "SD-90",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_STANDARD_AUDIO(0) },
++ { QUIRK_DATA_STANDARD_AUDIO(1) },
+ {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 2,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) {
+ .out_cables = 0x000f,
+ .in_cables = 0x000f
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ {
+ /* has ID 0x001c when not in "Advanced Driver" mode */
+ USB_DEVICE(0x0582, 0x001b),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Roland",
+ .product_name = "MMP-2",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 0,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
+- {
+- .ifnum = 1,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_IGNORE(0) },
++ { QUIRK_DATA_IGNORE(1) },
+ {
+- .ifnum = 2,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ {
+ /* has ID 0x001e when not in "Advanced Driver" mode */
+ USB_DEVICE(0x0582, 0x001d),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Roland",
+ .product_name = "V-SYNTH",
+- .ifnum = 0,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+@@ -992,12 +740,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+ /* has ID 0x0024 when not in "Advanced Driver" mode */
+ USB_DEVICE(0x0582, 0x0023),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "EDIROL",
+ .product_name = "UM-550",
+- .ifnum = 0,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+ .out_cables = 0x003f,
+ .in_cables = 0x003f
+ }
+@@ -1010,20 +756,13 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ * and no MIDI.
+ */
+ USB_DEVICE(0x0582, 0x0025),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "EDIROL",
+ .product_name = "UA-20",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 0,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_IGNORE(0) },
+ {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = & (const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(1) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 2,
+ .iface = 1,
+@@ -1038,9 +777,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ },
+ {
+- .ifnum = 2,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = & (const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(2) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 2,
+ .iface = 2,
+@@ -1055,28 +792,22 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ },
+ {
+- .ifnum = 3,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(3) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ {
+ /* has ID 0x0028 when not in "Advanced Driver" mode */
+ USB_DEVICE(0x0582, 0x0027),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "EDIROL",
+ .product_name = "SD-20",
+- .ifnum = 0,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+ .out_cables = 0x0003,
+ .in_cables = 0x0007
+ }
+@@ -1085,12 +816,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+ /* has ID 0x002a when not in "Advanced Driver" mode */
+ USB_DEVICE(0x0582, 0x0029),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "EDIROL",
+ .product_name = "SD-80",
+- .ifnum = 0,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+ .out_cables = 0x000f,
+ .in_cables = 0x000f
+ }
+@@ -1103,39 +832,24 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ * but offers only 16-bit PCM and no MIDI.
+ */
+ USB_DEVICE_VENDOR_SPEC(0x0582, 0x002b),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "EDIROL",
+ .product_name = "UA-700",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_EDIROL_UAXX
+- },
+- {
+- .ifnum = 2,
+- .type = QUIRK_AUDIO_EDIROL_UAXX
+- },
+- {
+- .ifnum = 3,
+- .type = QUIRK_AUDIO_EDIROL_UAXX
+- },
+- {
+- .ifnum = -1
+- }
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_EDIROL_UAXX(1) },
++ { QUIRK_DATA_EDIROL_UAXX(2) },
++ { QUIRK_DATA_EDIROL_UAXX(3) },
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ {
+ /* has ID 0x002e when not in "Advanced Driver" mode */
+ USB_DEVICE(0x0582, 0x002d),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Roland",
+ .product_name = "XV-2020",
+- .ifnum = 0,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+@@ -1144,12 +858,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+ /* has ID 0x0030 when not in "Advanced Driver" mode */
+ USB_DEVICE(0x0582, 0x002f),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Roland",
+ .product_name = "VariOS",
+- .ifnum = 0,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+ .out_cables = 0x0007,
+ .in_cables = 0x0007
+ }
+@@ -1158,12 +870,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+ /* has ID 0x0034 when not in "Advanced Driver" mode */
+ USB_DEVICE(0x0582, 0x0033),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "EDIROL",
+ .product_name = "PCR",
+- .ifnum = 0,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+ .out_cables = 0x0003,
+ .in_cables = 0x0007
+ }
+@@ -1175,12 +885,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ * later revisions use IDs 0x0054 and 0x00a2.
+ */
+ USB_DEVICE(0x0582, 0x0037),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Roland",
+ .product_name = "Digital Piano",
+- .ifnum = 0,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+@@ -1193,39 +901,24 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ * and no MIDI.
+ */
+ USB_DEVICE_VENDOR_SPEC(0x0582, 0x003b),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "BOSS",
+ .product_name = "GS-10",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = & (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 2,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 3,
+- .type = QUIRK_MIDI_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = -1
+- }
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_STANDARD_AUDIO(1) },
++ { QUIRK_DATA_STANDARD_AUDIO(2) },
++ { QUIRK_DATA_STANDARD_MIDI(3) },
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ {
+ /* has ID 0x0041 when not in "Advanced Driver" mode */
+ USB_DEVICE(0x0582, 0x0040),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Roland",
+ .product_name = "GI-20",
+- .ifnum = 0,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+@@ -1234,12 +927,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+ /* has ID 0x0043 when not in "Advanced Driver" mode */
+ USB_DEVICE(0x0582, 0x0042),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Roland",
+ .product_name = "RS-70",
+- .ifnum = 0,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+@@ -1248,36 +939,24 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+ /* has ID 0x0049 when not in "Advanced Driver" mode */
+ USB_DEVICE(0x0582, 0x0047),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ /* .vendor_name = "EDIROL", */
+ /* .product_name = "UR-80", */
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
++ QUIRK_DATA_COMPOSITE {
+ /* in the 96 kHz modes, only interface 1 is there */
+- {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 2,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = -1
+- }
++ { QUIRK_DATA_STANDARD_AUDIO(1) },
++ { QUIRK_DATA_STANDARD_AUDIO(2) },
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ {
+ /* has ID 0x004a when not in "Advanced Driver" mode */
+ USB_DEVICE(0x0582, 0x0048),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ /* .vendor_name = "EDIROL", */
+ /* .product_name = "UR-80", */
+- .ifnum = 0,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+ .out_cables = 0x0003,
+ .in_cables = 0x0007
+ }
+@@ -1286,35 +965,23 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+ /* has ID 0x004e when not in "Advanced Driver" mode */
+ USB_DEVICE(0x0582, 0x004c),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "EDIROL",
+ .product_name = "PCR-A",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 2,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = -1
+- }
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_STANDARD_AUDIO(1) },
++ { QUIRK_DATA_STANDARD_AUDIO(2) },
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ {
+ /* has ID 0x004f when not in "Advanced Driver" mode */
+ USB_DEVICE(0x0582, 0x004d),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "EDIROL",
+ .product_name = "PCR-A",
+- .ifnum = 0,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+ .out_cables = 0x0003,
+ .in_cables = 0x0007
+ }
+@@ -1326,76 +993,52 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ * is standard compliant, but has only 16-bit PCM.
+ */
+ USB_DEVICE(0x0582, 0x0050),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "EDIROL",
+ .product_name = "UA-3FX",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 2,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = -1
+- }
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_STANDARD_AUDIO(1) },
++ { QUIRK_DATA_STANDARD_AUDIO(2) },
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ {
+ USB_DEVICE(0x0582, 0x0052),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "EDIROL",
+ .product_name = "UM-1SX",
+- .ifnum = 0,
+- .type = QUIRK_MIDI_STANDARD_INTERFACE
++ QUIRK_DATA_STANDARD_MIDI(0)
+ }
+ },
+ {
+ USB_DEVICE(0x0582, 0x0060),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Roland",
+ .product_name = "EXR Series",
+- .ifnum = 0,
+- .type = QUIRK_MIDI_STANDARD_INTERFACE
++ QUIRK_DATA_STANDARD_MIDI(0)
+ }
+ },
+ {
+ /* has ID 0x0066 when not in "Advanced Driver" mode */
+ USB_DEVICE(0x0582, 0x0064),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ /* .vendor_name = "EDIROL", */
+ /* .product_name = "PCR-1", */
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 2,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = -1
+- }
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_STANDARD_AUDIO(1) },
++ { QUIRK_DATA_STANDARD_AUDIO(2) },
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ {
+ /* has ID 0x0067 when not in "Advanced Driver" mode */
+ USB_DEVICE(0x0582, 0x0065),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ /* .vendor_name = "EDIROL", */
+ /* .product_name = "PCR-1", */
+- .ifnum = 0,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0003
+ }
+@@ -1404,12 +1047,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+ /* has ID 0x006e when not in "Advanced Driver" mode */
+ USB_DEVICE(0x0582, 0x006d),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Roland",
+ .product_name = "FANTOM-X",
+- .ifnum = 0,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+@@ -1422,39 +1063,24 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ * offers only 16-bit PCM at 44.1 kHz and no MIDI.
+ */
+ USB_DEVICE_VENDOR_SPEC(0x0582, 0x0074),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "EDIROL",
+ .product_name = "UA-25",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_EDIROL_UAXX
+- },
+- {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_EDIROL_UAXX
+- },
+- {
+- .ifnum = 2,
+- .type = QUIRK_AUDIO_EDIROL_UAXX
+- },
+- {
+- .ifnum = -1
+- }
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_EDIROL_UAXX(0) },
++ { QUIRK_DATA_EDIROL_UAXX(1) },
++ { QUIRK_DATA_EDIROL_UAXX(2) },
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ {
+ /* has ID 0x0076 when not in "Advanced Driver" mode */
+ USB_DEVICE(0x0582, 0x0075),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "BOSS",
+ .product_name = "DR-880",
+- .ifnum = 0,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+@@ -1463,12 +1089,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+ /* has ID 0x007b when not in "Advanced Driver" mode */
+ USB_DEVICE_VENDOR_SPEC(0x0582, 0x007a),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Roland",
+ /* "RD" or "RD-700SX"? */
+- .ifnum = 0,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+ .out_cables = 0x0003,
+ .in_cables = 0x0003
+ }
+@@ -1477,12 +1101,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+ /* has ID 0x0081 when not in "Advanced Driver" mode */
+ USB_DEVICE(0x0582, 0x0080),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Roland",
+ .product_name = "G-70",
+- .ifnum = 0,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+@@ -1491,12 +1113,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+ /* has ID 0x008c when not in "Advanced Driver" mode */
+ USB_DEVICE(0x0582, 0x008b),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "EDIROL",
+ .product_name = "PC-50",
+- .ifnum = 0,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+@@ -1508,56 +1128,31 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ * is standard compliant, but has only 16-bit PCM and no MIDI.
+ */
+ USB_DEVICE(0x0582, 0x00a3),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "EDIROL",
+ .product_name = "UA-4FX",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_EDIROL_UAXX
+- },
+- {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_EDIROL_UAXX
+- },
+- {
+- .ifnum = 2,
+- .type = QUIRK_AUDIO_EDIROL_UAXX
+- },
+- {
+- .ifnum = -1
+- }
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_EDIROL_UAXX(0) },
++ { QUIRK_DATA_EDIROL_UAXX(1) },
++ { QUIRK_DATA_EDIROL_UAXX(2) },
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ {
+ /* Edirol M-16DX */
+ USB_DEVICE(0x0582, 0x00c4),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
++ QUIRK_DRIVER_INFO {
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_STANDARD_AUDIO(0) },
++ { QUIRK_DATA_STANDARD_AUDIO(1) },
+ {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 2,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -1567,37 +1162,22 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ * offers only 16-bit PCM at 44.1 kHz and no MIDI.
+ */
+ USB_DEVICE_VENDOR_SPEC(0x0582, 0x00e6),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "EDIROL",
+ .product_name = "UA-25EX",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_EDIROL_UAXX
+- },
+- {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_EDIROL_UAXX
+- },
+- {
+- .ifnum = 2,
+- .type = QUIRK_AUDIO_EDIROL_UAXX
+- },
+- {
+- .ifnum = -1
+- }
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_EDIROL_UAXX(0) },
++ { QUIRK_DATA_EDIROL_UAXX(1) },
++ { QUIRK_DATA_EDIROL_UAXX(2) },
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ {
+ /* Edirol UM-3G */
+ USB_DEVICE_VENDOR_SPEC(0x0582, 0x0108),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+- .ifnum = 0,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DRIVER_INFO {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+ .out_cables = 0x0007,
+ .in_cables = 0x0007
+ }
+@@ -1606,45 +1186,29 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+ /* BOSS ME-25 */
+ USB_DEVICE(0x0582, 0x0113),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
++ QUIRK_DRIVER_INFO {
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_STANDARD_AUDIO(0) },
++ { QUIRK_DATA_STANDARD_AUDIO(1) },
+ {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 2,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ {
+ /* only 44.1 kHz works at the moment */
+ USB_DEVICE(0x0582, 0x0120),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ /* .vendor_name = "Roland", */
+ /* .product_name = "OCTO-CAPTURE", */
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
++ QUIRK_DATA_COMPOSITE {
+ {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = & (const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(0) {
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .channels = 10,
+ .iface = 0,
+@@ -1660,9 +1224,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ },
+ {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = & (const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(1) {
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .channels = 12,
+ .iface = 1,
+@@ -1678,40 +1240,26 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ },
+ {
+- .ifnum = 2,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+ },
+- {
+- .ifnum = 3,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
+- {
+- .ifnum = 4,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
+- {
+- .ifnum = -1
+- }
++ { QUIRK_DATA_IGNORE(3) },
++ { QUIRK_DATA_IGNORE(4) },
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ {
+ /* only 44.1 kHz works at the moment */
+ USB_DEVICE(0x0582, 0x012f),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ /* .vendor_name = "Roland", */
+ /* .product_name = "QUAD-CAPTURE", */
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
++ QUIRK_DATA_COMPOSITE {
+ {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = & (const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(0) {
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .channels = 4,
+ .iface = 0,
+@@ -1727,9 +1275,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ },
+ {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = & (const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(1) {
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .channels = 6,
+ .iface = 1,
+@@ -1745,54 +1291,32 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ },
+ {
+- .ifnum = 2,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+ },
+- {
+- .ifnum = 3,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
+- {
+- .ifnum = 4,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
+- {
+- .ifnum = -1
+- }
++ { QUIRK_DATA_IGNORE(3) },
++ { QUIRK_DATA_IGNORE(4) },
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ {
+ USB_DEVICE(0x0582, 0x0159),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ /* .vendor_name = "Roland", */
+ /* .product_name = "UA-22", */
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_STANDARD_AUDIO(0) },
++ { QUIRK_DATA_STANDARD_AUDIO(1) },
+ {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 2,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -1800,19 +1324,19 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ /* UA101 and co are supported by another driver */
+ {
+ USB_DEVICE(0x0582, 0x0044), /* UA-1000 high speed */
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .ifnum = QUIRK_NODEV_INTERFACE
+ },
+ },
+ {
+ USB_DEVICE(0x0582, 0x007d), /* UA-101 high speed */
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .ifnum = QUIRK_NODEV_INTERFACE
+ },
+ },
+ {
+ USB_DEVICE(0x0582, 0x008d), /* UA-101 full speed */
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .ifnum = QUIRK_NODEV_INTERFACE
+ },
+ },
+@@ -1823,7 +1347,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ USB_DEVICE_ID_MATCH_INT_CLASS,
+ .idVendor = 0x0582,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_AUTODETECT
+ }
+@@ -1838,12 +1362,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ * compliant USB MIDI ports for external MIDI and controls.
+ */
+ USB_DEVICE_VENDOR_SPEC(0x06f8, 0xb000),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Hercules",
+ .product_name = "DJ Console (WE)",
+- .ifnum = 4,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(4) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+@@ -1853,12 +1375,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ /* Midiman/M-Audio devices */
+ {
+ USB_DEVICE_VENDOR_SPEC(0x0763, 0x1002),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "M-Audio",
+ .product_name = "MidiSport 2x2",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_MIDI_MIDIMAN,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_MIDIMAN(QUIRK_ANY_INTERFACE) {
+ .out_cables = 0x0003,
+ .in_cables = 0x0003
+ }
+@@ -1866,12 +1386,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ },
+ {
+ USB_DEVICE_VENDOR_SPEC(0x0763, 0x1011),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "M-Audio",
+ .product_name = "MidiSport 1x1",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_MIDI_MIDIMAN,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_MIDIMAN(QUIRK_ANY_INTERFACE) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+@@ -1879,12 +1397,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ },
+ {
+ USB_DEVICE_VENDOR_SPEC(0x0763, 0x1015),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "M-Audio",
+ .product_name = "Keystation",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_MIDI_MIDIMAN,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_MIDIMAN(QUIRK_ANY_INTERFACE) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+@@ -1892,12 +1408,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ },
+ {
+ USB_DEVICE_VENDOR_SPEC(0x0763, 0x1021),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "M-Audio",
+ .product_name = "MidiSport 4x4",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_MIDI_MIDIMAN,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_MIDIMAN(QUIRK_ANY_INTERFACE) {
+ .out_cables = 0x000f,
+ .in_cables = 0x000f
+ }
+@@ -1910,12 +1424,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ * Thanks to Olaf Giesbrecht <Olaf_Giesbrecht@yahoo.de>
+ */
+ USB_DEVICE_VER(0x0763, 0x1031, 0x0100, 0x0109),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "M-Audio",
+ .product_name = "MidiSport 8x8",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_MIDI_MIDIMAN,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_MIDIMAN(QUIRK_ANY_INTERFACE) {
+ .out_cables = 0x01ff,
+ .in_cables = 0x01ff
+ }
+@@ -1923,12 +1435,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ },
+ {
+ USB_DEVICE_VENDOR_SPEC(0x0763, 0x1033),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "M-Audio",
+ .product_name = "MidiSport 8x8",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_MIDI_MIDIMAN,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_MIDIMAN(QUIRK_ANY_INTERFACE) {
+ .out_cables = 0x01ff,
+ .in_cables = 0x01ff
+ }
+@@ -1936,12 +1446,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ },
+ {
+ USB_DEVICE_VENDOR_SPEC(0x0763, 0x1041),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "M-Audio",
+ .product_name = "MidiSport 2x4",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_MIDI_MIDIMAN,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_MIDIMAN(QUIRK_ANY_INTERFACE) {
+ .out_cables = 0x000f,
+ .in_cables = 0x0003
+ }
+@@ -1949,76 +1457,41 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ },
+ {
+ USB_DEVICE_VENDOR_SPEC(0x0763, 0x2001),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "M-Audio",
+ .product_name = "Quattro",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = & (const struct snd_usb_audio_quirk[]) {
++ QUIRK_DATA_COMPOSITE {
+ /*
+ * Interfaces 0-2 are "Windows-compatible", 16-bit only,
+ * and share endpoints with the other interfaces.
+ * Ignore them. The other interfaces can do 24 bits,
+ * but captured samples are big-endian (see usbaudio.c).
+ */
+- {
+- .ifnum = 0,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
+- {
+- .ifnum = 1,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
+- {
+- .ifnum = 2,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
+- {
+- .ifnum = 3,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
+- {
+- .ifnum = 4,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 5,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 6,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
+- {
+- .ifnum = 7,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 8,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 9,
+- .type = QUIRK_MIDI_MIDIMAN,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ { QUIRK_DATA_IGNORE(0) },
++ { QUIRK_DATA_IGNORE(1) },
++ { QUIRK_DATA_IGNORE(2) },
++ { QUIRK_DATA_IGNORE(3) },
++ { QUIRK_DATA_STANDARD_AUDIO(4) },
++ { QUIRK_DATA_STANDARD_AUDIO(5) },
++ { QUIRK_DATA_IGNORE(6) },
++ { QUIRK_DATA_STANDARD_AUDIO(7) },
++ { QUIRK_DATA_STANDARD_AUDIO(8) },
++ {
++ QUIRK_DATA_MIDI_MIDIMAN(9) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ {
+ USB_DEVICE_VENDOR_SPEC(0x0763, 0x2003),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "M-Audio",
+ .product_name = "AudioPhile",
+- .ifnum = 6,
+- .type = QUIRK_MIDI_MIDIMAN,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_MIDIMAN(6) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+@@ -2026,12 +1499,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ },
+ {
+ USB_DEVICE_VENDOR_SPEC(0x0763, 0x2008),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "M-Audio",
+ .product_name = "Ozone",
+- .ifnum = 3,
+- .type = QUIRK_MIDI_MIDIMAN,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_MIDIMAN(3) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+@@ -2039,93 +1510,45 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ },
+ {
+ USB_DEVICE_VENDOR_SPEC(0x0763, 0x200d),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "M-Audio",
+ .product_name = "OmniStudio",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = & (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 0,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
+- {
+- .ifnum = 1,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
+- {
+- .ifnum = 2,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
+- {
+- .ifnum = 3,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
+- {
+- .ifnum = 4,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 5,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 6,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
+- {
+- .ifnum = 7,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 8,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 9,
+- .type = QUIRK_MIDI_MIDIMAN,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_IGNORE(0) },
++ { QUIRK_DATA_IGNORE(1) },
++ { QUIRK_DATA_IGNORE(2) },
++ { QUIRK_DATA_IGNORE(3) },
++ { QUIRK_DATA_STANDARD_AUDIO(4) },
++ { QUIRK_DATA_STANDARD_AUDIO(5) },
++ { QUIRK_DATA_IGNORE(6) },
++ { QUIRK_DATA_STANDARD_AUDIO(7) },
++ { QUIRK_DATA_STANDARD_AUDIO(8) },
++ {
++ QUIRK_DATA_MIDI_MIDIMAN(9) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ {
+ USB_DEVICE(0x0763, 0x2019),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ /* .vendor_name = "M-Audio", */
+ /* .product_name = "Ozone Academic", */
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = & (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_STANDARD_AUDIO(0) },
++ { QUIRK_DATA_STANDARD_AUDIO(1) },
++ { QUIRK_DATA_STANDARD_AUDIO(2) },
+ {
+- .ifnum = 2,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 3,
+- .type = QUIRK_MIDI_MIDIMAN,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_MIDIMAN(3) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -2135,21 +1558,14 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ },
+ {
+ USB_DEVICE_VENDOR_SPEC(0x0763, 0x2030),
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ /* .vendor_name = "M-Audio", */
+ /* .product_name = "Fast Track C400", */
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = &(const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_STANDARD_MIXER,
+- },
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_STANDARD_MIXER(1) },
+ /* Playback */
+ {
+- .ifnum = 2,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(2) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 6,
+ .iface = 2,
+@@ -2173,9 +1589,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ },
+ /* Capture */
+ {
+- .ifnum = 3,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(3) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 4,
+ .iface = 3,
+@@ -2197,30 +1611,21 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ .clock = 0x80,
+ }
+ },
+- /* MIDI */
+- {
+- .ifnum = -1 /* Interface = 4 */
+- }
++ /* MIDI: Interface = 4*/
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ {
+ USB_DEVICE_VENDOR_SPEC(0x0763, 0x2031),
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ /* .vendor_name = "M-Audio", */
+ /* .product_name = "Fast Track C600", */
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = &(const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_STANDARD_MIXER,
+- },
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_STANDARD_MIXER(1) },
+ /* Playback */
+ {
+- .ifnum = 2,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(2) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 8,
+ .iface = 2,
+@@ -2244,9 +1649,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ },
+ /* Capture */
+ {
+- .ifnum = 3,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(3) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 6,
+ .iface = 3,
+@@ -2268,29 +1671,20 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ .clock = 0x80,
+ }
+ },
+- /* MIDI */
+- {
+- .ifnum = -1 /* Interface = 4 */
+- }
++ /* MIDI: Interface = 4 */
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ {
+ USB_DEVICE_VENDOR_SPEC(0x0763, 0x2080),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ /* .vendor_name = "M-Audio", */
+ /* .product_name = "Fast Track Ultra", */
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = & (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_STANDARD_MIXER,
+- },
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_STANDARD_MIXER(0) },
+ {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = & (const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(1) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 8,
+ .iface = 1,
+@@ -2312,9 +1706,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ },
+ {
+- .ifnum = 2,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = & (const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(2) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 8,
+ .iface = 2,
+@@ -2336,28 +1728,19 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ },
+ /* interface 3 (MIDI) is standard compliant */
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ {
+ USB_DEVICE_VENDOR_SPEC(0x0763, 0x2081),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ /* .vendor_name = "M-Audio", */
+ /* .product_name = "Fast Track Ultra 8R", */
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = & (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_STANDARD_MIXER,
+- },
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_STANDARD_MIXER(0) },
+ {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = & (const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(1) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 8,
+ .iface = 1,
+@@ -2379,9 +1762,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ },
+ {
+- .ifnum = 2,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = & (const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(2) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 8,
+ .iface = 2,
+@@ -2403,9 +1784,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ },
+ /* interface 3 (MIDI) is standard compliant */
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -2413,21 +1792,19 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ /* Casio devices */
+ {
+ USB_DEVICE(0x07cf, 0x6801),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Casio",
+ .product_name = "PL-40R",
+- .ifnum = 0,
+- .type = QUIRK_MIDI_YAMAHA
++ QUIRK_DATA_MIDI_YAMAHA(0)
+ }
+ },
+ {
+ /* this ID is used by several devices without a product ID */
+ USB_DEVICE(0x07cf, 0x6802),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Casio",
+ .product_name = "Keyboard",
+- .ifnum = 0,
+- .type = QUIRK_MIDI_YAMAHA
++ QUIRK_DATA_MIDI_YAMAHA(0)
+ }
+ },
+
+@@ -2440,23 +1817,13 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ .idVendor = 0x07fd,
+ .idProduct = 0x0001,
+ .bDeviceSubClass = 2,
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "MOTU",
+ .product_name = "Fastlane",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = & (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 0,
+- .type = QUIRK_MIDI_RAW_BYTES
+- },
+- {
+- .ifnum = 1,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
+- {
+- .ifnum = -1
+- }
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_RAW_BYTES(0) },
++ { QUIRK_DATA_IGNORE(1) },
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -2464,12 +1831,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ /* Emagic devices */
+ {
+ USB_DEVICE(0x086a, 0x0001),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Emagic",
+ .product_name = "Unitor8",
+- .ifnum = 2,
+- .type = QUIRK_MIDI_EMAGIC,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_EMAGIC(2) {
+ .out_cables = 0x80ff,
+ .in_cables = 0x80ff
+ }
+@@ -2477,12 +1842,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ },
+ {
+ USB_DEVICE(0x086a, 0x0002),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Emagic",
+ /* .product_name = "AMT8", */
+- .ifnum = 2,
+- .type = QUIRK_MIDI_EMAGIC,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_EMAGIC(2) {
+ .out_cables = 0x80ff,
+ .in_cables = 0x80ff
+ }
+@@ -2490,12 +1853,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ },
+ {
+ USB_DEVICE(0x086a, 0x0003),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Emagic",
+ /* .product_name = "MT4", */
+- .ifnum = 2,
+- .type = QUIRK_MIDI_EMAGIC,
+- .data = & (const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_EMAGIC(2) {
+ .out_cables = 0x800f,
+ .in_cables = 0x8003
+ }
+@@ -2505,38 +1866,35 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ /* KORG devices */
+ {
+ USB_DEVICE_VENDOR_SPEC(0x0944, 0x0200),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "KORG, Inc.",
+ /* .product_name = "PANDORA PX5D", */
+- .ifnum = 3,
+- .type = QUIRK_MIDI_STANDARD_INTERFACE,
++ QUIRK_DATA_STANDARD_MIDI(3)
+ }
+ },
+
+ {
+ USB_DEVICE_VENDOR_SPEC(0x0944, 0x0201),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "KORG, Inc.",
+ /* .product_name = "ToneLab ST", */
+- .ifnum = 3,
+- .type = QUIRK_MIDI_STANDARD_INTERFACE,
++ QUIRK_DATA_STANDARD_MIDI(3)
+ }
+ },
+
+ {
+ USB_DEVICE_VENDOR_SPEC(0x0944, 0x0204),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "KORG, Inc.",
+ /* .product_name = "ToneLab EX", */
+- .ifnum = 3,
+- .type = QUIRK_MIDI_STANDARD_INTERFACE,
++ QUIRK_DATA_STANDARD_MIDI(3)
+ }
+ },
+
+ /* AKAI devices */
+ {
+ USB_DEVICE(0x09e8, 0x0062),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "AKAI",
+ .product_name = "MPD16",
+ .ifnum = 0,
+@@ -2547,21 +1905,11 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+ /* Akai MPC Element */
+ USB_DEVICE(0x09e8, 0x0021),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = & (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 0,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
+- {
+- .ifnum = 1,
+- .type = QUIRK_MIDI_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = -1
+- }
++ QUIRK_DRIVER_INFO {
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_IGNORE(0) },
++ { QUIRK_DATA_STANDARD_MIDI(1) },
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -2570,66 +1918,36 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+ /* Steinberg MI2 */
+ USB_DEVICE_VENDOR_SPEC(0x0a4e, 0x2040),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = & (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 2,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
++ QUIRK_DRIVER_INFO {
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_STANDARD_AUDIO(0) },
++ { QUIRK_DATA_STANDARD_AUDIO(1) },
++ { QUIRK_DATA_STANDARD_AUDIO(2) },
+ {
+- .ifnum = 3,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = &(const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(3) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ {
+ /* Steinberg MI4 */
+ USB_DEVICE_VENDOR_SPEC(0x0a4e, 0x4040),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = & (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = 2,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
++ QUIRK_DRIVER_INFO {
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_STANDARD_AUDIO(0) },
++ { QUIRK_DATA_STANDARD_AUDIO(1) },
++ { QUIRK_DATA_STANDARD_AUDIO(2) },
+ {
+- .ifnum = 3,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = &(const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(3) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -2637,34 +1955,31 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ /* TerraTec devices */
+ {
+ USB_DEVICE_VENDOR_SPEC(0x0ccd, 0x0012),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "TerraTec",
+ .product_name = "PHASE 26",
+- .ifnum = 3,
+- .type = QUIRK_MIDI_STANDARD_INTERFACE
++ QUIRK_DATA_STANDARD_MIDI(3)
+ }
+ },
+ {
+ USB_DEVICE_VENDOR_SPEC(0x0ccd, 0x0013),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "TerraTec",
+ .product_name = "PHASE 26",
+- .ifnum = 3,
+- .type = QUIRK_MIDI_STANDARD_INTERFACE
++ QUIRK_DATA_STANDARD_MIDI(3)
+ }
+ },
+ {
+ USB_DEVICE_VENDOR_SPEC(0x0ccd, 0x0014),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "TerraTec",
+ .product_name = "PHASE 26",
+- .ifnum = 3,
+- .type = QUIRK_MIDI_STANDARD_INTERFACE
++ QUIRK_DATA_STANDARD_MIDI(3)
+ }
+ },
+ {
+ USB_DEVICE(0x0ccd, 0x0035),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Miditech",
+ .product_name = "Play'n Roll",
+ .ifnum = 0,
+@@ -2679,7 +1994,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ /* Novation EMS devices */
+ {
+ USB_DEVICE_VENDOR_SPEC(0x1235, 0x0001),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Novation",
+ .product_name = "ReMOTE Audio/XStation",
+ .ifnum = 4,
+@@ -2688,7 +2003,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ },
+ {
+ USB_DEVICE_VENDOR_SPEC(0x1235, 0x0002),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Novation",
+ .product_name = "Speedio",
+ .ifnum = 3,
+@@ -2697,38 +2012,29 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ },
+ {
+ USB_DEVICE(0x1235, 0x000a),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ /* .vendor_name = "Novation", */
+ /* .product_name = "Nocturn", */
+- .ifnum = 0,
+- .type = QUIRK_MIDI_RAW_BYTES
++ QUIRK_DATA_RAW_BYTES(0)
+ }
+ },
+ {
+ USB_DEVICE(0x1235, 0x000e),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ /* .vendor_name = "Novation", */
+ /* .product_name = "Launchpad", */
+- .ifnum = 0,
+- .type = QUIRK_MIDI_RAW_BYTES
++ QUIRK_DATA_RAW_BYTES(0)
+ }
+ },
+ {
+ USB_DEVICE(0x1235, 0x0010),
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Focusrite",
+ .product_name = "Saffire 6 USB",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_STANDARD_MIXER(0) },
+ {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_STANDARD_MIXER,
+- },
+- {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(0) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 4,
+ .iface = 0,
+@@ -2755,9 +2061,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ },
+ {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(0) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 2,
+ .iface = 0,
+@@ -2779,28 +2083,19 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ }
+ },
+- {
+- .ifnum = 1,
+- .type = QUIRK_MIDI_RAW_BYTES
+- },
+- {
+- .ifnum = -1
+- }
++ { QUIRK_DATA_RAW_BYTES(1) },
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ {
+ USB_DEVICE(0x1235, 0x0018),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Novation",
+ .product_name = "Twitch",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
++ QUIRK_DATA_COMPOSITE {
+ {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = & (const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(0) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 4,
+ .iface = 0,
+@@ -2819,19 +2114,14 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ }
+ },
+- {
+- .ifnum = 1,
+- .type = QUIRK_MIDI_RAW_BYTES
+- },
+- {
+- .ifnum = -1
+- }
++ { QUIRK_DATA_RAW_BYTES(1) },
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ {
+ USB_DEVICE_VENDOR_SPEC(0x1235, 0x4661),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Novation",
+ .product_name = "ReMOTE25",
+ .ifnum = 0,
+@@ -2843,25 +2133,16 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+ /* VirusTI Desktop */
+ USB_DEVICE_VENDOR_SPEC(0x133e, 0x0815),
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = &(const struct snd_usb_audio_quirk[]) {
++ QUIRK_DRIVER_INFO {
++ QUIRK_DATA_COMPOSITE {
+ {
+- .ifnum = 3,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = &(const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(3) {
+ .out_cables = 0x0003,
+ .in_cables = 0x0003
+ }
+ },
+- {
+- .ifnum = 4,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
+- {
+- .ifnum = -1
+- }
++ { QUIRK_DATA_IGNORE(4) },
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -2889,7 +2170,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ /* QinHeng devices */
+ {
+ USB_DEVICE(0x1a86, 0x752d),
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "QinHeng",
+ .product_name = "CH345",
+ .ifnum = 1,
+@@ -2903,7 +2184,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ /* Miditech devices */
+ {
+ USB_DEVICE(0x4752, 0x0011),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Miditech",
+ .product_name = "Midistart-2",
+ .ifnum = 0,
+@@ -2915,7 +2196,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+ /* this ID used by both Miditech MidiStudio-2 and CME UF-x */
+ USB_DEVICE(0x7104, 0x2202),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .ifnum = 0,
+ .type = QUIRK_MIDI_CME
+ }
+@@ -2925,20 +2206,13 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+ /* Thanks to Clemens Ladisch <clemens@ladisch.de> */
+ USB_DEVICE(0x0dba, 0x1000),
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Digidesign",
+ .product_name = "MBox",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]){
+- {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_STANDARD_MIXER,
+- },
++ QUIRK_DATA_COMPOSITE{
++ { QUIRK_DATA_STANDARD_MIXER(0) },
+ {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(1) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3BE,
+ .channels = 2,
+ .iface = 1,
+@@ -2959,9 +2233,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ },
+ {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(1) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3BE,
+ .channels = 2,
+ .iface = 1,
+@@ -2982,9 +2254,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -2992,24 +2262,14 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ /* DIGIDESIGN MBOX 2 */
+ {
+ USB_DEVICE(0x0dba, 0x3000),
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Digidesign",
+ .product_name = "Mbox 2",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 0,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
+- {
+- .ifnum = 1,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_IGNORE(0) },
++ { QUIRK_DATA_IGNORE(1) },
+ {
+- .ifnum = 2,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(2) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3BE,
+ .channels = 2,
+ .iface = 2,
+@@ -3027,15 +2287,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ }
+ },
++ { QUIRK_DATA_IGNORE(3) },
+ {
+- .ifnum = 3,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
+- {
+- .ifnum = 4,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
+- .formats = SNDRV_PCM_FMTBIT_S24_3BE,
++ QUIRK_DATA_AUDIOFORMAT(4) {
++ .formats = SNDRV_PCM_FMTBIT_S24_3BE,
+ .channels = 2,
+ .iface = 4,
+ .altsetting = 2,
+@@ -3052,14 +2307,9 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ }
+ },
++ { QUIRK_DATA_IGNORE(5) },
+ {
+- .ifnum = 5,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
+- {
+- .ifnum = 6,
+- .type = QUIRK_MIDI_MIDIMAN,
+- .data = &(const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_MIDIMAN(6) {
+ .out_ep = 0x02,
+ .out_cables = 0x0001,
+ .in_ep = 0x81,
+@@ -3067,33 +2317,21 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ .in_cables = 0x0001
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ /* DIGIDESIGN MBOX 3 */
+ {
+ USB_DEVICE(0x0dba, 0x5000),
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Digidesign",
+ .product_name = "Mbox 3",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 0,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_IGNORE(0) },
++ { QUIRK_DATA_IGNORE(1) },
+ {
+- .ifnum = 1,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
+- {
+- .ifnum = 2,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(2) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .fmt_bits = 24,
+ .channels = 4,
+@@ -3120,9 +2358,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ },
+ {
+- .ifnum = 3,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(3) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .fmt_bits = 24,
+ .channels = 4,
+@@ -3146,36 +2382,25 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ },
+ {
+- .ifnum = 4,
+- .type = QUIRK_MIDI_FIXED_ENDPOINT,
+- .data = &(const struct snd_usb_midi_endpoint_info) {
++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(4) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ {
+ /* Tascam US122 MKII - playback-only support */
+ USB_DEVICE_VENDOR_SPEC(0x0644, 0x8021),
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "TASCAM",
+ .product_name = "US122 MKII",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_IGNORE(0) },
+ {
+- .ifnum = 0,
+- .type = QUIRK_IGNORE_INTERFACE
+- },
+- {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(1) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 2,
+ .iface = 1,
+@@ -3196,9 +2421,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -3206,20 +2429,13 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ /* Denon DN-X1600 */
+ {
+ USB_AUDIO_DEVICE(0x154e, 0x500e),
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Denon",
+ .product_name = "DN-X1600",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]){
++ QUIRK_DATA_COMPOSITE{
++ { QUIRK_DATA_IGNORE(0) },
+ {
+- .ifnum = 0,
+- .type = QUIRK_IGNORE_INTERFACE,
+- },
+- {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(1) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 8,
+ .iface = 1,
+@@ -3240,9 +2456,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ },
+ {
+- .ifnum = 2,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(2) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 8,
+ .iface = 2,
+@@ -3262,13 +2476,8 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ }
+ },
+- {
+- .ifnum = 4,
+- .type = QUIRK_MIDI_STANDARD_INTERFACE,
+- },
+- {
+- .ifnum = -1
+- }
++ { QUIRK_DATA_STANDARD_MIDI(4) },
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -3277,17 +2486,13 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+ USB_DEVICE(0x045e, 0x0283),
+ .bInterfaceClass = USB_CLASS_PER_INTERFACE,
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Microsoft",
+ .product_name = "XboxLive Headset/Xbox Communicator",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = &(const struct snd_usb_audio_quirk[]) {
++ QUIRK_DATA_COMPOSITE {
+ {
+ /* playback */
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(0) {
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels = 1,
+ .iface = 0,
+@@ -3303,9 +2508,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ },
+ {
+ /* capture */
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(1) {
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels = 1,
+ .iface = 1,
+@@ -3319,9 +2522,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ .rate_max = 16000
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -3330,18 +2531,11 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+ USB_DEVICE(0x200c, 0x100b),
+ .bInterfaceClass = USB_CLASS_PER_INTERFACE,
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = &(const struct snd_usb_audio_quirk[]) {
++ QUIRK_DRIVER_INFO {
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_STANDARD_MIXER(0) },
+ {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_STANDARD_MIXER,
+- },
+- {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(1) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 4,
+ .iface = 1,
+@@ -3360,9 +2554,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -3375,28 +2567,12 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ * enabled in create_standard_audio_quirk().
+ */
+ USB_DEVICE(0x1686, 0x00dd),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
+- {
+- /* Playback */
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE,
+- },
+- {
+- /* Capture */
+- .ifnum = 2,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE,
+- },
+- {
+- /* Midi */
+- .ifnum = 3,
+- .type = QUIRK_MIDI_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = -1
+- },
++ QUIRK_DRIVER_INFO {
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_STANDARD_AUDIO(1) }, /* Playback */
++ { QUIRK_DATA_STANDARD_AUDIO(2) }, /* Capture */
++ { QUIRK_DATA_STANDARD_MIDI(3) }, /* Midi */
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -3410,18 +2586,16 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ USB_DEVICE_ID_MATCH_INT_SUBCLASS,
+ .bInterfaceClass = USB_CLASS_AUDIO,
+ .bInterfaceSubClass = USB_SUBCLASS_MIDISTREAMING,
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_MIDI_STANDARD_INTERFACE
++ QUIRK_DRIVER_INFO {
++ QUIRK_DATA_STANDARD_MIDI(QUIRK_ANY_INTERFACE)
+ }
+ },
+
+ /* Rane SL-1 */
+ {
+ USB_DEVICE(0x13e5, 0x0001),
+- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
++ QUIRK_DRIVER_INFO {
++ QUIRK_DATA_STANDARD_AUDIO(QUIRK_ANY_INTERFACE)
+ }
+ },
+
+@@ -3437,24 +2611,13 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ * and only the 48 kHz sample rate works for the playback interface.
+ */
+ USB_DEVICE(0x0a12, 0x1243),
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_STANDARD_MIXER,
+- },
+- /* Capture */
+- {
+- .ifnum = 1,
+- .type = QUIRK_IGNORE_INTERFACE,
+- },
++ QUIRK_DRIVER_INFO {
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_STANDARD_MIXER(0) },
++ { QUIRK_DATA_IGNORE(1) }, /* Capture */
+ /* Playback */
+ {
+- .ifnum = 2,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(2) {
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels = 2,
+ .iface = 2,
+@@ -3473,9 +2636,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ }
+ },
+- {
+- .ifnum = -1
+- },
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -3488,19 +2649,12 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ * even on windows.
+ */
+ USB_DEVICE(0x19b5, 0x0021),
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_STANDARD_MIXER,
+- },
++ QUIRK_DRIVER_INFO {
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_STANDARD_MIXER(0) },
+ /* Playback */
+ {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(1) {
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels = 2,
+ .iface = 1,
+@@ -3519,29 +2673,20 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ }
+ },
+- {
+- .ifnum = -1
+- },
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+ /* MOTU Microbook II */
+ {
+ USB_DEVICE_VENDOR_SPEC(0x07fd, 0x0004),
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "MOTU",
+ .product_name = "MicroBookII",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_STANDARD_MIXER,
+- },
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_STANDARD_MIXER(0) },
+ {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(0) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3BE,
+ .channels = 6,
+ .iface = 0,
+@@ -3562,9 +2707,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ },
+ {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(0) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3BE,
+ .channels = 8,
+ .iface = 0,
+@@ -3585,9 +2728,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -3599,14 +2740,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ * The feedback for the output is the input.
+ */
+ USB_DEVICE_VENDOR_SPEC(0x2b73, 0x0023),
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
++ QUIRK_DRIVER_INFO {
++ QUIRK_DATA_COMPOSITE {
+ {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(0) {
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .channels = 12,
+ .iface = 0,
+@@ -3623,9 +2760,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ },
+ {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(0) {
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .channels = 10,
+ .iface = 0,
+@@ -3643,9 +2778,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ .rate_table = (unsigned int[]) { 44100 }
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -3688,14 +2821,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ * but not for DVS (Digital Vinyl Systems) like in Mixxx.
+ */
+ USB_DEVICE_VENDOR_SPEC(0x2b73, 0x0017),
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
++ QUIRK_DRIVER_INFO {
++ QUIRK_DATA_COMPOSITE {
+ {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(0) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 8, // outputs
+ .iface = 0,
+@@ -3712,9 +2841,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ },
+ {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(0) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 8, // inputs
+ .iface = 0,
+@@ -3732,9 +2859,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ .rate_table = (unsigned int[]) { 48000 }
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -3745,14 +2870,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ * The feedback for the output is the dummy input.
+ */
+ USB_DEVICE_VENDOR_SPEC(0x2b73, 0x000e),
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
++ QUIRK_DRIVER_INFO {
++ QUIRK_DATA_COMPOSITE {
+ {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(0) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 4,
+ .iface = 0,
+@@ -3769,9 +2890,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ },
+ {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(0) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 2,
+ .iface = 0,
+@@ -3789,9 +2908,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ .rate_table = (unsigned int[]) { 44100 }
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -3802,14 +2919,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ * PCM is 6 channels out & 4 channels in @ 44.1 fixed
+ */
+ USB_DEVICE_VENDOR_SPEC(0x2b73, 0x000d),
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
++ QUIRK_DRIVER_INFO {
++ QUIRK_DATA_COMPOSITE {
+ {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(0) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 6, //Master, Headphones & Booth
+ .iface = 0,
+@@ -3826,9 +2939,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ },
+ {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(0) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 4, //2x RCA inputs (CH1 & CH2)
+ .iface = 0,
+@@ -3846,9 +2957,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ .rate_table = (unsigned int[]) { 44100 }
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -3860,14 +2969,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ * The Feedback for the output is the input
+ */
+ USB_DEVICE_VENDOR_SPEC(0x2b73, 0x001e),
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
++ QUIRK_DRIVER_INFO {
++ QUIRK_DATA_COMPOSITE {
+ {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(0) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 4,
+ .iface = 0,
+@@ -3884,9 +2989,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ },
+ {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(0) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 6,
+ .iface = 0,
+@@ -3904,9 +3007,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ .rate_table = (unsigned int[]) { 44100 }
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -3917,14 +3018,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ * 10 channels playback & 12 channels capture @ 44.1/48/96kHz S24LE
+ */
+ USB_DEVICE_VENDOR_SPEC(0x2b73, 0x000a),
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
++ QUIRK_DRIVER_INFO {
++ QUIRK_DATA_COMPOSITE {
+ {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(0) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 10,
+ .iface = 0,
+@@ -3945,9 +3042,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ },
+ {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(0) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 12,
+ .iface = 0,
+@@ -3969,9 +3064,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -3983,14 +3076,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ * The Feedback for the output is the input
+ */
+ USB_DEVICE_VENDOR_SPEC(0x2b73, 0x0029),
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
++ QUIRK_DRIVER_INFO {
++ QUIRK_DATA_COMPOSITE {
+ {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(0) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 6,
+ .iface = 0,
+@@ -4007,9 +3096,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ },
+ {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(0) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 6,
+ .iface = 0,
+@@ -4027,9 +3114,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ .rate_table = (unsigned int[]) { 44100 }
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -4047,20 +3132,13 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ */
+ {
+ USB_AUDIO_DEVICE(0x534d, 0x0021),
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "MacroSilicon",
+ .product_name = "MS210x",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = &(const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 2,
+- .type = QUIRK_AUDIO_STANDARD_MIXER,
+- },
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_STANDARD_MIXER(2) },
+ {
+- .ifnum = 3,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(3) {
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels = 2,
+ .iface = 3,
+@@ -4075,9 +3153,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ .rate_max = 48000,
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -4095,20 +3171,13 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ */
+ {
+ USB_AUDIO_DEVICE(0x534d, 0x2109),
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "MacroSilicon",
+ .product_name = "MS2109",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = &(const struct snd_usb_audio_quirk[]) {
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_STANDARD_MIXER(2) },
+ {
+- .ifnum = 2,
+- .type = QUIRK_AUDIO_STANDARD_MIXER,
+- },
+- {
+- .ifnum = 3,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(3) {
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels = 2,
+ .iface = 3,
+@@ -4123,9 +3192,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ .rate_max = 48000,
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -4135,14 +3202,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ * 8 channels playback & 8 channels capture @ 44.1/48/96kHz S24LE
+ */
+ USB_DEVICE_VENDOR_SPEC(0x08e4, 0x017f),
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
++ QUIRK_DRIVER_INFO {
++ QUIRK_DATA_COMPOSITE {
+ {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(0) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 8,
+ .iface = 0,
+@@ -4161,9 +3224,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ },
+ {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(0) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 8,
+ .iface = 0,
+@@ -4183,9 +3244,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ .rate_table = (unsigned int[]) { 44100, 48000, 96000 }
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -4195,14 +3254,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ * 10 channels playback & 12 channels capture @ 48kHz S24LE
+ */
+ USB_DEVICE_VENDOR_SPEC(0x2b73, 0x001b),
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
++ QUIRK_DRIVER_INFO {
++ QUIRK_DATA_COMPOSITE {
+ {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(0) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 10,
+ .iface = 0,
+@@ -4221,9 +3276,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ },
+ {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(0) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 12,
+ .iface = 0,
+@@ -4241,9 +3294,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ .rate_table = (unsigned int[]) { 48000 }
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -4255,14 +3306,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ * Capture on EP 0x86
+ */
+ USB_DEVICE_VENDOR_SPEC(0x08e4, 0x0163),
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
++ QUIRK_DRIVER_INFO {
++ QUIRK_DATA_COMPOSITE {
+ {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(0) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 8,
+ .iface = 0,
+@@ -4282,9 +3329,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ },
+ {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(0) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 8,
+ .iface = 0,
+@@ -4304,9 +3349,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ .rate_table = (unsigned int[]) { 44100, 48000, 96000 }
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -4317,14 +3360,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ * and 8 channels in @ 48 fixed (endpoint 0x82).
+ */
+ USB_DEVICE_VENDOR_SPEC(0x2b73, 0x0013),
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
++ QUIRK_DRIVER_INFO {
++ QUIRK_DATA_COMPOSITE {
+ {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(0) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 8, // outputs
+ .iface = 0,
+@@ -4341,9 +3380,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ },
+ {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(0) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 8, // inputs
+ .iface = 0,
+@@ -4361,9 +3398,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ .rate_table = (unsigned int[]) { 48000 }
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -4374,28 +3409,15 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ */
+ USB_DEVICE(0x1395, 0x0300),
+ .bInterfaceClass = USB_CLASS_PER_INTERFACE,
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = &(const struct snd_usb_audio_quirk[]) {
++ QUIRK_DRIVER_INFO {
++ QUIRK_DATA_COMPOSITE {
+ // Communication
+- {
+- .ifnum = 3,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
++ { QUIRK_DATA_STANDARD_AUDIO(3) },
+ // Recording
+- {
+- .ifnum = 4,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
++ { QUIRK_DATA_STANDARD_AUDIO(4) },
+ // Main
+- {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
+- {
+- .ifnum = -1
+- }
++ { QUIRK_DATA_STANDARD_AUDIO(1) },
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -4404,21 +3426,14 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ * Fiero SC-01 (firmware v1.0.0 @ 48 kHz)
+ */
+ USB_DEVICE(0x2b53, 0x0023),
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Fiero",
+ .product_name = "SC-01",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = &(const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_STANDARD_AUDIO(0) },
+ /* Playback */
+ {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(1) {
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .channels = 2,
+ .fmt_bits = 24,
+@@ -4438,9 +3453,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ },
+ /* Capture */
+ {
+- .ifnum = 2,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(2) {
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .channels = 2,
+ .fmt_bits = 24,
+@@ -4459,9 +3472,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ .clock = 0x29
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -4470,21 +3481,14 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ * Fiero SC-01 (firmware v1.0.0 @ 96 kHz)
+ */
+ USB_DEVICE(0x2b53, 0x0024),
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Fiero",
+ .product_name = "SC-01",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = &(const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_STANDARD_AUDIO(0) },
+ /* Playback */
+ {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(1) {
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .channels = 2,
+ .fmt_bits = 24,
+@@ -4504,9 +3508,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ },
+ /* Capture */
+ {
+- .ifnum = 2,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(2) {
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .channels = 2,
+ .fmt_bits = 24,
+@@ -4525,9 +3527,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ .clock = 0x29
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -4536,21 +3536,14 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ * Fiero SC-01 (firmware v1.1.0)
+ */
+ USB_DEVICE(0x2b53, 0x0031),
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Fiero",
+ .product_name = "SC-01",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = &(const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 0,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+- },
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_STANDARD_AUDIO(0) },
+ /* Playback */
+ {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(1) {
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .channels = 2,
+ .fmt_bits = 24,
+@@ -4571,9 +3564,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ },
+ /* Capture */
+ {
+- .ifnum = 2,
+- .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+- .data = &(const struct audioformat) {
++ QUIRK_DATA_AUDIOFORMAT(2) {
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .channels = 2,
+ .fmt_bits = 24,
+@@ -4593,9 +3584,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ .clock = 0x29
+ }
+ },
+- {
+- .ifnum = -1
+- }
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+@@ -4604,27 +3593,14 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ * For the standard mode, Mythware XA001AU has ID ffad:a001
+ */
+ USB_DEVICE_VENDOR_SPEC(0xffad, 0xa001),
+- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++ QUIRK_DRIVER_INFO {
+ .vendor_name = "Mythware",
+ .product_name = "XA001AU",
+- .ifnum = QUIRK_ANY_INTERFACE,
+- .type = QUIRK_COMPOSITE,
+- .data = (const struct snd_usb_audio_quirk[]) {
+- {
+- .ifnum = 0,
+- .type = QUIRK_IGNORE_INTERFACE,
+- },
+- {
+- .ifnum = 1,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE,
+- },
+- {
+- .ifnum = 2,
+- .type = QUIRK_AUDIO_STANDARD_INTERFACE,
+- },
+- {
+- .ifnum = -1
+- }
++ QUIRK_DATA_COMPOSITE {
++ { QUIRK_DATA_IGNORE(0) },
++ { QUIRK_DATA_STANDARD_AUDIO(1) },
++ { QUIRK_DATA_STANDARD_AUDIO(2) },
++ QUIRK_COMPOSITE_END
+ }
+ }
+ },
+--
+2.43.0
+
--- /dev/null
+From 1900d66454dede84d5e1cdca46b1443b272293a3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 11 Aug 2024 17:29:56 -0700
+Subject: ALSA: usb-audio: Support multiple control interfaces
+
+From: Karol Kosik <k.kosik@outlook.com>
+
+[ Upstream commit 6aa8700150f7dc62f60b4cf5b1624e2e3d9ed78e ]
+
+Registering Numark Party Mix II fails with error 'bogus bTerminalLink 1'.
+The problem stems from the driver not being able to find input/output
+terminals required to configure audio streaming. The information about
+those terminals is stored in AudioControl Interface. Numark device
+contains 2 AudioControl Interfaces and the driver checks only one of them.
+
+According to the USB standard, a device can have multiple audio functions,
+each represented by Audio Interface Collection. Every audio function is
+considered to be closed box and will contain unique AudioControl Interface
+and zero or more AudioStreaming and MIDIStreaming Interfaces.
+
+The Numark device adheres to the standard and defines two audio functions:
+- MIDIStreaming function
+- AudioStreaming function
+It starts with MIDI function, followed by the audio function. The driver
+saves the first AudioControl Interface in `snd_usb_audio` structure
+associated with the entire device. It then attempts to use this interface
+to query for terminals and clocks. However, this fails because the correct
+information is stored in the second AudioControl Interface, defined in the
+second Audio Interface Collection.
+
+This patch introduces a structure holding association between each
+MIDI/Audio Interface and its corresponding AudioControl Interface,
+instead of relying on AudioControl Interface defined for the entire
+device. This structure is populated during usb probing phase and leveraged
+later when querying for terminals and when sending USB requests.
+
+Alternative solutions considered include:
+- defining a quirk for Numark where the order of interface is manually
+changed, or terminals are hardcoded in the driver. This solution would
+have fixed only this model, though it seems that device is USB compliant,
+and it also seems that other devices from this company may be affected.
+What's more, it looks like products from other manufacturers have similar
+problems, i.e. Rane One DJ console
+- keeping a list of all AudioControl Interfaces and querying all of them
+to find required information. That would have solved my problem and have
+low probability of breaking other devices, as we would always start with
+the same logic of querying first AudioControl Interface. This solution
+would not have followed the standard though.
+
+This patch preserves the `snd_usb_audio.ctrl_intf` variable, which holds
+the first AudioControl Interface, and uses it as a fallback when some
+interfaces are not parsed correctly and lack an associated AudioControl
+Interface, i.e., when configured via quirks.
+
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=217865
+Signed-off-by: Karol Kosik <k.kosik@outlook.com>
+Link: https://patch.msgid.link/AS8P190MB1285893F4735C8B32AD3886BEC852@AS8P190MB1285.EURP190.PROD.OUTLOOK.COM
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/usb/card.c | 2 ++
+ sound/usb/clock.c | 62 ++++++++++++++++++++++++--------------
+ sound/usb/format.c | 6 ++--
+ sound/usb/helper.c | 34 +++++++++++++++++++++
+ sound/usb/helper.h | 10 ++++--
+ sound/usb/mixer.c | 2 +-
+ sound/usb/mixer_quirks.c | 17 ++++++-----
+ sound/usb/mixer_scarlett.c | 4 +--
+ sound/usb/power.c | 3 +-
+ sound/usb/power.h | 1 +
+ sound/usb/stream.c | 21 ++++++++-----
+ sound/usb/usbaudio.h | 12 ++++++++
+ 12 files changed, 127 insertions(+), 47 deletions(-)
+
+diff --git a/sound/usb/card.c b/sound/usb/card.c
+index bdb04fa37a71d..778de9244f1e7 100644
+--- a/sound/usb/card.c
++++ b/sound/usb/card.c
+@@ -206,6 +206,8 @@ static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int int
+ return -EINVAL;
+ }
+
++ snd_usb_add_ctrl_interface_link(chip, interface, ctrlif);
++
+ if (! snd_usb_parse_audio_interface(chip, interface)) {
+ usb_set_interface(dev, interface, 0); /* reset the current interface */
+ return usb_driver_claim_interface(&usb_audio_driver, iface,
+diff --git a/sound/usb/clock.c b/sound/usb/clock.c
+index 60fcb872a80b6..8f85200292f3f 100644
+--- a/sound/usb/clock.c
++++ b/sound/usb/clock.c
+@@ -76,11 +76,14 @@ static bool validate_clock_multiplier(void *p, int id, int proto)
+ }
+
+ #define DEFINE_FIND_HELPER(name, obj, validator, type2, type3) \
+-static obj *name(struct snd_usb_audio *chip, int id, int proto) \
++static obj *name(struct snd_usb_audio *chip, int id, \
++ const struct audioformat *fmt) \
+ { \
+- return find_uac_clock_desc(chip->ctrl_intf, id, validator, \
+- proto == UAC_VERSION_3 ? (type3) : (type2), \
+- proto); \
++ struct usb_host_interface *ctrl_intf = \
++ snd_usb_find_ctrl_interface(chip, fmt->iface); \
++ return find_uac_clock_desc(ctrl_intf, id, validator, \
++ fmt->protocol == UAC_VERSION_3 ? (type3) : (type2), \
++ fmt->protocol); \
+ }
+
+ DEFINE_FIND_HELPER(snd_usb_find_clock_source,
+@@ -93,16 +96,19 @@ DEFINE_FIND_HELPER(snd_usb_find_clock_multiplier,
+ union uac23_clock_multiplier_desc, validate_clock_multiplier,
+ UAC2_CLOCK_MULTIPLIER, UAC3_CLOCK_MULTIPLIER);
+
+-static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_id)
++static int uac_clock_selector_get_val(struct snd_usb_audio *chip,
++ int selector_id, int iface_no)
+ {
++ struct usb_host_interface *ctrl_intf;
+ unsigned char buf;
+ int ret;
+
++ ctrl_intf = snd_usb_find_ctrl_interface(chip, iface_no);
+ ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0),
+ UAC2_CS_CUR,
+ USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+ UAC2_CX_CLOCK_SELECTOR << 8,
+- snd_usb_ctrl_intf(chip) | (selector_id << 8),
++ snd_usb_ctrl_intf(ctrl_intf) | (selector_id << 8),
+ &buf, sizeof(buf));
+
+ if (ret < 0)
+@@ -111,16 +117,18 @@ static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_i
+ return buf;
+ }
+
+-static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_id,
+- unsigned char pin)
++static int uac_clock_selector_set_val(struct snd_usb_audio *chip,
++ int selector_id, unsigned char pin, int iface_no)
+ {
++ struct usb_host_interface *ctrl_intf;
+ int ret;
+
++ ctrl_intf = snd_usb_find_ctrl_interface(chip, iface_no);
+ ret = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0),
+ UAC2_CS_CUR,
+ USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+ UAC2_CX_CLOCK_SELECTOR << 8,
+- snd_usb_ctrl_intf(chip) | (selector_id << 8),
++ snd_usb_ctrl_intf(ctrl_intf) | (selector_id << 8),
+ &pin, sizeof(pin));
+ if (ret < 0)
+ return ret;
+@@ -132,7 +140,7 @@ static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_i
+ return -EINVAL;
+ }
+
+- ret = uac_clock_selector_get_val(chip, selector_id);
++ ret = uac_clock_selector_get_val(chip, selector_id, iface_no);
+ if (ret < 0)
+ return ret;
+
+@@ -155,8 +163,10 @@ static bool uac_clock_source_is_valid_quirk(struct snd_usb_audio *chip,
+ unsigned char data;
+ struct usb_device *dev = chip->dev;
+ union uac23_clock_source_desc *cs_desc;
++ struct usb_host_interface *ctrl_intf;
+
+- cs_desc = snd_usb_find_clock_source(chip, source_id, fmt->protocol);
++ ctrl_intf = snd_usb_find_ctrl_interface(chip, fmt->iface);
++ cs_desc = snd_usb_find_clock_source(chip, source_id, fmt);
+ if (!cs_desc)
+ return false;
+
+@@ -191,7 +201,7 @@ static bool uac_clock_source_is_valid_quirk(struct snd_usb_audio *chip,
+ err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+ UAC2_CS_CONTROL_CLOCK_VALID << 8,
+- snd_usb_ctrl_intf(chip) | (source_id << 8),
++ snd_usb_ctrl_intf(ctrl_intf) | (source_id << 8),
+ &data, sizeof(data));
+ if (err < 0) {
+ dev_warn(&dev->dev,
+@@ -217,8 +227,10 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip,
+ struct usb_device *dev = chip->dev;
+ u32 bmControls;
+ union uac23_clock_source_desc *cs_desc;
++ struct usb_host_interface *ctrl_intf;
+
+- cs_desc = snd_usb_find_clock_source(chip, source_id, fmt->protocol);
++ ctrl_intf = snd_usb_find_ctrl_interface(chip, fmt->iface);
++ cs_desc = snd_usb_find_clock_source(chip, source_id, fmt);
+ if (!cs_desc)
+ return false;
+
+@@ -235,7 +247,7 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip,
+ err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+ UAC2_CS_CONTROL_CLOCK_VALID << 8,
+- snd_usb_ctrl_intf(chip) | (source_id << 8),
++ snd_usb_ctrl_intf(ctrl_intf) | (source_id << 8),
+ &data, sizeof(data));
+
+ if (err < 0) {
+@@ -274,7 +286,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
+ }
+
+ /* first, see if the ID we're looking at is a clock source already */
+- source = snd_usb_find_clock_source(chip, entity_id, proto);
++ source = snd_usb_find_clock_source(chip, entity_id, fmt);
+ if (source) {
+ entity_id = GET_VAL(source, proto, bClockID);
+ if (validate && !uac_clock_source_is_valid(chip, fmt,
+@@ -287,7 +299,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
+ return entity_id;
+ }
+
+- selector = snd_usb_find_clock_selector(chip, entity_id, proto);
++ selector = snd_usb_find_clock_selector(chip, entity_id, fmt);
+ if (selector) {
+ pins = GET_VAL(selector, proto, bNrInPins);
+ clock_id = GET_VAL(selector, proto, bClockID);
+@@ -317,7 +329,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
+
+ /* the entity ID we are looking at is a selector.
+ * find out what it currently selects */
+- ret = uac_clock_selector_get_val(chip, clock_id);
++ ret = uac_clock_selector_get_val(chip, clock_id, fmt->iface);
+ if (ret < 0) {
+ if (!chip->autoclock)
+ return ret;
+@@ -346,7 +358,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
+ if (chip->quirk_flags & QUIRK_FLAG_SKIP_CLOCK_SELECTOR ||
+ !writeable)
+ return ret;
+- err = uac_clock_selector_set_val(chip, entity_id, cur);
++ err = uac_clock_selector_set_val(chip, entity_id, cur, fmt->iface);
+ if (err < 0) {
+ if (pins == 1) {
+ usb_audio_dbg(chip,
+@@ -377,7 +389,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
+ if (ret < 0)
+ continue;
+
+- err = uac_clock_selector_set_val(chip, entity_id, i);
++ err = uac_clock_selector_set_val(chip, entity_id, i, fmt->iface);
+ if (err < 0)
+ continue;
+
+@@ -391,7 +403,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
+ }
+
+ /* FIXME: multipliers only act as pass-thru element for now */
+- multiplier = snd_usb_find_clock_multiplier(chip, entity_id, proto);
++ multiplier = snd_usb_find_clock_multiplier(chip, entity_id, fmt);
+ if (multiplier)
+ return __uac_clock_find_source(chip, fmt,
+ GET_VAL(multiplier, proto, bCSourceID),
+@@ -491,11 +503,13 @@ static int get_sample_rate_v2v3(struct snd_usb_audio *chip, int iface,
+ struct usb_device *dev = chip->dev;
+ __le32 data;
+ int err;
++ struct usb_host_interface *ctrl_intf;
+
++ ctrl_intf = snd_usb_find_ctrl_interface(chip, iface);
+ err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+ UAC2_CS_CONTROL_SAM_FREQ << 8,
+- snd_usb_ctrl_intf(chip) | (clock << 8),
++ snd_usb_ctrl_intf(ctrl_intf) | (clock << 8),
+ &data, sizeof(data));
+ if (err < 0) {
+ dev_warn(&dev->dev, "%d:%d: cannot get freq (v2/v3): err %d\n",
+@@ -524,8 +538,10 @@ int snd_usb_set_sample_rate_v2v3(struct snd_usb_audio *chip,
+ __le32 data;
+ int err;
+ union uac23_clock_source_desc *cs_desc;
++ struct usb_host_interface *ctrl_intf;
+
+- cs_desc = snd_usb_find_clock_source(chip, clock, fmt->protocol);
++ ctrl_intf = snd_usb_find_ctrl_interface(chip, fmt->iface);
++ cs_desc = snd_usb_find_clock_source(chip, clock, fmt);
+
+ if (!cs_desc)
+ return 0;
+@@ -544,7 +560,7 @@ int snd_usb_set_sample_rate_v2v3(struct snd_usb_audio *chip,
+ err = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), UAC2_CS_CUR,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
+ UAC2_CS_CONTROL_SAM_FREQ << 8,
+- snd_usb_ctrl_intf(chip) | (clock << 8),
++ snd_usb_ctrl_intf(ctrl_intf) | (clock << 8),
+ &data, sizeof(data));
+ if (err < 0)
+ return err;
+diff --git a/sound/usb/format.c b/sound/usb/format.c
+index 3b45d0ee76938..61c4aca8be09e 100644
+--- a/sound/usb/format.c
++++ b/sound/usb/format.c
+@@ -548,7 +548,9 @@ static int parse_audio_format_rates_v2v3(struct snd_usb_audio *chip,
+ unsigned char tmp[2], *data;
+ int nr_triplets, data_size, ret = 0, ret_l6;
+ int clock = snd_usb_clock_find_source(chip, fp, false);
++ struct usb_host_interface *ctrl_intf;
+
++ ctrl_intf = snd_usb_find_ctrl_interface(chip, fp->iface);
+ if (clock < 0) {
+ dev_err(&dev->dev,
+ "%s(): unable to find clock source (clock %d)\n",
+@@ -560,7 +562,7 @@ static int parse_audio_format_rates_v2v3(struct snd_usb_audio *chip,
+ ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+ UAC2_CS_CONTROL_SAM_FREQ << 8,
+- snd_usb_ctrl_intf(chip) | (clock << 8),
++ snd_usb_ctrl_intf(ctrl_intf) | (clock << 8),
+ tmp, sizeof(tmp));
+
+ if (ret < 0) {
+@@ -595,7 +597,7 @@ static int parse_audio_format_rates_v2v3(struct snd_usb_audio *chip,
+ ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+ UAC2_CS_CONTROL_SAM_FREQ << 8,
+- snd_usb_ctrl_intf(chip) | (clock << 8),
++ snd_usb_ctrl_intf(ctrl_intf) | (clock << 8),
+ data, data_size);
+
+ if (ret < 0) {
+diff --git a/sound/usb/helper.c b/sound/usb/helper.c
+index bf80e55d013a8..72b671fb2c84c 100644
+--- a/sound/usb/helper.c
++++ b/sound/usb/helper.c
+@@ -130,3 +130,37 @@ snd_usb_get_host_interface(struct snd_usb_audio *chip, int ifnum, int altsetting
+ return NULL;
+ return usb_altnum_to_altsetting(iface, altsetting);
+ }
++
++int snd_usb_add_ctrl_interface_link(struct snd_usb_audio *chip, int ifnum,
++ int ctrlif)
++{
++ struct usb_device *dev = chip->dev;
++ struct usb_host_interface *host_iface;
++
++ if (chip->num_intf_to_ctrl >= MAX_CARD_INTERFACES) {
++ dev_info(&dev->dev, "Too many interfaces assigned to the single USB-audio card\n");
++ return -EINVAL;
++ }
++
++ /* find audiocontrol interface */
++ host_iface = &usb_ifnum_to_if(dev, ctrlif)->altsetting[0];
++
++ chip->intf_to_ctrl[chip->num_intf_to_ctrl].interface = ifnum;
++ chip->intf_to_ctrl[chip->num_intf_to_ctrl].ctrl_intf = host_iface;
++ chip->num_intf_to_ctrl++;
++
++ return 0;
++}
++
++struct usb_host_interface *snd_usb_find_ctrl_interface(struct snd_usb_audio *chip,
++ int ifnum)
++{
++ int i;
++
++ for (i = 0; i < chip->num_intf_to_ctrl; ++i)
++ if (chip->intf_to_ctrl[i].interface == ifnum)
++ return chip->intf_to_ctrl[i].ctrl_intf;
++
++ /* Fallback to first audiocontrol interface */
++ return chip->ctrl_intf;
++}
+diff --git a/sound/usb/helper.h b/sound/usb/helper.h
+index e2b51ec96ec62..0372e050b3dc4 100644
+--- a/sound/usb/helper.h
++++ b/sound/usb/helper.h
+@@ -17,6 +17,12 @@ unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip,
+ struct usb_host_interface *
+ snd_usb_get_host_interface(struct snd_usb_audio *chip, int ifnum, int altsetting);
+
++int snd_usb_add_ctrl_interface_link(struct snd_usb_audio *chip, int ifnum,
++ int ctrlif);
++
++struct usb_host_interface *snd_usb_find_ctrl_interface(struct snd_usb_audio *chip,
++ int ifnum);
++
+ /*
+ * retrieve usb_interface descriptor from the host interface
+ * (conditional for compatibility with the older API)
+@@ -28,9 +34,9 @@ snd_usb_get_host_interface(struct snd_usb_audio *chip, int ifnum, int altsetting
+
+ #define snd_usb_get_speed(dev) ((dev)->speed)
+
+-static inline int snd_usb_ctrl_intf(struct snd_usb_audio *chip)
++static inline int snd_usb_ctrl_intf(struct usb_host_interface *ctrl_intf)
+ {
+- return get_iface_desc(chip->ctrl_intf)->bInterfaceNumber;
++ return get_iface_desc(ctrl_intf)->bInterfaceNumber;
+ }
+
+ /* in validate.c */
+diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
+index 197fd07e69edd..017b50322d88f 100644
+--- a/sound/usb/mixer.c
++++ b/sound/usb/mixer.c
+@@ -728,7 +728,7 @@ static int get_cluster_channels_v3(struct mixer_build *state, unsigned int clust
+ UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR,
+ USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+ cluster_id,
+- snd_usb_ctrl_intf(state->chip),
++ snd_usb_ctrl_intf(state->mixer->hostif),
+ &c_header, sizeof(c_header));
+ if (err < 0)
+ goto error;
+diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
+index 212b5e6443d88..1d8bf1ecfed44 100644
+--- a/sound/usb/mixer_quirks.c
++++ b/sound/usb/mixer_quirks.c
+@@ -1043,7 +1043,7 @@ static int snd_ftu_eff_switch_init(struct usb_mixer_interface *mixer,
+ err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR,
+ USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+ pval & 0xff00,
+- snd_usb_ctrl_intf(mixer->chip) | ((pval & 0xff) << 8),
++ snd_usb_ctrl_intf(mixer->hostif) | ((pval & 0xff) << 8),
+ value, 2);
+ if (err < 0)
+ return err;
+@@ -1077,7 +1077,7 @@ static int snd_ftu_eff_switch_update(struct usb_mixer_elem_list *list)
+ UAC_SET_CUR,
+ USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+ pval & 0xff00,
+- snd_usb_ctrl_intf(chip) | ((pval & 0xff) << 8),
++ snd_usb_ctrl_intf(list->mixer->hostif) | ((pval & 0xff) << 8),
+ value, 2);
+ snd_usb_unlock_shutdown(chip);
+ return err;
+@@ -2115,24 +2115,25 @@ static int dell_dock_mixer_create(struct usb_mixer_interface *mixer)
+ return 0;
+ }
+
+-static void dell_dock_init_vol(struct snd_usb_audio *chip, int ch, int id)
++static void dell_dock_init_vol(struct usb_mixer_interface *mixer, int ch, int id)
+ {
++ struct snd_usb_audio *chip = mixer->chip;
+ u16 buf = 0;
+
+ snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR,
+ USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+ (UAC_FU_VOLUME << 8) | ch,
+- snd_usb_ctrl_intf(chip) | (id << 8),
++ snd_usb_ctrl_intf(mixer->hostif) | (id << 8),
+ &buf, 2);
+ }
+
+ static int dell_dock_mixer_init(struct usb_mixer_interface *mixer)
+ {
+ /* fix to 0dB playback volumes */
+- dell_dock_init_vol(mixer->chip, 1, 16);
+- dell_dock_init_vol(mixer->chip, 2, 16);
+- dell_dock_init_vol(mixer->chip, 1, 19);
+- dell_dock_init_vol(mixer->chip, 2, 19);
++ dell_dock_init_vol(mixer, 1, 16);
++ dell_dock_init_vol(mixer, 2, 16);
++ dell_dock_init_vol(mixer, 1, 19);
++ dell_dock_init_vol(mixer, 2, 19);
+ return 0;
+ }
+
+diff --git a/sound/usb/mixer_scarlett.c b/sound/usb/mixer_scarlett.c
+index 0d6e4f15bf77c..ff548041679bb 100644
+--- a/sound/usb/mixer_scarlett.c
++++ b/sound/usb/mixer_scarlett.c
+@@ -460,7 +460,7 @@ static int scarlett_ctl_meter_get(struct snd_kcontrol *kctl,
+ struct snd_usb_audio *chip = elem->head.mixer->chip;
+ unsigned char buf[2 * MAX_CHANNELS] = {0, };
+ int wValue = (elem->control << 8) | elem->idx_off;
+- int idx = snd_usb_ctrl_intf(chip) | (elem->head.id << 8);
++ int idx = snd_usb_ctrl_intf(elem->head.mixer->hostif) | (elem->head.id << 8);
+ int err;
+
+ err = snd_usb_ctl_msg(chip->dev,
+@@ -1002,7 +1002,7 @@ int snd_scarlett_controls_create(struct usb_mixer_interface *mixer)
+ err = snd_usb_ctl_msg(mixer->chip->dev,
+ usb_sndctrlpipe(mixer->chip->dev, 0), UAC2_CS_CUR,
+ USB_RECIP_INTERFACE | USB_TYPE_CLASS |
+- USB_DIR_OUT, 0x0100, snd_usb_ctrl_intf(mixer->chip) |
++ USB_DIR_OUT, 0x0100, snd_usb_ctrl_intf(mixer->hostif) |
+ (0x29 << 8), sample_rate_buffer, 4);
+ if (err < 0)
+ return err;
+diff --git a/sound/usb/power.c b/sound/usb/power.c
+index 606a2cb23eab6..66bd4daa68fd5 100644
+--- a/sound/usb/power.c
++++ b/sound/usb/power.c
+@@ -40,6 +40,7 @@ snd_usb_find_power_domain(struct usb_host_interface *ctrl_iface,
+ le16_to_cpu(pd_desc->waRecoveryTime1);
+ pd->pd_d2d0_rec =
+ le16_to_cpu(pd_desc->waRecoveryTime2);
++ pd->ctrl_iface = ctrl_iface;
+ return pd;
+ }
+ }
+@@ -57,7 +58,7 @@ int snd_usb_power_domain_set(struct snd_usb_audio *chip,
+ unsigned char current_state;
+ int err, idx;
+
+- idx = snd_usb_ctrl_intf(chip) | (pd->pd_id << 8);
++ idx = snd_usb_ctrl_intf(pd->ctrl_iface) | (pd->pd_id << 8);
+
+ err = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0),
+ UAC2_CS_CUR,
+diff --git a/sound/usb/power.h b/sound/usb/power.h
+index 396e3e51440a7..1fa92ad0ca925 100644
+--- a/sound/usb/power.h
++++ b/sound/usb/power.h
+@@ -6,6 +6,7 @@ struct snd_usb_power_domain {
+ int pd_id; /* UAC3 Power Domain ID */
+ int pd_d1d0_rec; /* D1 to D0 recovery time */
+ int pd_d2d0_rec; /* D2 to D0 recovery time */
++ struct usb_host_interface *ctrl_iface; /* Control interface */
+ };
+
+ enum {
+diff --git a/sound/usb/stream.c b/sound/usb/stream.c
+index e14c725acebf2..d70c140813d68 100644
+--- a/sound/usb/stream.c
++++ b/sound/usb/stream.c
+@@ -713,10 +713,13 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
+ struct usb_device *dev = chip->dev;
+ struct uac_format_type_i_continuous_descriptor *fmt;
+ unsigned int num_channels = 0, chconfig = 0;
++ struct usb_host_interface *ctrl_intf;
+ struct audioformat *fp;
+ int clock = 0;
+ u64 format;
+
++ ctrl_intf = snd_usb_find_ctrl_interface(chip, iface_no);
++
+ /* get audio formats */
+ if (protocol == UAC_VERSION_1) {
+ struct uac1_as_header_descriptor *as =
+@@ -740,7 +743,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
+
+ format = le16_to_cpu(as->wFormatTag); /* remember the format value */
+
+- iterm = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
++ iterm = snd_usb_find_input_terminal_descriptor(ctrl_intf,
+ as->bTerminalLink,
+ protocol);
+ if (iterm) {
+@@ -776,7 +779,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
+ * lookup the terminal associated to this interface
+ * to extract the clock
+ */
+- input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
++ input_term = snd_usb_find_input_terminal_descriptor(ctrl_intf,
+ as->bTerminalLink,
+ protocol);
+ if (input_term) {
+@@ -786,7 +789,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
+ goto found_clock;
+ }
+
+- output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf,
++ output_term = snd_usb_find_output_terminal_descriptor(ctrl_intf,
+ as->bTerminalLink,
+ protocol);
+ if (output_term) {
+@@ -870,6 +873,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
+ struct uac3_cluster_header_descriptor *cluster;
+ struct uac3_as_header_descriptor *as = NULL;
+ struct uac3_hc_descriptor_header hc_header;
++ struct usb_host_interface *ctrl_intf;
+ struct snd_pcm_chmap_elem *chmap;
+ struct snd_usb_power_domain *pd;
+ unsigned char badd_profile;
+@@ -881,6 +885,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
+ int err;
+
+ badd_profile = chip->badd_profile;
++ ctrl_intf = snd_usb_find_ctrl_interface(chip, iface_no);
+
+ if (badd_profile >= UAC3_FUNCTION_SUBCLASS_GENERIC_IO) {
+ unsigned int maxpacksize =
+@@ -966,7 +971,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
+ UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR,
+ USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+ cluster_id,
+- snd_usb_ctrl_intf(chip),
++ snd_usb_ctrl_intf(ctrl_intf),
+ &hc_header, sizeof(hc_header));
+ if (err < 0)
+ return ERR_PTR(err);
+@@ -990,7 +995,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
+ UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR,
+ USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+ cluster_id,
+- snd_usb_ctrl_intf(chip),
++ snd_usb_ctrl_intf(ctrl_intf),
+ cluster, wLength);
+ if (err < 0) {
+ kfree(cluster);
+@@ -1011,7 +1016,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
+ * lookup the terminal associated to this interface
+ * to extract the clock
+ */
+- input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
++ input_term = snd_usb_find_input_terminal_descriptor(ctrl_intf,
+ as->bTerminalLink,
+ UAC_VERSION_3);
+ if (input_term) {
+@@ -1019,7 +1024,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
+ goto found_clock;
+ }
+
+- output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf,
++ output_term = snd_usb_find_output_terminal_descriptor(ctrl_intf,
+ as->bTerminalLink,
+ UAC_VERSION_3);
+ if (output_term) {
+@@ -1068,7 +1073,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
+ UAC_VERSION_3,
+ iface_no);
+
+- pd = snd_usb_find_power_domain(chip->ctrl_intf,
++ pd = snd_usb_find_power_domain(ctrl_intf,
+ as->bTerminalLink);
+
+ /* ok, let's parse further... */
+diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
+index 43d4029edab46..b0f042c996087 100644
+--- a/sound/usb/usbaudio.h
++++ b/sound/usb/usbaudio.h
+@@ -21,6 +21,15 @@ struct media_intf_devnode;
+
+ #define MAX_CARD_INTERFACES 16
+
++/*
++ * Structure holding assosiation between Audio Control Interface
++ * and given Streaming or Midi Interface.
++ */
++struct snd_intf_to_ctrl {
++ u8 interface;
++ struct usb_host_interface *ctrl_intf;
++};
++
+ struct snd_usb_audio {
+ int index;
+ struct usb_device *dev;
+@@ -63,6 +72,9 @@ struct snd_usb_audio {
+ struct usb_host_interface *ctrl_intf; /* the audio control interface */
+ struct media_device *media_dev;
+ struct media_intf_devnode *ctl_intf_media_devnode;
++
++ unsigned int num_intf_to_ctrl;
++ struct snd_intf_to_ctrl intf_to_ctrl[MAX_CARD_INTERFACES];
+ };
+
+ #define USB_AUDIO_IFACE_UNUSED ((void *)-1L)
+--
+2.43.0
+
--- /dev/null
+From ef4df77fdc02e20156f224327fa9c6bef48c8477 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 2 Sep 2024 16:33:08 +0000
+Subject: arm64: trans_pgd: mark PTEs entries as valid to avoid dead kexec()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Fares Mehanna <faresx@amazon.de>
+
+[ Upstream commit 7eced90b202d63cdc1b9b11b1353adb1389830f9 ]
+
+The reasons for PTEs in the kernel direct map to be marked invalid are not
+limited to kfence / debug pagealloc machinery. In particular,
+memfd_secret() also steals pages with set_direct_map_invalid_noflush().
+
+When building the transitional page tables for kexec from the current
+kernel's page tables, those pages need to become regular writable pages,
+otherwise, if the relocation places kexec segments over such pages, a fault
+will occur during kexec, leading to host going dark during kexec.
+
+This patch addresses the kexec issue by marking any PTE as valid if it is
+not none. While this fixes the kexec crash, it does not address the
+security concern that if processes owning secret memory are not terminated
+before kexec, the secret content will be mapped in the new kernel without
+being scrubbed.
+
+Suggested-by: Jan H. Schönherr <jschoenh@amazon.de>
+Signed-off-by: Fares Mehanna <faresx@amazon.de>
+Link: https://lore.kernel.org/r/20240902163309.97113-1-faresx@amazon.de
+Signed-off-by: Will Deacon <will@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/mm/trans_pgd.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm64/mm/trans_pgd.c b/arch/arm64/mm/trans_pgd.c
+index 5139a28130c08..0f7b484cb2ff2 100644
+--- a/arch/arm64/mm/trans_pgd.c
++++ b/arch/arm64/mm/trans_pgd.c
+@@ -42,14 +42,16 @@ static void _copy_pte(pte_t *dst_ptep, pte_t *src_ptep, unsigned long addr)
+ * the temporary mappings we use during restore.
+ */
+ __set_pte(dst_ptep, pte_mkwrite_novma(pte));
+- } else if ((debug_pagealloc_enabled() ||
+- is_kfence_address((void *)addr)) && !pte_none(pte)) {
++ } else if (!pte_none(pte)) {
+ /*
+ * debug_pagealloc will removed the PTE_VALID bit if
+ * the page isn't in use by the resume kernel. It may have
+ * been in use by the original kernel, in which case we need
+ * to put it back in our copy to do the restore.
+ *
++ * Other cases include kfence / vmalloc / memfd_secret which
++ * may call `set_direct_map_invalid_noflush()`.
++ *
+ * Before marking this entry valid, check the pfn should
+ * be mapped.
+ */
+--
+2.43.0
+
--- /dev/null
+From 09cce4885acc9400a4036e876167f112d26277a7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 10 Jul 2024 15:52:31 +0200
+Subject: ASoC: codecs: wsa883x: Handle reading version failure
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+[ Upstream commit 2fbf16992e5aa14acf0441320033a01a32309ded ]
+
+If reading version and variant from registers fails (which is unlikely
+but possible, because it is a read over bus), the driver will proceed
+and perform device configuration based on uninitialized stack variables.
+Handle it a bit better - bail out without doing any init and failing the
+update status Soundwire callback.
+
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Link: https://patch.msgid.link/20240710-asoc-wsa88xx-version-v1-2-f1c54966ccde@linaro.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/codecs/wsa883x.c | 16 +++++++++++-----
+ 1 file changed, 11 insertions(+), 5 deletions(-)
+
+diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c
+index 2169d93989841..1831d4487ba9d 100644
+--- a/sound/soc/codecs/wsa883x.c
++++ b/sound/soc/codecs/wsa883x.c
+@@ -998,15 +998,19 @@ static const struct reg_sequence reg_init[] = {
+ {WSA883X_GMAMP_SUP1, 0xE2},
+ };
+
+-static void wsa883x_init(struct wsa883x_priv *wsa883x)
++static int wsa883x_init(struct wsa883x_priv *wsa883x)
+ {
+ struct regmap *regmap = wsa883x->regmap;
+- int variant, version;
++ int variant, version, ret;
+
+- regmap_read(regmap, WSA883X_OTP_REG_0, &variant);
++ ret = regmap_read(regmap, WSA883X_OTP_REG_0, &variant);
++ if (ret)
++ return ret;
+ wsa883x->variant = variant & WSA883X_ID_MASK;
+
+- regmap_read(regmap, WSA883X_CHIP_ID0, &version);
++ ret = regmap_read(regmap, WSA883X_CHIP_ID0, &version);
++ if (ret)
++ return ret;
+ wsa883x->version = version;
+
+ switch (wsa883x->variant) {
+@@ -1041,6 +1045,8 @@ static void wsa883x_init(struct wsa883x_priv *wsa883x)
+ WSA883X_DRE_OFFSET_MASK,
+ wsa883x->comp_offset);
+ }
++
++ return 0;
+ }
+
+ static int wsa883x_update_status(struct sdw_slave *slave,
+@@ -1049,7 +1055,7 @@ static int wsa883x_update_status(struct sdw_slave *slave,
+ struct wsa883x_priv *wsa883x = dev_get_drvdata(&slave->dev);
+
+ if (status == SDW_SLAVE_ATTACHED && slave->dev_num > 0)
+- wsa883x_init(wsa883x);
++ return wsa883x_init(wsa883x);
+
+ return 0;
+ }
+--
+2.43.0
+
--- /dev/null
+From cee6740c36aaef52bf86b3e1691b4ec8aceed96c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 27 Aug 2024 20:32:01 +0800
+Subject: ASoC: Intel: boards: always check the result of
+ acpi_dev_get_first_match_dev()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
+
+[ Upstream commit 14e91ddd5c02d8c3e5a682ebfa0546352b459911 ]
+
+The code seems mostly copy-pasted, with some machine drivers
+forgetting to test if the 'adev' result is NULL.
+
+Add this check when missing, and use -ENOENT consistently as an error
+code.
+
+Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
+Closes: https://lore.kernel.org/alsa-devel/918944d2-3d00-465e-a9d1-5d57fc966113@stanley.mountain/T/#u
+Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
+Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
+Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
+Link: https://patch.msgid.link/20240827123215.258859-4-yung-chuan.liao@linux.intel.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/intel/boards/bytcht_cx2072x.c | 4 ++++
+ sound/soc/intel/boards/bytcht_da7213.c | 4 ++++
+ sound/soc/intel/boards/bytcht_es8316.c | 2 +-
+ sound/soc/intel/boards/bytcr_rt5640.c | 2 +-
+ sound/soc/intel/boards/bytcr_rt5651.c | 2 +-
+ sound/soc/intel/boards/cht_bsw_rt5645.c | 4 ++++
+ sound/soc/intel/boards/cht_bsw_rt5672.c | 4 ++++
+ sound/soc/intel/boards/sof_es8336.c | 2 +-
+ sound/soc/intel/boards/sof_wm8804.c | 4 ++++
+ 9 files changed, 24 insertions(+), 4 deletions(-)
+
+diff --git a/sound/soc/intel/boards/bytcht_cx2072x.c b/sound/soc/intel/boards/bytcht_cx2072x.c
+index df3c2a7b64d23..8c2b4ab764bba 100644
+--- a/sound/soc/intel/boards/bytcht_cx2072x.c
++++ b/sound/soc/intel/boards/bytcht_cx2072x.c
+@@ -255,7 +255,11 @@ static int snd_byt_cht_cx2072x_probe(struct platform_device *pdev)
+ snprintf(codec_name, sizeof(codec_name), "i2c-%s",
+ acpi_dev_name(adev));
+ byt_cht_cx2072x_dais[dai_index].codecs->name = codec_name;
++ } else {
++ dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id);
++ return -ENOENT;
+ }
++
+ acpi_dev_put(adev);
+
+ /* override platform name, if required */
+diff --git a/sound/soc/intel/boards/bytcht_da7213.c b/sound/soc/intel/boards/bytcht_da7213.c
+index 08c598b7e1eee..9178bbe8d9950 100644
+--- a/sound/soc/intel/boards/bytcht_da7213.c
++++ b/sound/soc/intel/boards/bytcht_da7213.c
+@@ -258,7 +258,11 @@ static int bytcht_da7213_probe(struct platform_device *pdev)
+ snprintf(codec_name, sizeof(codec_name),
+ "i2c-%s", acpi_dev_name(adev));
+ dailink[dai_index].codecs->name = codec_name;
++ } else {
++ dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id);
++ return -ENOENT;
+ }
++
+ acpi_dev_put(adev);
+
+ /* override platform name, if required */
+diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c
+index 77b91ea4dc32c..3539c9ff0fd2c 100644
+--- a/sound/soc/intel/boards/bytcht_es8316.c
++++ b/sound/soc/intel/boards/bytcht_es8316.c
+@@ -562,7 +562,7 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
+ byt_cht_es8316_dais[dai_index].codecs->name = codec_name;
+ } else {
+ dev_err(dev, "Error cannot find '%s' dev\n", mach->id);
+- return -ENXIO;
++ return -ENOENT;
+ }
+
+ codec_dev = acpi_get_first_physical_node(adev);
+diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c
+index db4a33680d948..4479825c08b5e 100644
+--- a/sound/soc/intel/boards/bytcr_rt5640.c
++++ b/sound/soc/intel/boards/bytcr_rt5640.c
+@@ -1693,7 +1693,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
+ byt_rt5640_dais[dai_index].codecs->name = byt_rt5640_codec_name;
+ } else {
+ dev_err(dev, "Error cannot find '%s' dev\n", mach->id);
+- return -ENXIO;
++ return -ENOENT;
+ }
+
+ codec_dev = acpi_get_first_physical_node(adev);
+diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c
+index 8514b79f389bb..1f54da98aacf4 100644
+--- a/sound/soc/intel/boards/bytcr_rt5651.c
++++ b/sound/soc/intel/boards/bytcr_rt5651.c
+@@ -926,7 +926,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
+ byt_rt5651_dais[dai_index].codecs->name = byt_rt5651_codec_name;
+ } else {
+ dev_err(dev, "Error cannot find '%s' dev\n", mach->id);
+- return -ENXIO;
++ return -ENOENT;
+ }
+
+ codec_dev = acpi_get_first_physical_node(adev);
+diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c
+index 1da9ceee4d593..ac23a8b7cafca 100644
+--- a/sound/soc/intel/boards/cht_bsw_rt5645.c
++++ b/sound/soc/intel/boards/cht_bsw_rt5645.c
+@@ -582,7 +582,11 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
+ snprintf(cht_rt5645_codec_name, sizeof(cht_rt5645_codec_name),
+ "i2c-%s", acpi_dev_name(adev));
+ cht_dailink[dai_index].codecs->name = cht_rt5645_codec_name;
++ } else {
++ dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id);
++ return -ENOENT;
+ }
++
+ /* acpi_get_first_physical_node() returns a borrowed ref, no need to deref */
+ codec_dev = acpi_get_first_physical_node(adev);
+ acpi_dev_put(adev);
+diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c
+index d68e5bc755dee..c6c469d51243e 100644
+--- a/sound/soc/intel/boards/cht_bsw_rt5672.c
++++ b/sound/soc/intel/boards/cht_bsw_rt5672.c
+@@ -479,7 +479,11 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
+ snprintf(drv->codec_name, sizeof(drv->codec_name),
+ "i2c-%s", acpi_dev_name(adev));
+ cht_dailink[dai_index].codecs->name = drv->codec_name;
++ } else {
++ dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id);
++ return -ENOENT;
+ }
++
+ acpi_dev_put(adev);
+
+ /* Use SSP0 on Bay Trail CR devices */
+diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c
+index c1fcc156a5752..809532238c44f 100644
+--- a/sound/soc/intel/boards/sof_es8336.c
++++ b/sound/soc/intel/boards/sof_es8336.c
+@@ -681,7 +681,7 @@ static int sof_es8336_probe(struct platform_device *pdev)
+ dai_links[0].codecs->dai_name = "ES8326 HiFi";
+ } else {
+ dev_err(dev, "Error cannot find '%s' dev\n", mach->id);
+- return -ENXIO;
++ return -ENOENT;
+ }
+
+ codec_dev = acpi_get_first_physical_node(adev);
+diff --git a/sound/soc/intel/boards/sof_wm8804.c b/sound/soc/intel/boards/sof_wm8804.c
+index 4cb0d463bf404..9c5b3f8f09f36 100644
+--- a/sound/soc/intel/boards/sof_wm8804.c
++++ b/sound/soc/intel/boards/sof_wm8804.c
+@@ -270,7 +270,11 @@ static int sof_wm8804_probe(struct platform_device *pdev)
+ snprintf(codec_name, sizeof(codec_name),
+ "%s%s", "i2c-", acpi_dev_name(adev));
+ dailink[dai_index].codecs->name = codec_name;
++ } else {
++ dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id);
++ return -ENOENT;
+ }
++
+ acpi_dev_put(adev);
+
+ snd_soc_card_set_drvdata(card, ctx);
+--
+2.43.0
+
--- /dev/null
+From 893be2b55594d369e87cf9e3dea8fc26ec0cc178 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 26 Jul 2024 10:58:36 +0900
+Subject: ata: pata_serverworks: Do not use the term blacklist
+
+From: Damien Le Moal <dlemoal@kernel.org>
+
+[ Upstream commit 858048568c9e3887d8b19e101ee72f129d65cb15 ]
+
+Let's not use the term blacklist in the function
+serverworks_osb4_filter() documentation comment and rather simply refer
+to what that function looks at: the list of devices with groken UDMA5.
+
+While at it, also constify the values of the csb_bad_ata100 array.
+
+Of note is that all of this should probably be handled using libata
+quirk mechanism but it is unclear if these UDMA5 quirks are specific
+to this controller only.
+
+Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
+Reviewed-by: Niklas Cassel <cassel@kernel.org>
+Reviewed-by: Igor Pylypiv <ipylypiv@google.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/ata/pata_serverworks.c | 16 +++++++++-------
+ 1 file changed, 9 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c
+index 549ff24a98231..4edddf6bcc150 100644
+--- a/drivers/ata/pata_serverworks.c
++++ b/drivers/ata/pata_serverworks.c
+@@ -46,10 +46,11 @@
+ #define SVWKS_CSB5_REVISION_NEW 0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */
+ #define SVWKS_CSB6_REVISION 0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */
+
+-/* Seagate Barracuda ATA IV Family drives in UDMA mode 5
+- * can overrun their FIFOs when used with the CSB5 */
+-
+-static const char *csb_bad_ata100[] = {
++/*
++ * Seagate Barracuda ATA IV Family drives in UDMA mode 5
++ * can overrun their FIFOs when used with the CSB5.
++ */
++static const char * const csb_bad_ata100[] = {
+ "ST320011A",
+ "ST340016A",
+ "ST360021A",
+@@ -163,10 +164,11 @@ static unsigned int serverworks_osb4_filter(struct ata_device *adev, unsigned in
+ * @adev: ATA device
+ * @mask: Mask of proposed modes
+ *
+- * Check the blacklist and disable UDMA5 if matched
++ * Check the list of devices with broken UDMA5 and
++ * disable UDMA5 if matched.
+ */
+-
+-static unsigned int serverworks_csb_filter(struct ata_device *adev, unsigned int mask)
++static unsigned int serverworks_csb_filter(struct ata_device *adev,
++ unsigned int mask)
+ {
+ const char *p;
+ char model_num[ATA_ID_PROD_LEN + 1];
+--
+2.43.0
+
--- /dev/null
+From 62ee2a44cced011ddb078e8b2c363a85b5be5662 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 26 Jul 2024 11:14:11 +0900
+Subject: ata: sata_sil: Rename sil_blacklist to sil_quirks
+
+From: Damien Le Moal <dlemoal@kernel.org>
+
+[ Upstream commit 93b0f9e11ce511353c65b7f924cf5f95bd9c3aba ]
+
+Rename the array sil_blacklist to sil_quirks as this name is more
+neutral and is also consistent with how this driver define quirks with
+the SIL_QUIRK_XXX flags.
+
+Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
+Reviewed-by: Niklas Cassel <cassel@kernel.org>
+Reviewed-by: Igor Pylypiv <ipylypiv@google.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/ata/sata_sil.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c
+index cc77c02482843..df095659bae0f 100644
+--- a/drivers/ata/sata_sil.c
++++ b/drivers/ata/sata_sil.c
+@@ -128,7 +128,7 @@ static const struct pci_device_id sil_pci_tbl[] = {
+ static const struct sil_drivelist {
+ const char *product;
+ unsigned int quirk;
+-} sil_blacklist [] = {
++} sil_quirks[] = {
+ { "ST320012AS", SIL_QUIRK_MOD15WRITE },
+ { "ST330013AS", SIL_QUIRK_MOD15WRITE },
+ { "ST340017AS", SIL_QUIRK_MOD15WRITE },
+@@ -600,8 +600,8 @@ static void sil_thaw(struct ata_port *ap)
+ * list, and apply the fixups to only the specific
+ * devices/hosts/firmwares that need it.
+ *
+- * 20040111 - Seagate drives affected by the Mod15Write bug are blacklisted
+- * The Maxtor quirk is in the blacklist, but I'm keeping the original
++ * 20040111 - Seagate drives affected by the Mod15Write bug are quirked
++ * The Maxtor quirk is in sil_quirks, but I'm keeping the original
+ * pessimistic fix for the following reasons...
+ * - There seems to be less info on it, only one device gleaned off the
+ * Windows driver, maybe only one is affected. More info would be greatly
+@@ -620,9 +620,9 @@ static void sil_dev_config(struct ata_device *dev)
+
+ ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num));
+
+- for (n = 0; sil_blacklist[n].product; n++)
+- if (!strcmp(sil_blacklist[n].product, model_num)) {
+- quirks = sil_blacklist[n].quirk;
++ for (n = 0; sil_quirks[n].product; n++)
++ if (!strcmp(sil_quirks[n].product, model_num)) {
++ quirks = sil_quirks[n].quirk;
+ break;
+ }
+
+--
+2.43.0
+
--- /dev/null
+From c82b11c13ccf00d24d38b7e229563abeb2db305e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 22 Aug 2024 08:41:36 -0700
+Subject: blk_iocost: fix more out of bound shifts
+
+From: Konstantin Ovsepian <ovs@ovs.to>
+
+[ Upstream commit 9bce8005ec0dcb23a58300e8522fe4a31da606fa ]
+
+Recently running UBSAN caught few out of bound shifts in the
+ioc_forgive_debts() function:
+
+UBSAN: shift-out-of-bounds in block/blk-iocost.c:2142:38
+shift exponent 80 is too large for 64-bit type 'u64' (aka 'unsigned long
+long')
+...
+UBSAN: shift-out-of-bounds in block/blk-iocost.c:2144:30
+shift exponent 80 is too large for 64-bit type 'u64' (aka 'unsigned long
+long')
+...
+Call Trace:
+<IRQ>
+dump_stack_lvl+0xca/0x130
+__ubsan_handle_shift_out_of_bounds+0x22c/0x280
+? __lock_acquire+0x6441/0x7c10
+ioc_timer_fn+0x6cec/0x7750
+? blk_iocost_init+0x720/0x720
+? call_timer_fn+0x5d/0x470
+call_timer_fn+0xfa/0x470
+? blk_iocost_init+0x720/0x720
+__run_timer_base+0x519/0x700
+...
+
+Actual impact of this issue was not identified but I propose to fix the
+undefined behaviour.
+The proposed fix to prevent those out of bound shifts consist of
+precalculating exponent before using it the shift operations by taking
+min value from the actual exponent and maximum possible number of bits.
+
+Reported-by: Breno Leitao <leitao@debian.org>
+Signed-off-by: Konstantin Ovsepian <ovs@ovs.to>
+Acked-by: Tejun Heo <tj@kernel.org>
+Link: https://lore.kernel.org/r/20240822154137.2627818-1-ovs@ovs.to
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ block/blk-iocost.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/block/blk-iocost.c b/block/blk-iocost.c
+index 690ca99dfaca6..5a6098a3db57e 100644
+--- a/block/blk-iocost.c
++++ b/block/blk-iocost.c
+@@ -2076,7 +2076,7 @@ static void ioc_forgive_debts(struct ioc *ioc, u64 usage_us_sum, int nr_debtors,
+ struct ioc_now *now)
+ {
+ struct ioc_gq *iocg;
+- u64 dur, usage_pct, nr_cycles;
++ u64 dur, usage_pct, nr_cycles, nr_cycles_shift;
+
+ /* if no debtor, reset the cycle */
+ if (!nr_debtors) {
+@@ -2138,10 +2138,12 @@ static void ioc_forgive_debts(struct ioc *ioc, u64 usage_us_sum, int nr_debtors,
+ old_debt = iocg->abs_vdebt;
+ old_delay = iocg->delay;
+
++ nr_cycles_shift = min_t(u64, nr_cycles, BITS_PER_LONG - 1);
+ if (iocg->abs_vdebt)
+- iocg->abs_vdebt = iocg->abs_vdebt >> nr_cycles ?: 1;
++ iocg->abs_vdebt = iocg->abs_vdebt >> nr_cycles_shift ?: 1;
++
+ if (iocg->delay)
+- iocg->delay = iocg->delay >> nr_cycles ?: 1;
++ iocg->delay = iocg->delay >> nr_cycles_shift ?: 1;
+
+ iocg_kick_waitq(iocg, true, now);
+
+--
+2.43.0
+
--- /dev/null
+From 5739969a5ed222459f95efdda581664b8b8498c0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Sep 2024 22:48:19 +0300
+Subject: block: fix integer overflow in BLKSECDISCARD
+
+From: Alexey Dobriyan <adobriyan@gmail.com>
+
+[ Upstream commit 697ba0b6ec4ae04afb67d3911799b5e2043b4455 ]
+
+I independently rediscovered
+
+ commit 22d24a544b0d49bbcbd61c8c0eaf77d3c9297155
+ block: fix overflow in blk_ioctl_discard()
+
+but for secure erase.
+
+Same problem:
+
+ uint64_t r[2] = {512, 18446744073709551104ULL};
+ ioctl(fd, BLKSECDISCARD, r);
+
+will enter near infinite loop inside blkdev_issue_secure_erase():
+
+ a.out: attempt to access beyond end of device
+ loop0: rw=5, sector=3399043073, nr_sectors = 1024 limit=2048
+ bio_check_eod: 3286214 callbacks suppressed
+
+Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
+Link: https://lore.kernel.org/r/9e64057f-650a-46d1-b9f7-34af391536ef@p183
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ block/ioctl.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/block/ioctl.c b/block/ioctl.c
+index d570e16958961..4515d4679eefd 100644
+--- a/block/ioctl.c
++++ b/block/ioctl.c
+@@ -126,7 +126,7 @@ static int blk_ioctl_discard(struct block_device *bdev, blk_mode_t mode,
+ return -EINVAL;
+
+ filemap_invalidate_lock(bdev->bd_mapping);
+- err = truncate_bdev_range(bdev, mode, start, start + len - 1);
++ err = truncate_bdev_range(bdev, mode, start, end - 1);
+ if (err)
+ goto fail;
+
+@@ -163,7 +163,7 @@ static int blk_ioctl_discard(struct block_device *bdev, blk_mode_t mode,
+ static int blk_ioctl_secure_erase(struct block_device *bdev, blk_mode_t mode,
+ void __user *argp)
+ {
+- uint64_t start, len;
++ uint64_t start, len, end;
+ uint64_t range[2];
+ int err;
+
+@@ -178,11 +178,12 @@ static int blk_ioctl_secure_erase(struct block_device *bdev, blk_mode_t mode,
+ len = range[1];
+ if ((start & 511) || (len & 511))
+ return -EINVAL;
+- if (start + len > bdev_nr_bytes(bdev))
++ if (check_add_overflow(start, len, &end) ||
++ end > bdev_nr_bytes(bdev))
+ return -EINVAL;
+
+ filemap_invalidate_lock(bdev->bd_mapping);
+- err = truncate_bdev_range(bdev, mode, start, start + len - 1);
++ err = truncate_bdev_range(bdev, mode, start, end - 1);
+ if (!err)
+ err = blkdev_issue_secure_erase(bdev, start >> 9, len >> 9,
+ GFP_KERNEL);
+--
+2.43.0
+
--- /dev/null
+From 2fd8584d645edb1da5ff96ab4845cbbdd4abd5a0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 29 Aug 2024 16:40:05 +0800
+Subject: Bluetooth: btrtl: Set msft ext address filter quirk for RTL8852B
+
+From: Hilda Wu <hildawu@realtek.com>
+
+[ Upstream commit 9a0570948c5def5c59e588dc0e009ed850a1f5a1 ]
+
+For tracking multiple devices concurrently with a condition.
+The patch enables the HCI_QUIRK_USE_MSFT_EXT_ADDRESS_FILTER quirk
+on RTL8852B controller.
+
+The quirk setting is based on commit 9e14606d8f38 ("Bluetooth: msft:
+Extended monitor tracking by address filter")
+
+With this setting, when a pattern monitor detects a device, this
+feature issues an address monitor for tracking that device. Let the
+original pattern monitor keep monitor new devices.
+
+Signed-off-by: Hilda Wu <hildawu@realtek.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/bluetooth/btrtl.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c
+index bfcb41a57655f..78b5d44558d73 100644
+--- a/drivers/bluetooth/btrtl.c
++++ b/drivers/bluetooth/btrtl.c
+@@ -1296,6 +1296,7 @@ void btrtl_set_quirks(struct hci_dev *hdev, struct btrtl_device_info *btrtl_dev)
+ btrealtek_set_flag(hdev, REALTEK_ALT6_CONTINUOUS_TX_CHIP);
+
+ if (btrtl_dev->project_id == CHIP_ID_8852A ||
++ btrtl_dev->project_id == CHIP_ID_8852B ||
+ btrtl_dev->project_id == CHIP_ID_8852C)
+ set_bit(HCI_QUIRK_USE_MSFT_EXT_ADDRESS_FILTER, &hdev->quirks);
+
+--
+2.43.0
+
--- /dev/null
+From ad42832760001ef079cda6ad2f60244dee4acf02 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 16 Aug 2024 16:58:22 +0800
+Subject: Bluetooth: btusb: Add Realtek RTL8852C support ID 0x0489:0xe122
+
+From: Hilda Wu <hildawu@realtek.com>
+
+[ Upstream commit bdf9557f70e7512bb2f754abf90d9e9958745316 ]
+
+Add the support ID (0x0489, 0xe122) to usb_device_id table for
+Realtek RTL8852C.
+
+The device info from /sys/kernel/debug/usb/devices as below.
+
+T: Bus=03 Lev=01 Prnt=01 Port=02 Cnt=01 Dev#= 2 Spd=12 MxCh= 0
+D: Ver= 1.00 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1
+P: Vendor=0489 ProdID=e122 Rev= 0.00
+S: Manufacturer=Realtek
+S: Product=Bluetooth Radio
+S: SerialNumber=00e04c000001
+C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=500mA
+I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms
+E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms
+E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms
+I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms
+E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms
+I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms
+E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms
+I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms
+E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms
+I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms
+E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms
+I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms
+E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms
+I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms
+E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms
+
+Signed-off-by: Hilda Wu <hildawu@realtek.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/bluetooth/btusb.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
+index c41b86608ba86..dd7d9b7fd1c42 100644
+--- a/drivers/bluetooth/btusb.c
++++ b/drivers/bluetooth/btusb.c
+@@ -539,6 +539,8 @@ static const struct usb_device_id quirks_table[] = {
+ BTUSB_WIDEBAND_SPEECH },
+ { USB_DEVICE(0x13d3, 0x3592), .driver_info = BTUSB_REALTEK |
+ BTUSB_WIDEBAND_SPEECH },
++ { USB_DEVICE(0x0489, 0xe122), .driver_info = BTUSB_REALTEK |
++ BTUSB_WIDEBAND_SPEECH },
+
+ /* Realtek 8852BE Bluetooth devices */
+ { USB_DEVICE(0x0cb8, 0xc559), .driver_info = BTUSB_REALTEK |
+--
+2.43.0
+
--- /dev/null
+From 1b72f78b090785489e61a0e8854f5cfcdcf55b30 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 13 Aug 2024 15:32:55 +0100
+Subject: bnxt_en: Extend maximum length of version string by 1 byte
+
+From: Simon Horman <horms@kernel.org>
+
+[ Upstream commit ffff7ee843c351ce71d6e0d52f0f20bea35e18c9 ]
+
+This corrects an out-by-one error in the maximum length of the package
+version string. The size argument of snprintf includes space for the
+trailing '\0' byte, so there is no need to allow extra space for it by
+reducing the value of the size argument by 1.
+
+Found by inspection.
+Compile tested only.
+
+Signed-off-by: Simon Horman <horms@kernel.org>
+Reviewed-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20240813-bnxt-str-v2-1-872050a157e7@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
+index 79c09c1cdf936..0032c4ebd7e12 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
+@@ -4146,7 +4146,7 @@ static void bnxt_get_pkgver(struct net_device *dev)
+
+ if (!bnxt_get_pkginfo(dev, buf, sizeof(buf))) {
+ len = strlen(bp->fw_ver_str);
+- snprintf(bp->fw_ver_str + len, FW_VER_STR_LEN - len - 1,
++ snprintf(bp->fw_ver_str + len, FW_VER_STR_LEN - len,
+ "/pkg %s", buf);
+ }
+ }
+--
+2.43.0
+
--- /dev/null
+From 6ec44d4fe03d8a1df90bf0c47f5655f4883bc6aa Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 13 Sep 2024 08:03:26 -0700
+Subject: bpf: Fix a sdiv overflow issue
+
+From: Yonghong Song <yonghong.song@linux.dev>
+
+[ Upstream commit 7dd34d7b7dcf9309fc6224caf4dd5b35bedddcb7 ]
+
+Zac Ecob reported a problem where a bpf program may cause kernel crash due
+to the following error:
+ Oops: divide error: 0000 [#1] PREEMPT SMP KASAN PTI
+
+The failure is due to the below signed divide:
+ LLONG_MIN/-1 where LLONG_MIN equals to -9,223,372,036,854,775,808.
+LLONG_MIN/-1 is supposed to give a positive number 9,223,372,036,854,775,808,
+but it is impossible since for 64-bit system, the maximum positive
+number is 9,223,372,036,854,775,807. On x86_64, LLONG_MIN/-1 will
+cause a kernel exception. On arm64, the result for LLONG_MIN/-1 is
+LLONG_MIN.
+
+Further investigation found all the following sdiv/smod cases may trigger
+an exception when bpf program is running on x86_64 platform:
+ - LLONG_MIN/-1 for 64bit operation
+ - INT_MIN/-1 for 32bit operation
+ - LLONG_MIN%-1 for 64bit operation
+ - INT_MIN%-1 for 32bit operation
+where -1 can be an immediate or in a register.
+
+On arm64, there are no exceptions:
+ - LLONG_MIN/-1 = LLONG_MIN
+ - INT_MIN/-1 = INT_MIN
+ - LLONG_MIN%-1 = 0
+ - INT_MIN%-1 = 0
+where -1 can be an immediate or in a register.
+
+Insn patching is needed to handle the above cases and the patched codes
+produced results aligned with above arm64 result. The below are pseudo
+codes to handle sdiv/smod exceptions including both divisor -1 and divisor 0
+and the divisor is stored in a register.
+
+sdiv:
+ tmp = rX
+ tmp += 1 /* [-1, 0] -> [0, 1]
+ if tmp >(unsigned) 1 goto L2
+ if tmp == 0 goto L1
+ rY = 0
+ L1:
+ rY = -rY;
+ goto L3
+ L2:
+ rY /= rX
+ L3:
+
+smod:
+ tmp = rX
+ tmp += 1 /* [-1, 0] -> [0, 1]
+ if tmp >(unsigned) 1 goto L1
+ if tmp == 1 (is64 ? goto L2 : goto L3)
+ rY = 0;
+ goto L2
+ L1:
+ rY %= rX
+ L2:
+ goto L4 // only when !is64
+ L3:
+ wY = wY // only when !is64
+ L4:
+
+ [1] https://lore.kernel.org/bpf/tPJLTEh7S_DxFEqAI2Ji5MBSoZVg7_G-Py2iaZpAaWtM961fFTWtsnlzwvTbzBzaUzwQAoNATXKUlt0LZOFgnDcIyKCswAnAGdUF3LBrhGQ=@protonmail.com/
+
+Reported-by: Zac Ecob <zacecob@protonmail.com>
+Signed-off-by: Yonghong Song <yonghong.song@linux.dev>
+Acked-by: Andrii Nakryiko <andrii@kernel.org>
+Link: https://lore.kernel.org/r/20240913150326.1187788-1-yonghong.song@linux.dev
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/verifier.c | 93 +++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 89 insertions(+), 4 deletions(-)
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index 4688dc82f8b06..eb4b4f5b1284f 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -19951,13 +19951,46 @@ static int do_misc_fixups(struct bpf_verifier_env *env)
+ /* Convert BPF_CLASS(insn->code) == BPF_ALU64 to 32-bit ALU */
+ insn->code = BPF_ALU | BPF_OP(insn->code) | BPF_SRC(insn->code);
+
+- /* Make divide-by-zero exceptions impossible. */
++ /* Make sdiv/smod divide-by-minus-one exceptions impossible. */
++ if ((insn->code == (BPF_ALU64 | BPF_MOD | BPF_K) ||
++ insn->code == (BPF_ALU64 | BPF_DIV | BPF_K) ||
++ insn->code == (BPF_ALU | BPF_MOD | BPF_K) ||
++ insn->code == (BPF_ALU | BPF_DIV | BPF_K)) &&
++ insn->off == 1 && insn->imm == -1) {
++ bool is64 = BPF_CLASS(insn->code) == BPF_ALU64;
++ bool isdiv = BPF_OP(insn->code) == BPF_DIV;
++ struct bpf_insn *patchlet;
++ struct bpf_insn chk_and_sdiv[] = {
++ BPF_RAW_INSN((is64 ? BPF_ALU64 : BPF_ALU) |
++ BPF_NEG | BPF_K, insn->dst_reg,
++ 0, 0, 0),
++ };
++ struct bpf_insn chk_and_smod[] = {
++ BPF_MOV32_IMM(insn->dst_reg, 0),
++ };
++
++ patchlet = isdiv ? chk_and_sdiv : chk_and_smod;
++ cnt = isdiv ? ARRAY_SIZE(chk_and_sdiv) : ARRAY_SIZE(chk_and_smod);
++
++ new_prog = bpf_patch_insn_data(env, i + delta, patchlet, cnt);
++ if (!new_prog)
++ return -ENOMEM;
++
++ delta += cnt - 1;
++ env->prog = prog = new_prog;
++ insn = new_prog->insnsi + i + delta;
++ goto next_insn;
++ }
++
++ /* Make divide-by-zero and divide-by-minus-one exceptions impossible. */
+ if (insn->code == (BPF_ALU64 | BPF_MOD | BPF_X) ||
+ insn->code == (BPF_ALU64 | BPF_DIV | BPF_X) ||
+ insn->code == (BPF_ALU | BPF_MOD | BPF_X) ||
+ insn->code == (BPF_ALU | BPF_DIV | BPF_X)) {
+ bool is64 = BPF_CLASS(insn->code) == BPF_ALU64;
+ bool isdiv = BPF_OP(insn->code) == BPF_DIV;
++ bool is_sdiv = isdiv && insn->off == 1;
++ bool is_smod = !isdiv && insn->off == 1;
+ struct bpf_insn *patchlet;
+ struct bpf_insn chk_and_div[] = {
+ /* [R,W]x div 0 -> 0 */
+@@ -19977,10 +20010,62 @@ static int do_misc_fixups(struct bpf_verifier_env *env)
+ BPF_JMP_IMM(BPF_JA, 0, 0, 1),
+ BPF_MOV32_REG(insn->dst_reg, insn->dst_reg),
+ };
++ struct bpf_insn chk_and_sdiv[] = {
++ /* [R,W]x sdiv 0 -> 0
++ * LLONG_MIN sdiv -1 -> LLONG_MIN
++ * INT_MIN sdiv -1 -> INT_MIN
++ */
++ BPF_MOV64_REG(BPF_REG_AX, insn->src_reg),
++ BPF_RAW_INSN((is64 ? BPF_ALU64 : BPF_ALU) |
++ BPF_ADD | BPF_K, BPF_REG_AX,
++ 0, 0, 1),
++ BPF_RAW_INSN((is64 ? BPF_JMP : BPF_JMP32) |
++ BPF_JGT | BPF_K, BPF_REG_AX,
++ 0, 4, 1),
++ BPF_RAW_INSN((is64 ? BPF_JMP : BPF_JMP32) |
++ BPF_JEQ | BPF_K, BPF_REG_AX,
++ 0, 1, 0),
++ BPF_RAW_INSN((is64 ? BPF_ALU64 : BPF_ALU) |
++ BPF_MOV | BPF_K, insn->dst_reg,
++ 0, 0, 0),
++ /* BPF_NEG(LLONG_MIN) == -LLONG_MIN == LLONG_MIN */
++ BPF_RAW_INSN((is64 ? BPF_ALU64 : BPF_ALU) |
++ BPF_NEG | BPF_K, insn->dst_reg,
++ 0, 0, 0),
++ BPF_JMP_IMM(BPF_JA, 0, 0, 1),
++ *insn,
++ };
++ struct bpf_insn chk_and_smod[] = {
++ /* [R,W]x mod 0 -> [R,W]x */
++ /* [R,W]x mod -1 -> 0 */
++ BPF_MOV64_REG(BPF_REG_AX, insn->src_reg),
++ BPF_RAW_INSN((is64 ? BPF_ALU64 : BPF_ALU) |
++ BPF_ADD | BPF_K, BPF_REG_AX,
++ 0, 0, 1),
++ BPF_RAW_INSN((is64 ? BPF_JMP : BPF_JMP32) |
++ BPF_JGT | BPF_K, BPF_REG_AX,
++ 0, 3, 1),
++ BPF_RAW_INSN((is64 ? BPF_JMP : BPF_JMP32) |
++ BPF_JEQ | BPF_K, BPF_REG_AX,
++ 0, 3 + (is64 ? 0 : 1), 1),
++ BPF_MOV32_IMM(insn->dst_reg, 0),
++ BPF_JMP_IMM(BPF_JA, 0, 0, 1),
++ *insn,
++ BPF_JMP_IMM(BPF_JA, 0, 0, 1),
++ BPF_MOV32_REG(insn->dst_reg, insn->dst_reg),
++ };
+
+- patchlet = isdiv ? chk_and_div : chk_and_mod;
+- cnt = isdiv ? ARRAY_SIZE(chk_and_div) :
+- ARRAY_SIZE(chk_and_mod) - (is64 ? 2 : 0);
++ if (is_sdiv) {
++ patchlet = chk_and_sdiv;
++ cnt = ARRAY_SIZE(chk_and_sdiv);
++ } else if (is_smod) {
++ patchlet = chk_and_smod;
++ cnt = ARRAY_SIZE(chk_and_smod) - (is64 ? 2 : 0);
++ } else {
++ patchlet = isdiv ? chk_and_div : chk_and_mod;
++ cnt = isdiv ? ARRAY_SIZE(chk_and_div) :
++ ARRAY_SIZE(chk_and_mod) - (is64 ? 2 : 0);
++ }
+
+ new_prog = bpf_patch_insn_data(env, i + delta, patchlet, cnt);
+ if (!new_prog)
+--
+2.43.0
+
--- /dev/null
+From 0b752f35496de47b25c3d5e7487b845d566687c7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 29 Aug 2024 21:11:17 +0100
+Subject: bpf: Make the pointer returned by iter next method valid
+
+From: Juntong Deng <juntong.deng@outlook.com>
+
+[ Upstream commit 4cc8c50c9abcb2646a7a4fcef3cea5dcb30c06cf ]
+
+Currently we cannot pass the pointer returned by iter next method as
+argument to KF_TRUSTED_ARGS or KF_RCU kfuncs, because the pointer
+returned by iter next method is not "valid".
+
+This patch sets the pointer returned by iter next method to be valid.
+
+This is based on the fact that if the iterator is implemented correctly,
+then the pointer returned from the iter next method should be valid.
+
+This does not make NULL pointer valid. If the iter next method has
+KF_RET_NULL flag, then the verifier will ask the ebpf program to
+check NULL pointer.
+
+KF_RCU_PROTECTED iterator is a special case, the pointer returned by
+iter next method should only be valid within RCU critical section,
+so it should be with MEM_RCU, not PTR_TRUSTED.
+
+Another special case is bpf_iter_num_next, which returns a pointer with
+base type PTR_TO_MEM. PTR_TO_MEM should not be combined with type flag
+PTR_TRUSTED (PTR_TO_MEM already means the pointer is valid).
+
+The pointer returned by iter next method of other types of iterators
+is with PTR_TRUSTED.
+
+In addition, this patch adds get_iter_from_state to help us get the
+current iterator from the current state.
+
+Signed-off-by: Juntong Deng <juntong.deng@outlook.com>
+Link: https://lore.kernel.org/r/AM6PR03MB584869F8B448EA1C87B7CDA399962@AM6PR03MB5848.eurprd03.prod.outlook.com
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/verifier.c | 26 ++++++++++++++++++++++----
+ 1 file changed, 22 insertions(+), 4 deletions(-)
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index c821713249c81..4688dc82f8b06 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -8017,6 +8017,15 @@ static int widen_imprecise_scalars(struct bpf_verifier_env *env,
+ return 0;
+ }
+
++static struct bpf_reg_state *get_iter_from_state(struct bpf_verifier_state *cur_st,
++ struct bpf_kfunc_call_arg_meta *meta)
++{
++ int iter_frameno = meta->iter.frameno;
++ int iter_spi = meta->iter.spi;
++
++ return &cur_st->frame[iter_frameno]->stack[iter_spi].spilled_ptr;
++}
++
+ /* process_iter_next_call() is called when verifier gets to iterator's next
+ * "method" (e.g., bpf_iter_num_next() for numbers iterator) call. We'll refer
+ * to it as just "iter_next()" in comments below.
+@@ -8101,12 +8110,10 @@ static int process_iter_next_call(struct bpf_verifier_env *env, int insn_idx,
+ struct bpf_verifier_state *cur_st = env->cur_state, *queued_st, *prev_st;
+ struct bpf_func_state *cur_fr = cur_st->frame[cur_st->curframe], *queued_fr;
+ struct bpf_reg_state *cur_iter, *queued_iter;
+- int iter_frameno = meta->iter.frameno;
+- int iter_spi = meta->iter.spi;
+
+ BTF_TYPE_EMIT(struct bpf_iter);
+
+- cur_iter = &env->cur_state->frame[iter_frameno]->stack[iter_spi].spilled_ptr;
++ cur_iter = get_iter_from_state(cur_st, meta);
+
+ if (cur_iter->iter.state != BPF_ITER_STATE_ACTIVE &&
+ cur_iter->iter.state != BPF_ITER_STATE_DRAINED) {
+@@ -8134,7 +8141,7 @@ static int process_iter_next_call(struct bpf_verifier_env *env, int insn_idx,
+ if (!queued_st)
+ return -ENOMEM;
+
+- queued_iter = &queued_st->frame[iter_frameno]->stack[iter_spi].spilled_ptr;
++ queued_iter = get_iter_from_state(queued_st, meta);
+ queued_iter->iter.state = BPF_ITER_STATE_ACTIVE;
+ queued_iter->iter.depth++;
+ if (prev_st)
+@@ -12675,6 +12682,17 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
+ regs[BPF_REG_0].btf = desc_btf;
+ regs[BPF_REG_0].type = PTR_TO_BTF_ID;
+ regs[BPF_REG_0].btf_id = ptr_type_id;
++
++ if (is_iter_next_kfunc(&meta)) {
++ struct bpf_reg_state *cur_iter;
++
++ cur_iter = get_iter_from_state(env->cur_state, &meta);
++
++ if (cur_iter->type & MEM_RCU) /* KF_RCU_PROTECTED */
++ regs[BPF_REG_0].type |= MEM_RCU;
++ else
++ regs[BPF_REG_0].type |= PTR_TRUSTED;
++ }
+ }
+
+ if (is_kfunc_ret_null(&meta)) {
+--
+2.43.0
+
--- /dev/null
+From 38c9d180fca76681259493870e8a793193c0f0cb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 8 Sep 2024 22:00:09 +0800
+Subject: bpftool: Fix undefined behavior caused by shifting into the sign bit
+
+From: Kuan-Wei Chiu <visitorckw@gmail.com>
+
+[ Upstream commit 4cdc0e4ce5e893bc92255f5f734d983012f2bc2e ]
+
+Replace shifts of '1' with '1U' in bitwise operations within
+__show_dev_tc_bpf() to prevent undefined behavior caused by shifting
+into the sign bit of a signed integer. By using '1U', the operations
+are explicitly performed on unsigned integers, avoiding potential
+integer overflow or sign-related issues.
+
+Signed-off-by: Kuan-Wei Chiu <visitorckw@gmail.com>
+Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
+Acked-by: Quentin Monnet <qmo@kernel.org>
+Link: https://lore.kernel.org/bpf/20240908140009.3149781-1-visitorckw@gmail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/bpf/bpftool/net.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c
+index 968714b4c3d45..ad2ea6cf2db11 100644
+--- a/tools/bpf/bpftool/net.c
++++ b/tools/bpf/bpftool/net.c
+@@ -482,9 +482,9 @@ static void __show_dev_tc_bpf(const struct ip_devname_ifindex *dev,
+ if (prog_flags[i] || json_output) {
+ NET_START_ARRAY("prog_flags", "%s ");
+ for (j = 0; prog_flags[i] && j < 32; j++) {
+- if (!(prog_flags[i] & (1 << j)))
++ if (!(prog_flags[i] & (1U << j)))
+ continue;
+- NET_DUMP_UINT_ONLY(1 << j);
++ NET_DUMP_UINT_ONLY(1U << j);
+ }
+ NET_END_ARRAY("");
+ }
+@@ -493,9 +493,9 @@ static void __show_dev_tc_bpf(const struct ip_devname_ifindex *dev,
+ if (link_flags[i] || json_output) {
+ NET_START_ARRAY("link_flags", "%s ");
+ for (j = 0; link_flags[i] && j < 32; j++) {
+- if (!(link_flags[i] & (1 << j)))
++ if (!(link_flags[i] & (1U << j)))
+ continue;
+- NET_DUMP_UINT_ONLY(1 << j);
++ NET_DUMP_UINT_ONLY(1U << j);
+ }
+ NET_END_ARRAY("");
+ }
+--
+2.43.0
+
--- /dev/null
+From 4845ae8332bd9154325ea6e6d3166d113e9a2692 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 10 Sep 2024 23:02:07 +0800
+Subject: bpftool: Fix undefined behavior in qsort(NULL, 0, ...)
+
+From: Kuan-Wei Chiu <visitorckw@gmail.com>
+
+[ Upstream commit f04e2ad394e2755d0bb2d858ecb5598718bf00d5 ]
+
+When netfilter has no entry to display, qsort is called with
+qsort(NULL, 0, ...). This results in undefined behavior, as UBSan
+reports:
+
+net.c:827:2: runtime error: null pointer passed as argument 1, which is declared to never be null
+
+Although the C standard does not explicitly state whether calling qsort
+with a NULL pointer when the size is 0 constitutes undefined behavior,
+Section 7.1.4 of the C standard (Use of library functions) mentions:
+
+"Each of the following statements applies unless explicitly stated
+otherwise in the detailed descriptions that follow: If an argument to a
+function has an invalid value (such as a value outside the domain of
+the function, or a pointer outside the address space of the program, or
+a null pointer, or a pointer to non-modifiable storage when the
+corresponding parameter is not const-qualified) or a type (after
+promotion) not expected by a function with variable number of
+arguments, the behavior is undefined."
+
+To avoid this, add an early return when nf_link_info is NULL to prevent
+calling qsort with a NULL pointer.
+
+Signed-off-by: Kuan-Wei Chiu <visitorckw@gmail.com>
+Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
+Reviewed-by: Quentin Monnet <qmo@kernel.org>
+Link: https://lore.kernel.org/bpf/20240910150207.3179306-1-visitorckw@gmail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/bpf/bpftool/net.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c
+index ad2ea6cf2db11..0f2106218e1f0 100644
+--- a/tools/bpf/bpftool/net.c
++++ b/tools/bpf/bpftool/net.c
+@@ -824,6 +824,9 @@ static void show_link_netfilter(void)
+ nf_link_count++;
+ }
+
++ if (!nf_link_info)
++ return;
++
+ qsort(nf_link_info, nf_link_count, sizeof(*nf_link_info), netfilter_link_compar);
+
+ for (id = 0; id < nf_link_count; id++) {
+--
+2.43.0
+
--- /dev/null
+From bff7fc8c8d969fbd15ecfc8750f2bc232d1dda48 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 8 Aug 2024 18:42:24 +0200
+Subject: can: netlink: avoid call to do_set_data_bittiming callback with stale
+ can_priv::ctrlmode
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Stefan Mätje <stefan.maetje@esd.eu>
+
+[ Upstream commit 2423cc20087ae9a7b7af575aa62304ef67cad7b6 ]
+
+This patch moves the evaluation of data[IFLA_CAN_CTRLMODE] in function
+can_changelink in front of the evaluation of data[IFLA_CAN_BITTIMING].
+
+This avoids a call to do_set_data_bittiming providing a stale
+can_priv::ctrlmode with a CAN_CTRLMODE_FD flag not matching the
+requested state when switching between a CAN Classic and CAN-FD bitrate.
+
+In the same manner the evaluation of data[IFLA_CAN_CTRLMODE] in function
+can_validate is also moved in front of the evaluation of
+data[IFLA_CAN_BITTIMING].
+
+This is a preparation for patches where the nominal and data bittiming
+may have interdependencies on the driver side depending on the
+CAN_CTRLMODE_FD flag state.
+
+Signed-off-by: Stefan Mätje <stefan.maetje@esd.eu>
+Link: https://patch.msgid.link/20240808164224.213522-1-stefan.maetje@esd.eu
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/can/dev/netlink.c | 102 +++++++++++++++++-----------------
+ 1 file changed, 51 insertions(+), 51 deletions(-)
+
+diff --git a/drivers/net/can/dev/netlink.c b/drivers/net/can/dev/netlink.c
+index dfdc039d92a6c..01aacdcda2606 100644
+--- a/drivers/net/can/dev/netlink.c
++++ b/drivers/net/can/dev/netlink.c
+@@ -65,15 +65,6 @@ static int can_validate(struct nlattr *tb[], struct nlattr *data[],
+ if (!data)
+ return 0;
+
+- if (data[IFLA_CAN_BITTIMING]) {
+- struct can_bittiming bt;
+-
+- memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt));
+- err = can_validate_bittiming(&bt, extack);
+- if (err)
+- return err;
+- }
+-
+ if (data[IFLA_CAN_CTRLMODE]) {
+ struct can_ctrlmode *cm = nla_data(data[IFLA_CAN_CTRLMODE]);
+ u32 tdc_flags = cm->flags & CAN_CTRLMODE_TDC_MASK;
+@@ -114,6 +105,15 @@ static int can_validate(struct nlattr *tb[], struct nlattr *data[],
+ }
+ }
+
++ if (data[IFLA_CAN_BITTIMING]) {
++ struct can_bittiming bt;
++
++ memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt));
++ err = can_validate_bittiming(&bt, extack);
++ if (err)
++ return err;
++ }
++
+ if (is_can_fd) {
+ if (!data[IFLA_CAN_BITTIMING] || !data[IFLA_CAN_DATA_BITTIMING])
+ return -EOPNOTSUPP;
+@@ -195,48 +195,6 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[],
+ /* We need synchronization with dev->stop() */
+ ASSERT_RTNL();
+
+- if (data[IFLA_CAN_BITTIMING]) {
+- struct can_bittiming bt;
+-
+- /* Do not allow changing bittiming while running */
+- if (dev->flags & IFF_UP)
+- return -EBUSY;
+-
+- /* Calculate bittiming parameters based on
+- * bittiming_const if set, otherwise pass bitrate
+- * directly via do_set_bitrate(). Bail out if neither
+- * is given.
+- */
+- if (!priv->bittiming_const && !priv->do_set_bittiming &&
+- !priv->bitrate_const)
+- return -EOPNOTSUPP;
+-
+- memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt));
+- err = can_get_bittiming(dev, &bt,
+- priv->bittiming_const,
+- priv->bitrate_const,
+- priv->bitrate_const_cnt,
+- extack);
+- if (err)
+- return err;
+-
+- if (priv->bitrate_max && bt.bitrate > priv->bitrate_max) {
+- NL_SET_ERR_MSG_FMT(extack,
+- "arbitration bitrate %u bps surpasses transceiver capabilities of %u bps",
+- bt.bitrate, priv->bitrate_max);
+- return -EINVAL;
+- }
+-
+- memcpy(&priv->bittiming, &bt, sizeof(bt));
+-
+- if (priv->do_set_bittiming) {
+- /* Finally, set the bit-timing registers */
+- err = priv->do_set_bittiming(dev);
+- if (err)
+- return err;
+- }
+- }
+-
+ if (data[IFLA_CAN_CTRLMODE]) {
+ struct can_ctrlmode *cm;
+ u32 ctrlstatic;
+@@ -284,6 +242,48 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[],
+ priv->ctrlmode &= cm->flags | ~CAN_CTRLMODE_TDC_MASK;
+ }
+
++ if (data[IFLA_CAN_BITTIMING]) {
++ struct can_bittiming bt;
++
++ /* Do not allow changing bittiming while running */
++ if (dev->flags & IFF_UP)
++ return -EBUSY;
++
++ /* Calculate bittiming parameters based on
++ * bittiming_const if set, otherwise pass bitrate
++ * directly via do_set_bitrate(). Bail out if neither
++ * is given.
++ */
++ if (!priv->bittiming_const && !priv->do_set_bittiming &&
++ !priv->bitrate_const)
++ return -EOPNOTSUPP;
++
++ memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt));
++ err = can_get_bittiming(dev, &bt,
++ priv->bittiming_const,
++ priv->bitrate_const,
++ priv->bitrate_const_cnt,
++ extack);
++ if (err)
++ return err;
++
++ if (priv->bitrate_max && bt.bitrate > priv->bitrate_max) {
++ NL_SET_ERR_MSG_FMT(extack,
++ "arbitration bitrate %u bps surpasses transceiver capabilities of %u bps",
++ bt.bitrate, priv->bitrate_max);
++ return -EINVAL;
++ }
++
++ memcpy(&priv->bittiming, &bt, sizeof(bt));
++
++ if (priv->do_set_bittiming) {
++ /* Finally, set the bit-timing registers */
++ err = priv->do_set_bittiming(dev);
++ if (err)
++ return err;
++ }
++ }
++
+ if (data[IFLA_CAN_RESTART_MS]) {
+ /* Do not allow changing restart delay while running */
+ if (dev->flags & IFF_UP)
+--
+2.43.0
+
--- /dev/null
+From f9571e8ad38d9421f6495a889213df68eaebc9ae Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 9 Sep 2024 18:32:22 +0200
+Subject: cgroup: Disallow mounting v1 hierarchies without controller
+ implementation
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Michal Koutný <mkoutny@suse.com>
+
+[ Upstream commit 3c41382e920f1dd5c9f432948fe799c07af1cced ]
+
+The configs that disable some v1 controllers would still allow mounting
+them but with no controller-specific files. (Making such hierarchies
+equivalent to named v1 hierarchies.) To achieve behavior consistent with
+actual out-compilation of a whole controller, the mounts should treat
+respective controllers as non-existent.
+
+Wrap implementation into a helper function, leverage legacy_files to
+detect compiled out controllers. The effect is that mounts on v1 would
+fail and produce a message like:
+ [ 1543.999081] cgroup: Unknown subsys name 'memory'
+
+Signed-off-by: Michal Koutný <mkoutny@suse.com>
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/cgroup/cgroup-v1.c | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+diff --git a/kernel/cgroup/cgroup-v1.c b/kernel/cgroup/cgroup-v1.c
+index b9dbf6bf2779d..784337694a4be 100644
+--- a/kernel/cgroup/cgroup-v1.c
++++ b/kernel/cgroup/cgroup-v1.c
+@@ -46,6 +46,12 @@ bool cgroup1_ssid_disabled(int ssid)
+ return cgroup_no_v1_mask & (1 << ssid);
+ }
+
++static bool cgroup1_subsys_absent(struct cgroup_subsys *ss)
++{
++ /* Check also dfl_cftypes for file-less controllers, i.e. perf_event */
++ return ss->legacy_cftypes == NULL && ss->dfl_cftypes;
++}
++
+ /**
+ * cgroup_attach_task_all - attach task 'tsk' to all cgroups of task 'from'
+ * @from: attach to all cgroups of a given task
+@@ -932,7 +938,8 @@ int cgroup1_parse_param(struct fs_context *fc, struct fs_parameter *param)
+ if (ret != -ENOPARAM)
+ return ret;
+ for_each_subsys(ss, i) {
+- if (strcmp(param->key, ss->legacy_name))
++ if (strcmp(param->key, ss->legacy_name) ||
++ cgroup1_subsys_absent(ss))
+ continue;
+ if (!cgroup_ssid_enabled(i) || cgroup1_ssid_disabled(i))
+ return invalfc(fc, "Disabled controller '%s'",
+@@ -1024,7 +1031,8 @@ static int check_cgroupfs_options(struct fs_context *fc)
+ mask = ~((u16)1 << cpuset_cgrp_id);
+ #endif
+ for_each_subsys(ss, i)
+- if (cgroup_ssid_enabled(i) && !cgroup1_ssid_disabled(i))
++ if (cgroup_ssid_enabled(i) && !cgroup1_ssid_disabled(i) &&
++ !cgroup1_subsys_absent(ss))
+ enabled |= 1 << i;
+
+ ctx->subsys_mask &= enabled;
+--
+2.43.0
+
--- /dev/null
+From f0a5649db30d6ff2509281ace680db9cc08ce258 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 18 Jul 2024 11:27:24 -0700
+Subject: coredump: Standartize and fix logging
+
+From: Roman Kisel <romank@linux.microsoft.com>
+
+[ Upstream commit c114e9948c2b6a0b400266e59cc656b59e795bca ]
+
+The coredump code does not log the process ID and the comm
+consistently, logs unescaped comm when it does log it, and
+does not always use the ratelimited logging. That makes it
+harder to analyze logs and puts the system at the risk of
+spamming the system log incase something crashes many times
+over and over again.
+
+Fix that by logging TGID and comm (escaped) consistently and
+using the ratelimited logging always.
+
+Signed-off-by: Roman Kisel <romank@linux.microsoft.com>
+Tested-by: Allen Pais <apais@linux.microsoft.com>
+Link: https://lore.kernel.org/r/20240718182743.1959160-2-romank@linux.microsoft.com
+Signed-off-by: Kees Cook <kees@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/coredump.c | 43 +++++++++++++++-------------------------
+ include/linux/coredump.h | 22 ++++++++++++++++++++
+ 2 files changed, 38 insertions(+), 27 deletions(-)
+
+diff --git a/fs/coredump.c b/fs/coredump.c
+index a57a06b80f571..19d3343b93c6b 100644
+--- a/fs/coredump.c
++++ b/fs/coredump.c
+@@ -586,8 +586,7 @@ void do_coredump(const kernel_siginfo_t *siginfo)
+ struct subprocess_info *sub_info;
+
+ if (ispipe < 0) {
+- printk(KERN_WARNING "format_corename failed\n");
+- printk(KERN_WARNING "Aborting core\n");
++ coredump_report_failure("format_corename failed, aborting core");
+ goto fail_unlock;
+ }
+
+@@ -607,27 +606,21 @@ void do_coredump(const kernel_siginfo_t *siginfo)
+ * right pid if a thread in a multi-threaded
+ * core_pattern process dies.
+ */
+- printk(KERN_WARNING
+- "Process %d(%s) has RLIMIT_CORE set to 1\n",
+- task_tgid_vnr(current), current->comm);
+- printk(KERN_WARNING "Aborting core\n");
++ coredump_report_failure("RLIMIT_CORE is set to 1, aborting core");
+ goto fail_unlock;
+ }
+ cprm.limit = RLIM_INFINITY;
+
+ dump_count = atomic_inc_return(&core_dump_count);
+ if (core_pipe_limit && (core_pipe_limit < dump_count)) {
+- printk(KERN_WARNING "Pid %d(%s) over core_pipe_limit\n",
+- task_tgid_vnr(current), current->comm);
+- printk(KERN_WARNING "Skipping core dump\n");
++ coredump_report_failure("over core_pipe_limit, skipping core dump");
+ goto fail_dropcount;
+ }
+
+ helper_argv = kmalloc_array(argc + 1, sizeof(*helper_argv),
+ GFP_KERNEL);
+ if (!helper_argv) {
+- printk(KERN_WARNING "%s failed to allocate memory\n",
+- __func__);
++ coredump_report_failure("%s failed to allocate memory", __func__);
+ goto fail_dropcount;
+ }
+ for (argi = 0; argi < argc; argi++)
+@@ -644,8 +637,7 @@ void do_coredump(const kernel_siginfo_t *siginfo)
+
+ kfree(helper_argv);
+ if (retval) {
+- printk(KERN_INFO "Core dump to |%s pipe failed\n",
+- cn.corename);
++ coredump_report_failure("|%s pipe failed", cn.corename);
+ goto close_fail;
+ }
+ } else {
+@@ -658,10 +650,8 @@ void do_coredump(const kernel_siginfo_t *siginfo)
+ goto fail_unlock;
+
+ if (need_suid_safe && cn.corename[0] != '/') {
+- printk(KERN_WARNING "Pid %d(%s) can only dump core "\
+- "to fully qualified path!\n",
+- task_tgid_vnr(current), current->comm);
+- printk(KERN_WARNING "Skipping core dump\n");
++ coredump_report_failure(
++ "this process can only dump core to a fully qualified path, skipping core dump");
+ goto fail_unlock;
+ }
+
+@@ -730,13 +720,13 @@ void do_coredump(const kernel_siginfo_t *siginfo)
+ idmap = file_mnt_idmap(cprm.file);
+ if (!vfsuid_eq_kuid(i_uid_into_vfsuid(idmap, inode),
+ current_fsuid())) {
+- pr_info_ratelimited("Core dump to %s aborted: cannot preserve file owner\n",
+- cn.corename);
++ coredump_report_failure("Core dump to %s aborted: "
++ "cannot preserve file owner", cn.corename);
+ goto close_fail;
+ }
+ if ((inode->i_mode & 0677) != 0600) {
+- pr_info_ratelimited("Core dump to %s aborted: cannot preserve file permissions\n",
+- cn.corename);
++ coredump_report_failure("Core dump to %s aborted: "
++ "cannot preserve file permissions", cn.corename);
+ goto close_fail;
+ }
+ if (!(cprm.file->f_mode & FMODE_CAN_WRITE))
+@@ -757,7 +747,7 @@ void do_coredump(const kernel_siginfo_t *siginfo)
+ * have this set to NULL.
+ */
+ if (!cprm.file) {
+- pr_info("Core dump to |%s disabled\n", cn.corename);
++ coredump_report_failure("Core dump to |%s disabled", cn.corename);
+ goto close_fail;
+ }
+ if (!dump_vma_snapshot(&cprm))
+@@ -983,11 +973,10 @@ void validate_coredump_safety(void)
+ {
+ if (suid_dumpable == SUID_DUMP_ROOT &&
+ core_pattern[0] != '/' && core_pattern[0] != '|') {
+- pr_warn(
+-"Unsafe core_pattern used with fs.suid_dumpable=2.\n"
+-"Pipe handler or fully qualified core dump path required.\n"
+-"Set kernel.core_pattern before fs.suid_dumpable.\n"
+- );
++
++ coredump_report_failure("Unsafe core_pattern used with fs.suid_dumpable=2: "
++ "pipe handler or fully qualified core dump path required. "
++ "Set kernel.core_pattern before fs.suid_dumpable.");
+ }
+ }
+
+diff --git a/include/linux/coredump.h b/include/linux/coredump.h
+index 0904ba010341a..45e598fe34766 100644
+--- a/include/linux/coredump.h
++++ b/include/linux/coredump.h
+@@ -43,8 +43,30 @@ extern int dump_align(struct coredump_params *cprm, int align);
+ int dump_user_range(struct coredump_params *cprm, unsigned long start,
+ unsigned long len);
+ extern void do_coredump(const kernel_siginfo_t *siginfo);
++
++/*
++ * Logging for the coredump code, ratelimited.
++ * The TGID and comm fields are added to the message.
++ */
++
++#define __COREDUMP_PRINTK(Level, Format, ...) \
++ do { \
++ char comm[TASK_COMM_LEN]; \
++ \
++ get_task_comm(comm, current); \
++ printk_ratelimited(Level "coredump: %d(%*pE): " Format "\n", \
++ task_tgid_vnr(current), (int)strlen(comm), comm, ##__VA_ARGS__); \
++ } while (0) \
++
++#define coredump_report(fmt, ...) __COREDUMP_PRINTK(KERN_INFO, fmt, ##__VA_ARGS__)
++#define coredump_report_failure(fmt, ...) __COREDUMP_PRINTK(KERN_WARNING, fmt, ##__VA_ARGS__)
++
+ #else
+ static inline void do_coredump(const kernel_siginfo_t *siginfo) {}
++
++#define coredump_report(...)
++#define coredump_report_failure(...)
++
+ #endif
+
+ #if defined(CONFIG_COREDUMP) && defined(CONFIG_SYSCTL)
+--
+2.43.0
+
--- /dev/null
+From 0141cf80196a1bcd3a305dc815841fa3c23708d9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 31 Aug 2024 17:50:07 +0800
+Subject: crypto: hisilicon - fix missed error branch
+
+From: Yang Shen <shenyang39@huawei.com>
+
+[ Upstream commit f386dc64e1a5d3dcb84579119ec350ab026fea88 ]
+
+If an error occurs in the process after the SGL is mapped
+successfully, it need to unmap the SGL.
+
+Otherwise, memory problems may occur.
+
+Signed-off-by: Yang Shen <shenyang39@huawei.com>
+Signed-off-by: Chenghai Huang <huangchenghai2@huawei.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/crypto/hisilicon/sgl.c | 14 ++++++++++----
+ 1 file changed, 10 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/crypto/hisilicon/sgl.c b/drivers/crypto/hisilicon/sgl.c
+index 568acd0aee3fa..c974f95cd126f 100644
+--- a/drivers/crypto/hisilicon/sgl.c
++++ b/drivers/crypto/hisilicon/sgl.c
+@@ -225,7 +225,7 @@ hisi_acc_sg_buf_map_to_hw_sgl(struct device *dev,
+ dma_addr_t curr_sgl_dma = 0;
+ struct acc_hw_sge *curr_hw_sge;
+ struct scatterlist *sg;
+- int sg_n;
++ int sg_n, ret;
+
+ if (!dev || !sgl || !pool || !hw_sgl_dma || index >= pool->count)
+ return ERR_PTR(-EINVAL);
+@@ -240,14 +240,15 @@ hisi_acc_sg_buf_map_to_hw_sgl(struct device *dev,
+
+ if (sg_n_mapped > pool->sge_nr) {
+ dev_err(dev, "the number of entries in input scatterlist is bigger than SGL pool setting.\n");
+- return ERR_PTR(-EINVAL);
++ ret = -EINVAL;
++ goto err_unmap;
+ }
+
+ curr_hw_sgl = acc_get_sgl(pool, index, &curr_sgl_dma);
+ if (IS_ERR(curr_hw_sgl)) {
+ dev_err(dev, "Get SGL error!\n");
+- dma_unmap_sg(dev, sgl, sg_n, DMA_BIDIRECTIONAL);
+- return ERR_PTR(-ENOMEM);
++ ret = -ENOMEM;
++ goto err_unmap;
+ }
+ curr_hw_sgl->entry_length_in_sgl = cpu_to_le16(pool->sge_nr);
+ curr_hw_sge = curr_hw_sgl->sge_entries;
+@@ -262,6 +263,11 @@ hisi_acc_sg_buf_map_to_hw_sgl(struct device *dev,
+ *hw_sgl_dma = curr_sgl_dma;
+
+ return curr_hw_sgl;
++
++err_unmap:
++ dma_unmap_sg(dev, sgl, sg_n, DMA_BIDIRECTIONAL);
++
++ return ERR_PTR(ret);
+ }
+ EXPORT_SYMBOL_GPL(hisi_acc_sg_buf_map_to_hw_sgl);
+
+--
+2.43.0
+
--- /dev/null
+From f9b0de8781f1488819b6a7ebeff5759c18e4a7f1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 17 Aug 2024 12:13:23 +0800
+Subject: crypto: octeontx - Fix authenc setkey
+
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+[ Upstream commit 311eea7e37c4c0b44b557d0c100860a03b4eab65 ]
+
+Use the generic crypto_authenc_extractkeys helper instead of custom
+parsing code that is slightly broken. Also fix a number of memory
+leaks by moving memory allocation from setkey to init_tfm (setkey
+can be called multiple times over the life of a tfm).
+
+Finally accept all hash key lengths by running the digest over
+extra-long keys.
+
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../crypto/marvell/octeontx/otx_cptvf_algs.c | 261 +++++++-----------
+ 1 file changed, 93 insertions(+), 168 deletions(-)
+
+diff --git a/drivers/crypto/marvell/octeontx/otx_cptvf_algs.c b/drivers/crypto/marvell/octeontx/otx_cptvf_algs.c
+index 3c5d577d8f0d5..0a1b85ad0057f 100644
+--- a/drivers/crypto/marvell/octeontx/otx_cptvf_algs.c
++++ b/drivers/crypto/marvell/octeontx/otx_cptvf_algs.c
+@@ -17,7 +17,6 @@
+ #include <crypto/sha2.h>
+ #include <crypto/xts.h>
+ #include <crypto/scatterwalk.h>
+-#include <linux/rtnetlink.h>
+ #include <linux/sort.h>
+ #include <linux/module.h>
+ #include "otx_cptvf.h"
+@@ -66,6 +65,8 @@ static struct cpt_device_table ae_devices = {
+ .count = ATOMIC_INIT(0)
+ };
+
++static struct otx_cpt_sdesc *alloc_sdesc(struct crypto_shash *alg);
++
+ static inline int get_se_device(struct pci_dev **pdev, int *cpu_num)
+ {
+ int count, ret = 0;
+@@ -509,44 +510,61 @@ static int cpt_aead_init(struct crypto_aead *tfm, u8 cipher_type, u8 mac_type)
+ ctx->cipher_type = cipher_type;
+ ctx->mac_type = mac_type;
+
++ switch (ctx->mac_type) {
++ case OTX_CPT_SHA1:
++ ctx->hashalg = crypto_alloc_shash("sha1", 0, 0);
++ break;
++
++ case OTX_CPT_SHA256:
++ ctx->hashalg = crypto_alloc_shash("sha256", 0, 0);
++ break;
++
++ case OTX_CPT_SHA384:
++ ctx->hashalg = crypto_alloc_shash("sha384", 0, 0);
++ break;
++
++ case OTX_CPT_SHA512:
++ ctx->hashalg = crypto_alloc_shash("sha512", 0, 0);
++ break;
++ }
++
++ if (IS_ERR(ctx->hashalg))
++ return PTR_ERR(ctx->hashalg);
++
++ crypto_aead_set_reqsize_dma(tfm, sizeof(struct otx_cpt_req_ctx));
++
++ if (!ctx->hashalg)
++ return 0;
++
+ /*
+ * When selected cipher is NULL we use HMAC opcode instead of
+ * FLEXICRYPTO opcode therefore we don't need to use HASH algorithms
+ * for calculating ipad and opad
+ */
+ if (ctx->cipher_type != OTX_CPT_CIPHER_NULL) {
+- switch (ctx->mac_type) {
+- case OTX_CPT_SHA1:
+- ctx->hashalg = crypto_alloc_shash("sha1", 0,
+- CRYPTO_ALG_ASYNC);
+- if (IS_ERR(ctx->hashalg))
+- return PTR_ERR(ctx->hashalg);
+- break;
+-
+- case OTX_CPT_SHA256:
+- ctx->hashalg = crypto_alloc_shash("sha256", 0,
+- CRYPTO_ALG_ASYNC);
+- if (IS_ERR(ctx->hashalg))
+- return PTR_ERR(ctx->hashalg);
+- break;
++ int ss = crypto_shash_statesize(ctx->hashalg);
+
+- case OTX_CPT_SHA384:
+- ctx->hashalg = crypto_alloc_shash("sha384", 0,
+- CRYPTO_ALG_ASYNC);
+- if (IS_ERR(ctx->hashalg))
+- return PTR_ERR(ctx->hashalg);
+- break;
++ ctx->ipad = kzalloc(ss, GFP_KERNEL);
++ if (!ctx->ipad) {
++ crypto_free_shash(ctx->hashalg);
++ return -ENOMEM;
++ }
+
+- case OTX_CPT_SHA512:
+- ctx->hashalg = crypto_alloc_shash("sha512", 0,
+- CRYPTO_ALG_ASYNC);
+- if (IS_ERR(ctx->hashalg))
+- return PTR_ERR(ctx->hashalg);
+- break;
++ ctx->opad = kzalloc(ss, GFP_KERNEL);
++ if (!ctx->opad) {
++ kfree(ctx->ipad);
++ crypto_free_shash(ctx->hashalg);
++ return -ENOMEM;
+ }
+ }
+
+- crypto_aead_set_reqsize_dma(tfm, sizeof(struct otx_cpt_req_ctx));
++ ctx->sdesc = alloc_sdesc(ctx->hashalg);
++ if (!ctx->sdesc) {
++ kfree(ctx->opad);
++ kfree(ctx->ipad);
++ crypto_free_shash(ctx->hashalg);
++ return -ENOMEM;
++ }
+
+ return 0;
+ }
+@@ -602,8 +620,7 @@ static void otx_cpt_aead_exit(struct crypto_aead *tfm)
+
+ kfree(ctx->ipad);
+ kfree(ctx->opad);
+- if (ctx->hashalg)
+- crypto_free_shash(ctx->hashalg);
++ crypto_free_shash(ctx->hashalg);
+ kfree(ctx->sdesc);
+ }
+
+@@ -699,7 +716,7 @@ static inline void swap_data64(void *buf, u32 len)
+ *dst = cpu_to_be64p(src);
+ }
+
+-static int copy_pad(u8 mac_type, u8 *out_pad, u8 *in_pad)
++static int swap_pad(u8 mac_type, u8 *pad)
+ {
+ struct sha512_state *sha512;
+ struct sha256_state *sha256;
+@@ -707,22 +724,19 @@ static int copy_pad(u8 mac_type, u8 *out_pad, u8 *in_pad)
+
+ switch (mac_type) {
+ case OTX_CPT_SHA1:
+- sha1 = (struct sha1_state *) in_pad;
++ sha1 = (struct sha1_state *)pad;
+ swap_data32(sha1->state, SHA1_DIGEST_SIZE);
+- memcpy(out_pad, &sha1->state, SHA1_DIGEST_SIZE);
+ break;
+
+ case OTX_CPT_SHA256:
+- sha256 = (struct sha256_state *) in_pad;
++ sha256 = (struct sha256_state *)pad;
+ swap_data32(sha256->state, SHA256_DIGEST_SIZE);
+- memcpy(out_pad, &sha256->state, SHA256_DIGEST_SIZE);
+ break;
+
+ case OTX_CPT_SHA384:
+ case OTX_CPT_SHA512:
+- sha512 = (struct sha512_state *) in_pad;
++ sha512 = (struct sha512_state *)pad;
+ swap_data64(sha512->state, SHA512_DIGEST_SIZE);
+- memcpy(out_pad, &sha512->state, SHA512_DIGEST_SIZE);
+ break;
+
+ default:
+@@ -732,55 +746,53 @@ static int copy_pad(u8 mac_type, u8 *out_pad, u8 *in_pad)
+ return 0;
+ }
+
+-static int aead_hmac_init(struct crypto_aead *cipher)
++static int aead_hmac_init(struct crypto_aead *cipher,
++ struct crypto_authenc_keys *keys)
+ {
+ struct otx_cpt_aead_ctx *ctx = crypto_aead_ctx_dma(cipher);
+- int state_size = crypto_shash_statesize(ctx->hashalg);
+ int ds = crypto_shash_digestsize(ctx->hashalg);
+ int bs = crypto_shash_blocksize(ctx->hashalg);
+- int authkeylen = ctx->auth_key_len;
++ int authkeylen = keys->authkeylen;
+ u8 *ipad = NULL, *opad = NULL;
+- int ret = 0, icount = 0;
++ int icount = 0;
++ int ret;
+
+- ctx->sdesc = alloc_sdesc(ctx->hashalg);
+- if (!ctx->sdesc)
+- return -ENOMEM;
++ if (authkeylen > bs) {
++ ret = crypto_shash_digest(&ctx->sdesc->shash, keys->authkey,
++ authkeylen, ctx->key);
++ if (ret)
++ return ret;
++ authkeylen = ds;
++ } else
++ memcpy(ctx->key, keys->authkey, authkeylen);
+
+- ctx->ipad = kzalloc(bs, GFP_KERNEL);
+- if (!ctx->ipad) {
+- ret = -ENOMEM;
+- goto calc_fail;
+- }
++ ctx->enc_key_len = keys->enckeylen;
++ ctx->auth_key_len = authkeylen;
+
+- ctx->opad = kzalloc(bs, GFP_KERNEL);
+- if (!ctx->opad) {
+- ret = -ENOMEM;
+- goto calc_fail;
+- }
++ if (ctx->cipher_type == OTX_CPT_CIPHER_NULL)
++ return keys->enckeylen ? -EINVAL : 0;
+
+- ipad = kzalloc(state_size, GFP_KERNEL);
+- if (!ipad) {
+- ret = -ENOMEM;
+- goto calc_fail;
++ switch (keys->enckeylen) {
++ case AES_KEYSIZE_128:
++ ctx->key_type = OTX_CPT_AES_128_BIT;
++ break;
++ case AES_KEYSIZE_192:
++ ctx->key_type = OTX_CPT_AES_192_BIT;
++ break;
++ case AES_KEYSIZE_256:
++ ctx->key_type = OTX_CPT_AES_256_BIT;
++ break;
++ default:
++ /* Invalid key length */
++ return -EINVAL;
+ }
+
+- opad = kzalloc(state_size, GFP_KERNEL);
+- if (!opad) {
+- ret = -ENOMEM;
+- goto calc_fail;
+- }
++ memcpy(ctx->key + authkeylen, keys->enckey, keys->enckeylen);
+
+- if (authkeylen > bs) {
+- ret = crypto_shash_digest(&ctx->sdesc->shash, ctx->key,
+- authkeylen, ipad);
+- if (ret)
+- goto calc_fail;
+-
+- authkeylen = ds;
+- } else {
+- memcpy(ipad, ctx->key, authkeylen);
+- }
++ ipad = ctx->ipad;
++ opad = ctx->opad;
+
++ memcpy(ipad, ctx->key, authkeylen);
+ memset(ipad + authkeylen, 0, bs - authkeylen);
+ memcpy(opad, ipad, bs);
+
+@@ -798,7 +810,7 @@ static int aead_hmac_init(struct crypto_aead *cipher)
+ crypto_shash_init(&ctx->sdesc->shash);
+ crypto_shash_update(&ctx->sdesc->shash, ipad, bs);
+ crypto_shash_export(&ctx->sdesc->shash, ipad);
+- ret = copy_pad(ctx->mac_type, ctx->ipad, ipad);
++ ret = swap_pad(ctx->mac_type, ipad);
+ if (ret)
+ goto calc_fail;
+
+@@ -806,25 +818,9 @@ static int aead_hmac_init(struct crypto_aead *cipher)
+ crypto_shash_init(&ctx->sdesc->shash);
+ crypto_shash_update(&ctx->sdesc->shash, opad, bs);
+ crypto_shash_export(&ctx->sdesc->shash, opad);
+- ret = copy_pad(ctx->mac_type, ctx->opad, opad);
+- if (ret)
+- goto calc_fail;
+-
+- kfree(ipad);
+- kfree(opad);
+-
+- return 0;
++ ret = swap_pad(ctx->mac_type, opad);
+
+ calc_fail:
+- kfree(ctx->ipad);
+- ctx->ipad = NULL;
+- kfree(ctx->opad);
+- ctx->opad = NULL;
+- kfree(ipad);
+- kfree(opad);
+- kfree(ctx->sdesc);
+- ctx->sdesc = NULL;
+-
+ return ret;
+ }
+
+@@ -832,57 +828,15 @@ static int otx_cpt_aead_cbc_aes_sha_setkey(struct crypto_aead *cipher,
+ const unsigned char *key,
+ unsigned int keylen)
+ {
+- struct otx_cpt_aead_ctx *ctx = crypto_aead_ctx_dma(cipher);
+- struct crypto_authenc_key_param *param;
+- int enckeylen = 0, authkeylen = 0;
+- struct rtattr *rta = (void *)key;
+- int status = -EINVAL;
+-
+- if (!RTA_OK(rta, keylen))
+- goto badkey;
+-
+- if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM)
+- goto badkey;
+-
+- if (RTA_PAYLOAD(rta) < sizeof(*param))
+- goto badkey;
+-
+- param = RTA_DATA(rta);
+- enckeylen = be32_to_cpu(param->enckeylen);
+- key += RTA_ALIGN(rta->rta_len);
+- keylen -= RTA_ALIGN(rta->rta_len);
+- if (keylen < enckeylen)
+- goto badkey;
++ struct crypto_authenc_keys authenc_keys;
++ int status;
+
+- if (keylen > OTX_CPT_MAX_KEY_SIZE)
+- goto badkey;
+-
+- authkeylen = keylen - enckeylen;
+- memcpy(ctx->key, key, keylen);
+-
+- switch (enckeylen) {
+- case AES_KEYSIZE_128:
+- ctx->key_type = OTX_CPT_AES_128_BIT;
+- break;
+- case AES_KEYSIZE_192:
+- ctx->key_type = OTX_CPT_AES_192_BIT;
+- break;
+- case AES_KEYSIZE_256:
+- ctx->key_type = OTX_CPT_AES_256_BIT;
+- break;
+- default:
+- /* Invalid key length */
+- goto badkey;
+- }
+-
+- ctx->enc_key_len = enckeylen;
+- ctx->auth_key_len = authkeylen;
+-
+- status = aead_hmac_init(cipher);
++ status = crypto_authenc_extractkeys(&authenc_keys, key, keylen);
+ if (status)
+ goto badkey;
+
+- return 0;
++ status = aead_hmac_init(cipher, &authenc_keys);
++
+ badkey:
+ return status;
+ }
+@@ -891,36 +845,7 @@ static int otx_cpt_aead_ecb_null_sha_setkey(struct crypto_aead *cipher,
+ const unsigned char *key,
+ unsigned int keylen)
+ {
+- struct otx_cpt_aead_ctx *ctx = crypto_aead_ctx_dma(cipher);
+- struct crypto_authenc_key_param *param;
+- struct rtattr *rta = (void *)key;
+- int enckeylen = 0;
+-
+- if (!RTA_OK(rta, keylen))
+- goto badkey;
+-
+- if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM)
+- goto badkey;
+-
+- if (RTA_PAYLOAD(rta) < sizeof(*param))
+- goto badkey;
+-
+- param = RTA_DATA(rta);
+- enckeylen = be32_to_cpu(param->enckeylen);
+- key += RTA_ALIGN(rta->rta_len);
+- keylen -= RTA_ALIGN(rta->rta_len);
+- if (enckeylen != 0)
+- goto badkey;
+-
+- if (keylen > OTX_CPT_MAX_KEY_SIZE)
+- goto badkey;
+-
+- memcpy(ctx->key, key, keylen);
+- ctx->enc_key_len = enckeylen;
+- ctx->auth_key_len = keylen;
+- return 0;
+-badkey:
+- return -EINVAL;
++ return otx_cpt_aead_cbc_aes_sha_setkey(cipher, key, keylen);
+ }
+
+ static int otx_cpt_aead_gcm_aes_setkey(struct crypto_aead *cipher,
+--
+2.43.0
+
--- /dev/null
+From 52307b37bb13b345c675f270db9d59b939d939f9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 17 Aug 2024 12:36:19 +0800
+Subject: crypto: octeontx2 - Fix authenc setkey
+
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+[ Upstream commit 7ccb750dcac8abbfc7743aab0db6a72c1c3703c7 ]
+
+Use the generic crypto_authenc_extractkeys helper instead of custom
+parsing code that is slightly broken. Also fix a number of memory
+leaks by moving memory allocation from setkey to init_tfm (setkey
+can be called multiple times over the life of a tfm).
+
+Finally accept all hash key lengths by running the digest over
+extra-long keys.
+
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../marvell/octeontx2/otx2_cptvf_algs.c | 254 +++++++-----------
+ 1 file changed, 90 insertions(+), 164 deletions(-)
+
+diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c b/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c
+index 1604fc58dc13e..5aa56f20f888c 100644
+--- a/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c
++++ b/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c
+@@ -11,7 +11,6 @@
+ #include <crypto/xts.h>
+ #include <crypto/gcm.h>
+ #include <crypto/scatterwalk.h>
+-#include <linux/rtnetlink.h>
+ #include <linux/sort.h>
+ #include <linux/module.h>
+ #include "otx2_cptvf.h"
+@@ -55,6 +54,8 @@ static struct cpt_device_table se_devices = {
+ .count = ATOMIC_INIT(0)
+ };
+
++static struct otx2_cpt_sdesc *alloc_sdesc(struct crypto_shash *alg);
++
+ static inline int get_se_device(struct pci_dev **pdev, int *cpu_num)
+ {
+ int count;
+@@ -598,40 +599,56 @@ static int cpt_aead_init(struct crypto_aead *atfm, u8 cipher_type, u8 mac_type)
+ ctx->cipher_type = cipher_type;
+ ctx->mac_type = mac_type;
+
++ switch (ctx->mac_type) {
++ case OTX2_CPT_SHA1:
++ ctx->hashalg = crypto_alloc_shash("sha1", 0, 0);
++ break;
++
++ case OTX2_CPT_SHA256:
++ ctx->hashalg = crypto_alloc_shash("sha256", 0, 0);
++ break;
++
++ case OTX2_CPT_SHA384:
++ ctx->hashalg = crypto_alloc_shash("sha384", 0, 0);
++ break;
++
++ case OTX2_CPT_SHA512:
++ ctx->hashalg = crypto_alloc_shash("sha512", 0, 0);
++ break;
++ }
++
++ if (IS_ERR(ctx->hashalg))
++ return PTR_ERR(ctx->hashalg);
++
++ if (ctx->hashalg) {
++ ctx->sdesc = alloc_sdesc(ctx->hashalg);
++ if (!ctx->sdesc) {
++ crypto_free_shash(ctx->hashalg);
++ return -ENOMEM;
++ }
++ }
++
+ /*
+ * When selected cipher is NULL we use HMAC opcode instead of
+ * FLEXICRYPTO opcode therefore we don't need to use HASH algorithms
+ * for calculating ipad and opad
+ */
+- if (ctx->cipher_type != OTX2_CPT_CIPHER_NULL) {
+- switch (ctx->mac_type) {
+- case OTX2_CPT_SHA1:
+- ctx->hashalg = crypto_alloc_shash("sha1", 0,
+- CRYPTO_ALG_ASYNC);
+- if (IS_ERR(ctx->hashalg))
+- return PTR_ERR(ctx->hashalg);
+- break;
+-
+- case OTX2_CPT_SHA256:
+- ctx->hashalg = crypto_alloc_shash("sha256", 0,
+- CRYPTO_ALG_ASYNC);
+- if (IS_ERR(ctx->hashalg))
+- return PTR_ERR(ctx->hashalg);
+- break;
++ if (ctx->cipher_type != OTX2_CPT_CIPHER_NULL && ctx->hashalg) {
++ int ss = crypto_shash_statesize(ctx->hashalg);
+
+- case OTX2_CPT_SHA384:
+- ctx->hashalg = crypto_alloc_shash("sha384", 0,
+- CRYPTO_ALG_ASYNC);
+- if (IS_ERR(ctx->hashalg))
+- return PTR_ERR(ctx->hashalg);
+- break;
++ ctx->ipad = kzalloc(ss, GFP_KERNEL);
++ if (!ctx->ipad) {
++ kfree(ctx->sdesc);
++ crypto_free_shash(ctx->hashalg);
++ return -ENOMEM;
++ }
+
+- case OTX2_CPT_SHA512:
+- ctx->hashalg = crypto_alloc_shash("sha512", 0,
+- CRYPTO_ALG_ASYNC);
+- if (IS_ERR(ctx->hashalg))
+- return PTR_ERR(ctx->hashalg);
+- break;
++ ctx->opad = kzalloc(ss, GFP_KERNEL);
++ if (!ctx->opad) {
++ kfree(ctx->ipad);
++ kfree(ctx->sdesc);
++ crypto_free_shash(ctx->hashalg);
++ return -ENOMEM;
+ }
+ }
+ switch (ctx->cipher_type) {
+@@ -713,8 +730,7 @@ static void otx2_cpt_aead_exit(struct crypto_aead *tfm)
+
+ kfree(ctx->ipad);
+ kfree(ctx->opad);
+- if (ctx->hashalg)
+- crypto_free_shash(ctx->hashalg);
++ crypto_free_shash(ctx->hashalg);
+ kfree(ctx->sdesc);
+
+ if (ctx->fbk_cipher) {
+@@ -788,7 +804,7 @@ static inline void swap_data64(void *buf, u32 len)
+ cpu_to_be64s(src);
+ }
+
+-static int copy_pad(u8 mac_type, u8 *out_pad, u8 *in_pad)
++static int swap_pad(u8 mac_type, u8 *pad)
+ {
+ struct sha512_state *sha512;
+ struct sha256_state *sha256;
+@@ -796,22 +812,19 @@ static int copy_pad(u8 mac_type, u8 *out_pad, u8 *in_pad)
+
+ switch (mac_type) {
+ case OTX2_CPT_SHA1:
+- sha1 = (struct sha1_state *) in_pad;
++ sha1 = (struct sha1_state *)pad;
+ swap_data32(sha1->state, SHA1_DIGEST_SIZE);
+- memcpy(out_pad, &sha1->state, SHA1_DIGEST_SIZE);
+ break;
+
+ case OTX2_CPT_SHA256:
+- sha256 = (struct sha256_state *) in_pad;
++ sha256 = (struct sha256_state *)pad;
+ swap_data32(sha256->state, SHA256_DIGEST_SIZE);
+- memcpy(out_pad, &sha256->state, SHA256_DIGEST_SIZE);
+ break;
+
+ case OTX2_CPT_SHA384:
+ case OTX2_CPT_SHA512:
+- sha512 = (struct sha512_state *) in_pad;
++ sha512 = (struct sha512_state *)pad;
+ swap_data64(sha512->state, SHA512_DIGEST_SIZE);
+- memcpy(out_pad, &sha512->state, SHA512_DIGEST_SIZE);
+ break;
+
+ default:
+@@ -821,55 +834,54 @@ static int copy_pad(u8 mac_type, u8 *out_pad, u8 *in_pad)
+ return 0;
+ }
+
+-static int aead_hmac_init(struct crypto_aead *cipher)
++static int aead_hmac_init(struct crypto_aead *cipher,
++ struct crypto_authenc_keys *keys)
+ {
+ struct otx2_cpt_aead_ctx *ctx = crypto_aead_ctx_dma(cipher);
+- int state_size = crypto_shash_statesize(ctx->hashalg);
+ int ds = crypto_shash_digestsize(ctx->hashalg);
+ int bs = crypto_shash_blocksize(ctx->hashalg);
+- int authkeylen = ctx->auth_key_len;
++ int authkeylen = keys->authkeylen;
+ u8 *ipad = NULL, *opad = NULL;
+- int ret = 0, icount = 0;
++ int icount = 0;
++ int ret;
+
+- ctx->sdesc = alloc_sdesc(ctx->hashalg);
+- if (!ctx->sdesc)
+- return -ENOMEM;
++ if (authkeylen > bs) {
++ ret = crypto_shash_digest(&ctx->sdesc->shash, keys->authkey,
++ authkeylen, ctx->key);
++ if (ret)
++ goto calc_fail;
+
+- ctx->ipad = kzalloc(bs, GFP_KERNEL);
+- if (!ctx->ipad) {
+- ret = -ENOMEM;
+- goto calc_fail;
+- }
++ authkeylen = ds;
++ } else
++ memcpy(ctx->key, keys->authkey, authkeylen);
+
+- ctx->opad = kzalloc(bs, GFP_KERNEL);
+- if (!ctx->opad) {
+- ret = -ENOMEM;
+- goto calc_fail;
+- }
++ ctx->enc_key_len = keys->enckeylen;
++ ctx->auth_key_len = authkeylen;
+
+- ipad = kzalloc(state_size, GFP_KERNEL);
+- if (!ipad) {
+- ret = -ENOMEM;
+- goto calc_fail;
+- }
++ if (ctx->cipher_type == OTX2_CPT_CIPHER_NULL)
++ return keys->enckeylen ? -EINVAL : 0;
+
+- opad = kzalloc(state_size, GFP_KERNEL);
+- if (!opad) {
+- ret = -ENOMEM;
+- goto calc_fail;
++ switch (keys->enckeylen) {
++ case AES_KEYSIZE_128:
++ ctx->key_type = OTX2_CPT_AES_128_BIT;
++ break;
++ case AES_KEYSIZE_192:
++ ctx->key_type = OTX2_CPT_AES_192_BIT;
++ break;
++ case AES_KEYSIZE_256:
++ ctx->key_type = OTX2_CPT_AES_256_BIT;
++ break;
++ default:
++ /* Invalid key length */
++ return -EINVAL;
+ }
+
+- if (authkeylen > bs) {
+- ret = crypto_shash_digest(&ctx->sdesc->shash, ctx->key,
+- authkeylen, ipad);
+- if (ret)
+- goto calc_fail;
++ memcpy(ctx->key + authkeylen, keys->enckey, keys->enckeylen);
+
+- authkeylen = ds;
+- } else {
+- memcpy(ipad, ctx->key, authkeylen);
+- }
++ ipad = ctx->ipad;
++ opad = ctx->opad;
+
++ memcpy(ipad, ctx->key, authkeylen);
+ memset(ipad + authkeylen, 0, bs - authkeylen);
+ memcpy(opad, ipad, bs);
+
+@@ -887,7 +899,7 @@ static int aead_hmac_init(struct crypto_aead *cipher)
+ crypto_shash_init(&ctx->sdesc->shash);
+ crypto_shash_update(&ctx->sdesc->shash, ipad, bs);
+ crypto_shash_export(&ctx->sdesc->shash, ipad);
+- ret = copy_pad(ctx->mac_type, ctx->ipad, ipad);
++ ret = swap_pad(ctx->mac_type, ipad);
+ if (ret)
+ goto calc_fail;
+
+@@ -895,25 +907,9 @@ static int aead_hmac_init(struct crypto_aead *cipher)
+ crypto_shash_init(&ctx->sdesc->shash);
+ crypto_shash_update(&ctx->sdesc->shash, opad, bs);
+ crypto_shash_export(&ctx->sdesc->shash, opad);
+- ret = copy_pad(ctx->mac_type, ctx->opad, opad);
+- if (ret)
+- goto calc_fail;
+-
+- kfree(ipad);
+- kfree(opad);
+-
+- return 0;
++ ret = swap_pad(ctx->mac_type, opad);
+
+ calc_fail:
+- kfree(ctx->ipad);
+- ctx->ipad = NULL;
+- kfree(ctx->opad);
+- ctx->opad = NULL;
+- kfree(ipad);
+- kfree(opad);
+- kfree(ctx->sdesc);
+- ctx->sdesc = NULL;
+-
+ return ret;
+ }
+
+@@ -921,87 +917,17 @@ static int otx2_cpt_aead_cbc_aes_sha_setkey(struct crypto_aead *cipher,
+ const unsigned char *key,
+ unsigned int keylen)
+ {
+- struct otx2_cpt_aead_ctx *ctx = crypto_aead_ctx_dma(cipher);
+- struct crypto_authenc_key_param *param;
+- int enckeylen = 0, authkeylen = 0;
+- struct rtattr *rta = (void *)key;
+-
+- if (!RTA_OK(rta, keylen))
+- return -EINVAL;
++ struct crypto_authenc_keys authenc_keys;
+
+- if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM)
+- return -EINVAL;
+-
+- if (RTA_PAYLOAD(rta) < sizeof(*param))
+- return -EINVAL;
+-
+- param = RTA_DATA(rta);
+- enckeylen = be32_to_cpu(param->enckeylen);
+- key += RTA_ALIGN(rta->rta_len);
+- keylen -= RTA_ALIGN(rta->rta_len);
+- if (keylen < enckeylen)
+- return -EINVAL;
+-
+- if (keylen > OTX2_CPT_MAX_KEY_SIZE)
+- return -EINVAL;
+-
+- authkeylen = keylen - enckeylen;
+- memcpy(ctx->key, key, keylen);
+-
+- switch (enckeylen) {
+- case AES_KEYSIZE_128:
+- ctx->key_type = OTX2_CPT_AES_128_BIT;
+- break;
+- case AES_KEYSIZE_192:
+- ctx->key_type = OTX2_CPT_AES_192_BIT;
+- break;
+- case AES_KEYSIZE_256:
+- ctx->key_type = OTX2_CPT_AES_256_BIT;
+- break;
+- default:
+- /* Invalid key length */
+- return -EINVAL;
+- }
+-
+- ctx->enc_key_len = enckeylen;
+- ctx->auth_key_len = authkeylen;
+-
+- return aead_hmac_init(cipher);
++ return crypto_authenc_extractkeys(&authenc_keys, key, keylen) ?:
++ aead_hmac_init(cipher, &authenc_keys);
+ }
+
+ static int otx2_cpt_aead_ecb_null_sha_setkey(struct crypto_aead *cipher,
+ const unsigned char *key,
+ unsigned int keylen)
+ {
+- struct otx2_cpt_aead_ctx *ctx = crypto_aead_ctx_dma(cipher);
+- struct crypto_authenc_key_param *param;
+- struct rtattr *rta = (void *)key;
+- int enckeylen = 0;
+-
+- if (!RTA_OK(rta, keylen))
+- return -EINVAL;
+-
+- if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM)
+- return -EINVAL;
+-
+- if (RTA_PAYLOAD(rta) < sizeof(*param))
+- return -EINVAL;
+-
+- param = RTA_DATA(rta);
+- enckeylen = be32_to_cpu(param->enckeylen);
+- key += RTA_ALIGN(rta->rta_len);
+- keylen -= RTA_ALIGN(rta->rta_len);
+- if (enckeylen != 0)
+- return -EINVAL;
+-
+- if (keylen > OTX2_CPT_MAX_KEY_SIZE)
+- return -EINVAL;
+-
+- memcpy(ctx->key, key, keylen);
+- ctx->enc_key_len = enckeylen;
+- ctx->auth_key_len = keylen;
+-
+- return 0;
++ return otx2_cpt_aead_cbc_aes_sha_setkey(cipher, key, keylen);
+ }
+
+ static int otx2_cpt_aead_gcm_aes_setkey(struct crypto_aead *cipher,
+--
+2.43.0
+
--- /dev/null
+From 647614c471b886f98a09d70bcdd4ae44bcf6dcc8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 17 Aug 2024 14:58:35 +0800
+Subject: crypto: simd - Do not call crypto_alloc_tfm during registration
+
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+[ Upstream commit 3c44d31cb34ce4eb8311a2e73634d57702948230 ]
+
+Algorithm registration is usually carried out during module init,
+where as little work as possible should be carried out. The SIMD
+code violated this rule by allocating a tfm, this then triggers a
+full test of the algorithm which may dead-lock in certain cases.
+
+SIMD is only allocating the tfm to get at the alg object, which is
+in fact already available as it is what we are registering. Use
+that directly and remove the crypto_alloc_tfm call.
+
+Also remove some obsolete and unused SIMD API.
+
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm/crypto/aes-ce-glue.c | 2 +-
+ arch/arm/crypto/aes-neonbs-glue.c | 2 +-
+ crypto/simd.c | 76 ++++++-------------------------
+ include/crypto/internal/simd.h | 12 +----
+ 4 files changed, 19 insertions(+), 73 deletions(-)
+
+diff --git a/arch/arm/crypto/aes-ce-glue.c b/arch/arm/crypto/aes-ce-glue.c
+index b668c97663ec0..f5b66f4cf45d9 100644
+--- a/arch/arm/crypto/aes-ce-glue.c
++++ b/arch/arm/crypto/aes-ce-glue.c
+@@ -711,7 +711,7 @@ static int __init aes_init(void)
+ algname = aes_algs[i].base.cra_name + 2;
+ drvname = aes_algs[i].base.cra_driver_name + 2;
+ basename = aes_algs[i].base.cra_driver_name;
+- simd = simd_skcipher_create_compat(algname, drvname, basename);
++ simd = simd_skcipher_create_compat(aes_algs + i, algname, drvname, basename);
+ err = PTR_ERR(simd);
+ if (IS_ERR(simd))
+ goto unregister_simds;
+diff --git a/arch/arm/crypto/aes-neonbs-glue.c b/arch/arm/crypto/aes-neonbs-glue.c
+index f00f042ef3570..0ca94b90bc4ec 100644
+--- a/arch/arm/crypto/aes-neonbs-glue.c
++++ b/arch/arm/crypto/aes-neonbs-glue.c
+@@ -539,7 +539,7 @@ static int __init aes_init(void)
+ algname = aes_algs[i].base.cra_name + 2;
+ drvname = aes_algs[i].base.cra_driver_name + 2;
+ basename = aes_algs[i].base.cra_driver_name;
+- simd = simd_skcipher_create_compat(algname, drvname, basename);
++ simd = simd_skcipher_create_compat(aes_algs + i, algname, drvname, basename);
+ err = PTR_ERR(simd);
+ if (IS_ERR(simd))
+ goto unregister_simds;
+diff --git a/crypto/simd.c b/crypto/simd.c
+index edaa479a1ec5e..d109866641a26 100644
+--- a/crypto/simd.c
++++ b/crypto/simd.c
+@@ -136,27 +136,19 @@ static int simd_skcipher_init(struct crypto_skcipher *tfm)
+ return 0;
+ }
+
+-struct simd_skcipher_alg *simd_skcipher_create_compat(const char *algname,
++struct simd_skcipher_alg *simd_skcipher_create_compat(struct skcipher_alg *ialg,
++ const char *algname,
+ const char *drvname,
+ const char *basename)
+ {
+ struct simd_skcipher_alg *salg;
+- struct crypto_skcipher *tfm;
+- struct skcipher_alg *ialg;
+ struct skcipher_alg *alg;
+ int err;
+
+- tfm = crypto_alloc_skcipher(basename, CRYPTO_ALG_INTERNAL,
+- CRYPTO_ALG_INTERNAL | CRYPTO_ALG_ASYNC);
+- if (IS_ERR(tfm))
+- return ERR_CAST(tfm);
+-
+- ialg = crypto_skcipher_alg(tfm);
+-
+ salg = kzalloc(sizeof(*salg), GFP_KERNEL);
+ if (!salg) {
+ salg = ERR_PTR(-ENOMEM);
+- goto out_put_tfm;
++ goto out;
+ }
+
+ salg->ialg_name = basename;
+@@ -195,30 +187,16 @@ struct simd_skcipher_alg *simd_skcipher_create_compat(const char *algname,
+ if (err)
+ goto out_free_salg;
+
+-out_put_tfm:
+- crypto_free_skcipher(tfm);
++out:
+ return salg;
+
+ out_free_salg:
+ kfree(salg);
+ salg = ERR_PTR(err);
+- goto out_put_tfm;
++ goto out;
+ }
+ EXPORT_SYMBOL_GPL(simd_skcipher_create_compat);
+
+-struct simd_skcipher_alg *simd_skcipher_create(const char *algname,
+- const char *basename)
+-{
+- char drvname[CRYPTO_MAX_ALG_NAME];
+-
+- if (snprintf(drvname, CRYPTO_MAX_ALG_NAME, "simd-%s", basename) >=
+- CRYPTO_MAX_ALG_NAME)
+- return ERR_PTR(-ENAMETOOLONG);
+-
+- return simd_skcipher_create_compat(algname, drvname, basename);
+-}
+-EXPORT_SYMBOL_GPL(simd_skcipher_create);
+-
+ void simd_skcipher_free(struct simd_skcipher_alg *salg)
+ {
+ crypto_unregister_skcipher(&salg->alg);
+@@ -246,7 +224,7 @@ int simd_register_skciphers_compat(struct skcipher_alg *algs, int count,
+ algname = algs[i].base.cra_name + 2;
+ drvname = algs[i].base.cra_driver_name + 2;
+ basename = algs[i].base.cra_driver_name;
+- simd = simd_skcipher_create_compat(algname, drvname, basename);
++ simd = simd_skcipher_create_compat(algs + i, algname, drvname, basename);
+ err = PTR_ERR(simd);
+ if (IS_ERR(simd))
+ goto err_unregister;
+@@ -383,27 +361,19 @@ static int simd_aead_init(struct crypto_aead *tfm)
+ return 0;
+ }
+
+-struct simd_aead_alg *simd_aead_create_compat(const char *algname,
+- const char *drvname,
+- const char *basename)
++static struct simd_aead_alg *simd_aead_create_compat(struct aead_alg *ialg,
++ const char *algname,
++ const char *drvname,
++ const char *basename)
+ {
+ struct simd_aead_alg *salg;
+- struct crypto_aead *tfm;
+- struct aead_alg *ialg;
+ struct aead_alg *alg;
+ int err;
+
+- tfm = crypto_alloc_aead(basename, CRYPTO_ALG_INTERNAL,
+- CRYPTO_ALG_INTERNAL | CRYPTO_ALG_ASYNC);
+- if (IS_ERR(tfm))
+- return ERR_CAST(tfm);
+-
+- ialg = crypto_aead_alg(tfm);
+-
+ salg = kzalloc(sizeof(*salg), GFP_KERNEL);
+ if (!salg) {
+ salg = ERR_PTR(-ENOMEM);
+- goto out_put_tfm;
++ goto out;
+ }
+
+ salg->ialg_name = basename;
+@@ -442,36 +412,20 @@ struct simd_aead_alg *simd_aead_create_compat(const char *algname,
+ if (err)
+ goto out_free_salg;
+
+-out_put_tfm:
+- crypto_free_aead(tfm);
++out:
+ return salg;
+
+ out_free_salg:
+ kfree(salg);
+ salg = ERR_PTR(err);
+- goto out_put_tfm;
+-}
+-EXPORT_SYMBOL_GPL(simd_aead_create_compat);
+-
+-struct simd_aead_alg *simd_aead_create(const char *algname,
+- const char *basename)
+-{
+- char drvname[CRYPTO_MAX_ALG_NAME];
+-
+- if (snprintf(drvname, CRYPTO_MAX_ALG_NAME, "simd-%s", basename) >=
+- CRYPTO_MAX_ALG_NAME)
+- return ERR_PTR(-ENAMETOOLONG);
+-
+- return simd_aead_create_compat(algname, drvname, basename);
++ goto out;
+ }
+-EXPORT_SYMBOL_GPL(simd_aead_create);
+
+-void simd_aead_free(struct simd_aead_alg *salg)
++static void simd_aead_free(struct simd_aead_alg *salg)
+ {
+ crypto_unregister_aead(&salg->alg);
+ kfree(salg);
+ }
+-EXPORT_SYMBOL_GPL(simd_aead_free);
+
+ int simd_register_aeads_compat(struct aead_alg *algs, int count,
+ struct simd_aead_alg **simd_algs)
+@@ -493,7 +447,7 @@ int simd_register_aeads_compat(struct aead_alg *algs, int count,
+ algname = algs[i].base.cra_name + 2;
+ drvname = algs[i].base.cra_driver_name + 2;
+ basename = algs[i].base.cra_driver_name;
+- simd = simd_aead_create_compat(algname, drvname, basename);
++ simd = simd_aead_create_compat(algs + i, algname, drvname, basename);
+ err = PTR_ERR(simd);
+ if (IS_ERR(simd))
+ goto err_unregister;
+diff --git a/include/crypto/internal/simd.h b/include/crypto/internal/simd.h
+index d2316242a9884..be97b97a75dd2 100644
+--- a/include/crypto/internal/simd.h
++++ b/include/crypto/internal/simd.h
+@@ -14,11 +14,10 @@
+ struct simd_skcipher_alg;
+ struct skcipher_alg;
+
+-struct simd_skcipher_alg *simd_skcipher_create_compat(const char *algname,
++struct simd_skcipher_alg *simd_skcipher_create_compat(struct skcipher_alg *ialg,
++ const char *algname,
+ const char *drvname,
+ const char *basename);
+-struct simd_skcipher_alg *simd_skcipher_create(const char *algname,
+- const char *basename);
+ void simd_skcipher_free(struct simd_skcipher_alg *alg);
+
+ int simd_register_skciphers_compat(struct skcipher_alg *algs, int count,
+@@ -32,13 +31,6 @@ void simd_unregister_skciphers(struct skcipher_alg *algs, int count,
+ struct simd_aead_alg;
+ struct aead_alg;
+
+-struct simd_aead_alg *simd_aead_create_compat(const char *algname,
+- const char *drvname,
+- const char *basename);
+-struct simd_aead_alg *simd_aead_create(const char *algname,
+- const char *basename);
+-void simd_aead_free(struct simd_aead_alg *alg);
+-
+ int simd_register_aeads_compat(struct aead_alg *algs, int count,
+ struct simd_aead_alg **simd_algs);
+
+--
+2.43.0
+
--- /dev/null
+From d0305bdd838b5c6a7f732265840a33791e7ca8fc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 13 Aug 2024 21:48:02 -0700
+Subject: crypto: x86/sha256 - Add parentheses around macros' single arguments
+
+From: Fangrui Song <maskray@google.com>
+
+[ Upstream commit 3363c460ef726ba693704dbcd73b7e7214ccc788 ]
+
+The macros FOUR_ROUNDS_AND_SCHED and DO_4ROUNDS rely on an
+unexpected/undocumented behavior of the GNU assembler, which might
+change in the future
+(https://sourceware.org/bugzilla/show_bug.cgi?id=32073).
+
+ M (1) (2) // 1 arg !? Future: 2 args
+ M 1 + 2 // 1 arg !? Future: 3 args
+
+ M 1 2 // 2 args
+
+Add parentheses around the single arguments to support future GNU
+assembler and LLVM integrated assembler (when the IsOperator hack from
+the following link is dropped).
+
+Link: https://github.com/llvm/llvm-project/commit/055006475e22014b28a070db1bff41ca15f322f0
+Signed-off-by: Fangrui Song <maskray@google.com>
+Reviewed-by: Jan Beulich <jbeulich@suse.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/crypto/sha256-avx2-asm.S | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+diff --git a/arch/x86/crypto/sha256-avx2-asm.S b/arch/x86/crypto/sha256-avx2-asm.S
+index 0ffb072be9561..0bbec1c75cd0b 100644
+--- a/arch/x86/crypto/sha256-avx2-asm.S
++++ b/arch/x86/crypto/sha256-avx2-asm.S
+@@ -592,22 +592,22 @@ SYM_TYPED_FUNC_START(sha256_transform_rorx)
+ leaq K256+0*32(%rip), INP ## reuse INP as scratch reg
+ vpaddd (INP, SRND), X0, XFER
+ vmovdqa XFER, 0*32+_XFER(%rsp, SRND)
+- FOUR_ROUNDS_AND_SCHED _XFER + 0*32
++ FOUR_ROUNDS_AND_SCHED (_XFER + 0*32)
+
+ leaq K256+1*32(%rip), INP
+ vpaddd (INP, SRND), X0, XFER
+ vmovdqa XFER, 1*32+_XFER(%rsp, SRND)
+- FOUR_ROUNDS_AND_SCHED _XFER + 1*32
++ FOUR_ROUNDS_AND_SCHED (_XFER + 1*32)
+
+ leaq K256+2*32(%rip), INP
+ vpaddd (INP, SRND), X0, XFER
+ vmovdqa XFER, 2*32+_XFER(%rsp, SRND)
+- FOUR_ROUNDS_AND_SCHED _XFER + 2*32
++ FOUR_ROUNDS_AND_SCHED (_XFER + 2*32)
+
+ leaq K256+3*32(%rip), INP
+ vpaddd (INP, SRND), X0, XFER
+ vmovdqa XFER, 3*32+_XFER(%rsp, SRND)
+- FOUR_ROUNDS_AND_SCHED _XFER + 3*32
++ FOUR_ROUNDS_AND_SCHED (_XFER + 3*32)
+
+ add $4*32, SRND
+ cmp $3*4*32, SRND
+@@ -618,12 +618,12 @@ SYM_TYPED_FUNC_START(sha256_transform_rorx)
+ leaq K256+0*32(%rip), INP
+ vpaddd (INP, SRND), X0, XFER
+ vmovdqa XFER, 0*32+_XFER(%rsp, SRND)
+- DO_4ROUNDS _XFER + 0*32
++ DO_4ROUNDS (_XFER + 0*32)
+
+ leaq K256+1*32(%rip), INP
+ vpaddd (INP, SRND), X1, XFER
+ vmovdqa XFER, 1*32+_XFER(%rsp, SRND)
+- DO_4ROUNDS _XFER + 1*32
++ DO_4ROUNDS (_XFER + 1*32)
+ add $2*32, SRND
+
+ vmovdqa X2, X0
+@@ -651,8 +651,8 @@ SYM_TYPED_FUNC_START(sha256_transform_rorx)
+ xor SRND, SRND
+ .align 16
+ .Lloop3:
+- DO_4ROUNDS _XFER + 0*32 + 16
+- DO_4ROUNDS _XFER + 1*32 + 16
++ DO_4ROUNDS (_XFER + 0*32 + 16)
++ DO_4ROUNDS (_XFER + 1*32 + 16)
+ add $2*32, SRND
+ cmp $4*4*32, SRND
+ jb .Lloop3
+--
+2.43.0
+
--- /dev/null
+From d1d69a973092a4e75c8b3caaf25d9ebb8e6babc6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 27 Aug 2024 15:51:12 +0100
+Subject: drivers/perf: arm_spe: Use perf_allow_kernel() for permissions
+
+From: James Clark <james.clark@linaro.org>
+
+[ Upstream commit 5e9629d0ae977d6f6916d7e519724804e95f0b07 ]
+
+Use perf_allow_kernel() for 'pa_enable' (physical addresses),
+'pct_enable' (physical timestamps) and context IDs. This means that
+perf_event_paranoid is now taken into account and LSM hooks can be used,
+which is more consistent with other perf_event_open calls. For example
+PERF_SAMPLE_PHYS_ADDR uses perf_allow_kernel() rather than just
+perfmon_capable().
+
+This also indirectly fixes the following error message which is
+misleading because perf_event_paranoid is not taken into account by
+perfmon_capable():
+
+ $ perf record -e arm_spe/pa_enable/
+
+ Error:
+ Access to performance monitoring and observability operations is
+ limited. Consider adjusting /proc/sys/kernel/perf_event_paranoid
+ setting ...
+
+Suggested-by: Al Grant <al.grant@arm.com>
+Signed-off-by: James Clark <james.clark@linaro.org>
+Link: https://lore.kernel.org/r/20240827145113.1224604-1-james.clark@linaro.org
+Link: https://lore.kernel.org/all/20240807120039.GD37996@noisy.programming.kicks-ass.net/
+Signed-off-by: Will Deacon <will@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/perf/arm_spe_pmu.c | 9 ++++-----
+ include/linux/perf_event.h | 8 +-------
+ kernel/events/core.c | 9 +++++++++
+ 3 files changed, 14 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/perf/arm_spe_pmu.c b/drivers/perf/arm_spe_pmu.c
+index 9100d82bfabc0..3569050f9cf37 100644
+--- a/drivers/perf/arm_spe_pmu.c
++++ b/drivers/perf/arm_spe_pmu.c
+@@ -41,7 +41,7 @@
+
+ /*
+ * Cache if the event is allowed to trace Context information.
+- * This allows us to perform the check, i.e, perfmon_capable(),
++ * This allows us to perform the check, i.e, perf_allow_kernel(),
+ * in the context of the event owner, once, during the event_init().
+ */
+ #define SPE_PMU_HW_FLAGS_CX 0x00001
+@@ -50,7 +50,7 @@ static_assert((PERF_EVENT_FLAG_ARCH & SPE_PMU_HW_FLAGS_CX) == SPE_PMU_HW_FLAGS_C
+
+ static void set_spe_event_has_cx(struct perf_event *event)
+ {
+- if (IS_ENABLED(CONFIG_PID_IN_CONTEXTIDR) && perfmon_capable())
++ if (IS_ENABLED(CONFIG_PID_IN_CONTEXTIDR) && !perf_allow_kernel(&event->attr))
+ event->hw.flags |= SPE_PMU_HW_FLAGS_CX;
+ }
+
+@@ -745,9 +745,8 @@ static int arm_spe_pmu_event_init(struct perf_event *event)
+
+ set_spe_event_has_cx(event);
+ reg = arm_spe_event_to_pmscr(event);
+- if (!perfmon_capable() &&
+- (reg & (PMSCR_EL1_PA | PMSCR_EL1_PCT)))
+- return -EACCES;
++ if (reg & (PMSCR_EL1_PA | PMSCR_EL1_PCT))
++ return perf_allow_kernel(&event->attr);
+
+ return 0;
+ }
+diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
+index 393fb13733b02..a7f1a3a4d1dce 100644
+--- a/include/linux/perf_event.h
++++ b/include/linux/perf_event.h
+@@ -1608,13 +1608,7 @@ static inline int perf_is_paranoid(void)
+ return sysctl_perf_event_paranoid > -1;
+ }
+
+-static inline int perf_allow_kernel(struct perf_event_attr *attr)
+-{
+- if (sysctl_perf_event_paranoid > 1 && !perfmon_capable())
+- return -EACCES;
+-
+- return security_perf_event_open(attr, PERF_SECURITY_KERNEL);
+-}
++int perf_allow_kernel(struct perf_event_attr *attr);
+
+ static inline int perf_allow_cpu(struct perf_event_attr *attr)
+ {
+diff --git a/kernel/events/core.c b/kernel/events/core.c
+index 36191add55c37..081d9692ce747 100644
+--- a/kernel/events/core.c
++++ b/kernel/events/core.c
+@@ -13362,6 +13362,15 @@ const struct perf_event_attr *perf_event_attrs(struct perf_event *event)
+ return &event->attr;
+ }
+
++int perf_allow_kernel(struct perf_event_attr *attr)
++{
++ if (sysctl_perf_event_paranoid > 1 && !perfmon_capable())
++ return -EACCES;
++
++ return security_perf_event_open(attr, PERF_SECURITY_KERNEL);
++}
++EXPORT_SYMBOL_GPL(perf_allow_kernel);
++
+ /*
+ * Inherit an event from parent task to child task.
+ *
+--
+2.43.0
+
--- /dev/null
+From 3b3000be1d25b696bdd18e588ec59a5967cf78fa Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 2 Aug 2024 12:35:13 +0530
+Subject: drm/amd/display: Add null check for 'afb' in
+ amdgpu_dm_plane_handle_cursor_update (v2)
+
+From: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+
+[ Upstream commit cd9e9e0852d501f169aa3bb34e4b413d2eb48c37 ]
+
+This commit adds a null check for the 'afb' variable in the
+amdgpu_dm_plane_handle_cursor_update function. Previously, 'afb' was
+assumed to be null, but was used later in the code without a null check.
+This could potentially lead to a null pointer dereference.
+
+Changes since v1:
+- Moved the null check for 'afb' to the line where 'afb' is used. (Alex)
+
+Fixes the below:
+drivers/gpu/drm/amd/amdgpu/../display/amdgpu_dm/amdgpu_dm_plane.c:1298 amdgpu_dm_plane_handle_cursor_update() error: we previously assumed 'afb' could be null (see line 1252)
+
+Cc: Tom Chung <chiahsuan.chung@amd.com>
+Cc: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
+Cc: Roman Li <roman.li@amd.com>
+Cc: Alex Hung <alex.hung@amd.com>
+Cc: Aurabindo Pillai <aurabindo.pillai@amd.com>
+Cc: Harry Wentland <harry.wentland@amd.com>
+Co-developed-by: Alex Hung <alex.hung@amd.com>
+Signed-off-by: Alex Hung <alex.hung@amd.com>
+Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+Reviewed-by: Tom Chung <chiahsuan.chung@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
+index 7d47acdd11d55..fe7a99aee47dd 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
+@@ -1285,7 +1285,8 @@ void amdgpu_dm_plane_handle_cursor_update(struct drm_plane *plane,
+ adev->dm.dc->caps.color.dpp.gamma_corr)
+ attributes.attribute_flags.bits.ENABLE_CURSOR_DEGAMMA = 1;
+
+- attributes.pitch = afb->base.pitches[0] / afb->base.format->cpp[0];
++ if (afb)
++ attributes.pitch = afb->base.pitches[0] / afb->base.format->cpp[0];
+
+ if (crtc_state->stream) {
+ mutex_lock(&adev->dm.dc_lock);
+--
+2.43.0
+
--- /dev/null
+From d832dd4067b47f8b1a95dd4eb5c0e964d13f3e57 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 22 Jul 2024 16:21:19 +0530
+Subject: drm/amd/display: Add NULL check for clk_mgr and clk_mgr->funcs in
+ dcn30_init_hw
+
+From: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+
+[ Upstream commit cba7fec864172dadd953daefdd26e01742b71a6a ]
+
+This commit addresses a potential null pointer dereference issue in the
+`dcn30_init_hw` function. The issue could occur when `dc->clk_mgr` or
+`dc->clk_mgr->funcs` is null.
+
+The fix adds a check to ensure `dc->clk_mgr` and `dc->clk_mgr->funcs` is
+not null before accessing its functions. This prevents a potential null
+pointer dereference.
+
+Reported by smatch:
+drivers/gpu/drm/amd/amdgpu/../display/dc/hwss/dcn30/dcn30_hwseq.c:789 dcn30_init_hw() error: we previously assumed 'dc->clk_mgr' could be null (see line 628)
+
+Cc: Tom Chung <chiahsuan.chung@amd.com>
+Cc: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
+Cc: Roman Li <roman.li@amd.com>
+Cc: Alex Hung <alex.hung@amd.com>
+Cc: Aurabindo Pillai <aurabindo.pillai@amd.com>
+Cc: Harry Wentland <harry.wentland@amd.com>
+Cc: Hamza Mahfooz <hamza.mahfooz@amd.com>
+Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+Reviewed-by: Alex Hung <alex.hung@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
+index 05c5d4f04e1bd..0f72a54e92af6 100644
+--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
+@@ -626,7 +626,7 @@ void dcn30_init_hw(struct dc *dc)
+ uint32_t backlight = MAX_BACKLIGHT_LEVEL;
+ uint32_t user_level = MAX_BACKLIGHT_LEVEL;
+
+- if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks)
++ if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->init_clocks)
+ dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);
+
+ // Initialize the dccg
+@@ -787,11 +787,12 @@ void dcn30_init_hw(struct dc *dc)
+ if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks)
+ dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub);
+
+- if (dc->clk_mgr->funcs->notify_wm_ranges)
++ if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->notify_wm_ranges)
+ dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr);
+
+ //if softmax is enabled then hardmax will be set by a different call
+- if (dc->clk_mgr->funcs->set_hard_max_memclk && !dc->clk_mgr->dc_mode_softmax_enabled)
++ if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->set_hard_max_memclk &&
++ !dc->clk_mgr->dc_mode_softmax_enabled)
+ dc->clk_mgr->funcs->set_hard_max_memclk(dc->clk_mgr);
+
+ if (dc->res_pool->hubbub->funcs->force_pstate_change_control)
+--
+2.43.0
+
--- /dev/null
+From 62a74751c15fea9c06713204890b9e8fde70f1d5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 22 Jul 2024 16:44:40 +0530
+Subject: drm/amd/display: Add NULL check for clk_mgr in dcn32_init_hw
+
+From: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+
+[ Upstream commit c395fd47d1565bd67671f45cca281b3acc2c31ef ]
+
+This commit addresses a potential null pointer dereference issue in the
+`dcn32_init_hw` function. The issue could occur when `dc->clk_mgr` is
+null.
+
+The fix adds a check to ensure `dc->clk_mgr` is not null before
+accessing its functions. This prevents a potential null pointer
+dereference.
+
+Reported by smatch:
+drivers/gpu/drm/amd/amdgpu/../display/dc/hwss/dcn32/dcn32_hwseq.c:961 dcn32_init_hw() error: we previously assumed 'dc->clk_mgr' could be null (see line 782)
+
+Cc: Tom Chung <chiahsuan.chung@amd.com>
+Cc: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
+Cc: Roman Li <roman.li@amd.com>
+Cc: Alex Hung <alex.hung@amd.com>
+Cc: Aurabindo Pillai <aurabindo.pillai@amd.com>
+Cc: Harry Wentland <harry.wentland@amd.com>
+Cc: Hamza Mahfooz <hamza.mahfooz@amd.com>
+Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+Reviewed-by: Alex Hung <alex.hung@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
+index 5fc377f51f562..aaf576f30a777 100644
+--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
+@@ -752,7 +752,7 @@ void dcn32_init_hw(struct dc *dc)
+ uint32_t backlight = MAX_BACKLIGHT_LEVEL;
+ uint32_t user_level = MAX_BACKLIGHT_LEVEL;
+
+- if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks)
++ if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->init_clocks)
+ dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);
+
+ // Initialize the dccg
+@@ -931,10 +931,11 @@ void dcn32_init_hw(struct dc *dc)
+ if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks)
+ dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub);
+
+- if (dc->clk_mgr->funcs->notify_wm_ranges)
++ if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->notify_wm_ranges)
+ dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr);
+
+- if (dc->clk_mgr->funcs->set_hard_max_memclk && !dc->clk_mgr->dc_mode_softmax_enabled)
++ if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->set_hard_max_memclk &&
++ !dc->clk_mgr->dc_mode_softmax_enabled)
+ dc->clk_mgr->funcs->set_hard_max_memclk(dc->clk_mgr);
+
+ if (dc->res_pool->hubbub->funcs->force_pstate_change_control)
+--
+2.43.0
+
--- /dev/null
+From cb38ad368fde8941cd8c9be6f1062bf6c97ba182 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 31 Jul 2024 13:09:28 +0530
+Subject: drm/amd/display: Add NULL check for function pointer in
+ dcn20_set_output_transfer_func
+
+From: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+
+[ Upstream commit 62ed6f0f198da04e884062264df308277628004f ]
+
+This commit adds a null check for the set_output_gamma function pointer
+in the dcn20_set_output_transfer_func function. Previously,
+set_output_gamma was being checked for null at line 1030, but then it
+was being dereferenced without any null check at line 1048. This could
+potentially lead to a null pointer dereference error if set_output_gamma
+is null.
+
+To fix this, we now ensure that set_output_gamma is not null before
+dereferencing it. We do this by adding a null check for set_output_gamma
+before the call to set_output_gamma at line 1048.
+
+Cc: Tom Chung <chiahsuan.chung@amd.com>
+Cc: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
+Cc: Roman Li <roman.li@amd.com>
+Cc: Alex Hung <alex.hung@amd.com>
+Cc: Aurabindo Pillai <aurabindo.pillai@amd.com>
+Cc: Harry Wentland <harry.wentland@amd.com>
+Cc: Hamza Mahfooz <hamza.mahfooz@amd.com>
+Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+Reviewed-by: Tom Chung <chiahsuan.chung@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
+index 7d833fa6dd77c..58e8b7482f4f5 100644
+--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
+@@ -1040,7 +1040,8 @@ bool dcn20_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx,
+ /*
+ * if above if is not executed then 'params' equal to 0 and set in bypass
+ */
+- mpc->funcs->set_output_gamma(mpc, mpcc_id, params);
++ if (mpc->funcs->set_output_gamma)
++ mpc->funcs->set_output_gamma(mpc, mpcc_id, params);
+
+ return true;
+ }
+--
+2.43.0
+
--- /dev/null
+From fca9b6da616d9b8b455d5aa1cd82d144df43e3bb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 31 Jul 2024 13:15:00 +0530
+Subject: drm/amd/display: Add NULL check for function pointer in
+ dcn32_set_output_transfer_func
+
+From: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+
+[ Upstream commit 28574b08c70e56d34d6f6379326a860b96749051 ]
+
+This commit adds a null check for the set_output_gamma function pointer
+in the dcn32_set_output_transfer_func function. Previously,
+set_output_gamma was being checked for null, but then it was being
+dereferenced without any null check. This could lead to a null pointer
+dereference if set_output_gamma is null.
+
+To fix this, we now ensure that set_output_gamma is not null before
+dereferencing it. We do this by adding a null check for set_output_gamma
+before the call to set_output_gamma.
+
+Cc: Tom Chung <chiahsuan.chung@amd.com>
+Cc: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
+Cc: Roman Li <roman.li@amd.com>
+Cc: Alex Hung <alex.hung@amd.com>
+Cc: Aurabindo Pillai <aurabindo.pillai@amd.com>
+Cc: Harry Wentland <harry.wentland@amd.com>
+Cc: Hamza Mahfooz <hamza.mahfooz@amd.com>
+Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+Reviewed-by: Tom Chung <chiahsuan.chung@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
+index aaf576f30a777..c050acc4ff065 100644
+--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
+@@ -581,7 +581,9 @@ bool dcn32_set_output_transfer_func(struct dc *dc,
+ }
+ }
+
+- mpc->funcs->set_output_gamma(mpc, mpcc_id, params);
++ if (mpc->funcs->set_output_gamma)
++ mpc->funcs->set_output_gamma(mpc, mpcc_id, params);
++
+ return ret;
+ }
+
+--
+2.43.0
+
--- /dev/null
+From 242bd6becd5cfaf0ffc77fc8b27c2e8db2c507e3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 21 Jul 2024 19:18:58 +0530
+Subject: drm/amd/display: Add null check for head_pipe in
+ dcn201_acquire_free_pipe_for_layer
+
+From: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+
+[ Upstream commit f22f4754aaa47d8c59f166ba3042182859e5dff7 ]
+
+This commit addresses a potential null pointer dereference issue in the
+`dcn201_acquire_free_pipe_for_layer` function. The issue could occur
+when `head_pipe` is null.
+
+The fix adds a check to ensure `head_pipe` is not null before asserting
+it. If `head_pipe` is null, the function returns NULL to prevent a
+potential null pointer dereference.
+
+Reported by smatch:
+drivers/gpu/drm/amd/amdgpu/../display/dc/resource/dcn201/dcn201_resource.c:1016 dcn201_acquire_free_pipe_for_layer() error: we previously assumed 'head_pipe' could be null (see line 1010)
+
+Cc: Tom Chung <chiahsuan.chung@amd.com>
+Cc: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
+Cc: Roman Li <roman.li@amd.com>
+Cc: Alex Hung <alex.hung@amd.com>
+Cc: Aurabindo Pillai <aurabindo.pillai@amd.com>
+Cc: Harry Wentland <harry.wentland@amd.com>
+Cc: Hamza Mahfooz <hamza.mahfooz@amd.com>
+Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+Reviewed-by: Tom Chung <chiahsuan.chung@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c
+index 070a4efb308bd..1aeede348bd39 100644
+--- a/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c
+@@ -1005,8 +1005,10 @@ static struct pipe_ctx *dcn201_acquire_free_pipe_for_layer(
+ struct pipe_ctx *head_pipe = resource_get_otg_master_for_stream(res_ctx, opp_head_pipe->stream);
+ struct pipe_ctx *idle_pipe = resource_find_free_secondary_pipe_legacy(res_ctx, pool, head_pipe);
+
+- if (!head_pipe)
++ if (!head_pipe) {
+ ASSERT(0);
++ return NULL;
++ }
+
+ if (!idle_pipe)
+ return NULL;
+--
+2.43.0
+
--- /dev/null
+From 44d9709ea1656c2885dfaa4f08a73876aa1f1604 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 21 Jul 2024 19:30:16 +0530
+Subject: drm/amd/display: Add null check for head_pipe in
+ dcn32_acquire_idle_pipe_for_head_pipe_in_layer
+
+From: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+
+[ Upstream commit ac2140449184a26eac99585b7f69814bd3ba8f2d ]
+
+This commit addresses a potential null pointer dereference issue in the
+`dcn32_acquire_idle_pipe_for_head_pipe_in_layer` function. The issue
+could occur when `head_pipe` is null.
+
+The fix adds a check to ensure `head_pipe` is not null before asserting
+it. If `head_pipe` is null, the function returns NULL to prevent a
+potential null pointer dereference.
+
+Reported by smatch:
+drivers/gpu/drm/amd/amdgpu/../display/dc/resource/dcn32/dcn32_resource.c:2690 dcn32_acquire_idle_pipe_for_head_pipe_in_layer() error: we previously assumed 'head_pipe' could be null (see line 2681)
+
+Cc: Tom Chung <chiahsuan.chung@amd.com>
+Cc: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
+Cc: Roman Li <roman.li@amd.com>
+Cc: Alex Hung <alex.hung@amd.com>
+Cc: Aurabindo Pillai <aurabindo.pillai@amd.com>
+Cc: Harry Wentland <harry.wentland@amd.com>
+Cc: Hamza Mahfooz <hamza.mahfooz@amd.com>
+Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+Reviewed-by: Tom Chung <chiahsuan.chung@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
+index d84c8e0e5c2f0..9209bcad699a8 100644
+--- a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
+@@ -2664,8 +2664,10 @@ static struct pipe_ctx *dcn32_acquire_idle_pipe_for_head_pipe_in_layer(
+ struct resource_context *old_ctx = &stream->ctx->dc->current_state->res_ctx;
+ int head_index;
+
+- if (!head_pipe)
++ if (!head_pipe) {
+ ASSERT(0);
++ return NULL;
++ }
+
+ /*
+ * Modified from dcn20_acquire_idle_pipe_for_layer
+--
+2.43.0
+
--- /dev/null
+From 89d6ae7d67b12b481ea6f83a0c0dafb5c78f497d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 25 Jul 2024 07:23:48 +0530
+Subject: drm/amd/display: Add null check for top_pipe_to_program in
+ commit_planes_for_stream
+
+From: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+
+[ Upstream commit 66d71a72539e173a9b00ca0b1852cbaa5f5bf1ad ]
+
+This commit addresses a null pointer dereference issue in the
+`commit_planes_for_stream` function at line 4140. The issue could occur
+when `top_pipe_to_program` is null.
+
+The fix adds a check to ensure `top_pipe_to_program` is not null before
+accessing its stream_res. This prevents a null pointer dereference.
+
+Reported by smatch:
+drivers/gpu/drm/amd/amdgpu/../display/dc/core/dc.c:4140 commit_planes_for_stream() error: we previously assumed 'top_pipe_to_program' could be null (see line 3906)
+
+Cc: Tom Chung <chiahsuan.chung@amd.com>
+Cc: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
+Cc: Roman Li <roman.li@amd.com>
+Cc: Alex Hung <alex.hung@amd.com>
+Cc: Aurabindo Pillai <aurabindo.pillai@amd.com>
+Cc: Harry Wentland <harry.wentland@amd.com>
+Cc: Hamza Mahfooz <hamza.mahfooz@amd.com>
+Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+Reviewed-by: Tom Chung <chiahsuan.chung@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/core/dc.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
+index da237f718dbdd..3bd18e862945f 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
+@@ -3970,7 +3970,8 @@ static void commit_planes_for_stream(struct dc *dc,
+ }
+
+ if ((update_type != UPDATE_TYPE_FAST) && stream->update_flags.bits.dsc_changed)
+- if (top_pipe_to_program->stream_res.tg->funcs->lock_doublebuffer_enable) {
++ if (top_pipe_to_program &&
++ top_pipe_to_program->stream_res.tg->funcs->lock_doublebuffer_enable) {
+ top_pipe_to_program->stream_res.tg->funcs->wait_for_state(
+ top_pipe_to_program->stream_res.tg,
+ CRTC_STATE_VACTIVE);
+--
+2.43.0
+
--- /dev/null
+From 02f404fb3acce378df2c7923ee2e5976a7c854f0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 17 Jul 2024 09:17:56 -0600
+Subject: drm/amd/display: Avoid overflow assignment in link_dp_cts
+
+From: Alex Hung <alex.hung@amd.com>
+
+[ Upstream commit a15268787b79fd183dd526cc16bec9af4f4e49a1 ]
+
+sampling_rate is an uint8_t but is assigned an unsigned int, and thus it
+can overflow. As a result, sampling_rate is changed to uint32_t.
+
+Similarly, LINK_QUAL_PATTERN_SET has a size of 2 bits, and it should
+only be assigned to a value less or equal than 4.
+
+This fixes 2 INTEGER_OVERFLOW issues reported by Coverity.
+
+Signed-off-by: Alex Hung <alex.hung@amd.com>
+Reviewed-by: Wenjing Liu <wenjing.liu@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Rodrigo Siqueira <rodrigo.siqueira@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/dc_dp_types.h | 2 +-
+ drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c | 3 ++-
+ drivers/gpu/drm/amd/display/include/dpcd_defs.h | 1 +
+ 3 files changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
+index 519c3df78ee5b..95c275bf649bd 100644
+--- a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
++++ b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
+@@ -727,7 +727,7 @@ struct dp_audio_test_data_flags {
+ struct dp_audio_test_data {
+
+ struct dp_audio_test_data_flags flags;
+- uint8_t sampling_rate;
++ uint32_t sampling_rate;
+ uint8_t channel_count;
+ uint8_t pattern_type;
+ uint8_t pattern_period[8];
+diff --git a/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c
+index 8d1a1cc94a8b3..6b27ac56f60d8 100644
+--- a/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c
++++ b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c
+@@ -775,7 +775,8 @@ bool dp_set_test_pattern(
+ core_link_read_dpcd(link, DP_TRAINING_PATTERN_SET,
+ &training_pattern.raw,
+ sizeof(training_pattern));
+- training_pattern.v1_3.LINK_QUAL_PATTERN_SET = pattern;
++ if (pattern <= PHY_TEST_PATTERN_END_DP11)
++ training_pattern.v1_3.LINK_QUAL_PATTERN_SET = pattern;
+ core_link_write_dpcd(link, DP_TRAINING_PATTERN_SET,
+ &training_pattern.raw,
+ sizeof(training_pattern));
+diff --git a/drivers/gpu/drm/amd/display/include/dpcd_defs.h b/drivers/gpu/drm/amd/display/include/dpcd_defs.h
+index aee5170f5fb23..c246235e4afec 100644
+--- a/drivers/gpu/drm/amd/display/include/dpcd_defs.h
++++ b/drivers/gpu/drm/amd/display/include/dpcd_defs.h
+@@ -76,6 +76,7 @@ enum dpcd_phy_test_patterns {
+ PHY_TEST_PATTERN_D10_2,
+ PHY_TEST_PATTERN_SYMBOL_ERROR,
+ PHY_TEST_PATTERN_PRBS7,
++ PHY_TEST_PATTERN_END_DP11 = PHY_TEST_PATTERN_PRBS7,
+ PHY_TEST_PATTERN_80BIT_CUSTOM,/* For DP1.2 only */
+ PHY_TEST_PATTERN_CP2520_1,
+ PHY_TEST_PATTERN_CP2520_2,
+--
+2.43.0
+
--- /dev/null
+From 6d43441908a3563e2d5a542156fbdad58e157e7d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Jun 2024 16:45:39 -0600
+Subject: drm/amd/display: Check link_res->hpo_dp_link_enc before using it
+
+From: Alex Hung <alex.hung@amd.com>
+
+[ Upstream commit 0beca868cde8742240cd0038141c30482d2b7eb8 ]
+
+[WHAT & HOW]
+Functions dp_enable_link_phy and dp_disable_link_phy can pass link_res
+without initializing hpo_dp_link_enc and it is necessary to check for
+null before dereferencing.
+
+This fixes 2 FORWARD_NULL issues reported by Coverity.
+
+Reviewed-by: Rodrigo Siqueira <rodrigo.siqueira@amd.com>
+Signed-off-by: Jerry Zuo <jerry.zuo@amd.com>
+Signed-off-by: Alex Hung <alex.hung@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.c b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.c
+index e1257404357b1..d0148f10dfc0a 100644
+--- a/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.c
++++ b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.c
+@@ -28,6 +28,8 @@
+ #include "dccg.h"
+ #include "clk_mgr.h"
+
++#define DC_LOGGER link->ctx->logger
++
+ void set_hpo_dp_throttled_vcp_size(struct pipe_ctx *pipe_ctx,
+ struct fixed31_32 throttled_vcp_size)
+ {
+@@ -124,6 +126,11 @@ void disable_hpo_dp_link_output(struct dc_link *link,
+ const struct link_resource *link_res,
+ enum signal_type signal)
+ {
++ if (!link_res->hpo_dp_link_enc) {
++ DC_LOG_ERROR("%s: invalid hpo_dp_link_enc\n", __func__);
++ return;
++ }
++
+ link_res->hpo_dp_link_enc->funcs->link_disable(link_res->hpo_dp_link_enc);
+ link_res->hpo_dp_link_enc->funcs->disable_link_phy(
+ link_res->hpo_dp_link_enc, signal);
+--
+2.43.0
+
--- /dev/null
+From dee3df10e147a8152d95b51c254228f0bb10367e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Jun 2024 17:34:18 -0600
+Subject: drm/amd/display: Check null-initialized variables
+
+From: Alex Hung <alex.hung@amd.com>
+
+[ Upstream commit 367cd9ceba1933b63bc1d87d967baf6d9fd241d2 ]
+
+[WHAT & HOW]
+drr_timing and subvp_pipe are initialized to null and they are not
+always assigned new values. It is necessary to check for null before
+dereferencing.
+
+This fixes 2 FORWARD_NULL issues reported by Coverity.
+
+Reviewed-by: Nevenko Stupar <nevenko.stupar@amd.com>
+Reviewed-by: Rodrigo Siqueira <rodrigo.siqueira@amd.com>
+Signed-off-by: Jerry Zuo <jerry.zuo@amd.com>
+Signed-off-by: Alex Hung <alex.hung@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
+index ebcf5ece209a4..bf8c89fe95a7e 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
+@@ -871,8 +871,9 @@ static bool subvp_drr_schedulable(struct dc *dc, struct dc_state *context)
+ * for VBLANK: (VACTIVE region of the SubVP pipe can fit the MALL prefetch, VBLANK frame time,
+ * and the max of (VBLANK blanking time, MALL region)).
+ */
+- if (stretched_drr_us < (1 / (double)drr_timing->min_refresh_in_uhz) * 1000000 * 1000000 &&
+- subvp_active_us - prefetch_us - stretched_drr_us - max_vblank_mallregion > 0)
++ if (drr_timing &&
++ stretched_drr_us < (1 / (double)drr_timing->min_refresh_in_uhz) * 1000000 * 1000000 &&
++ subvp_active_us - prefetch_us - stretched_drr_us - max_vblank_mallregion > 0)
+ schedulable = true;
+
+ return schedulable;
+@@ -937,7 +938,7 @@ static bool subvp_vblank_schedulable(struct dc *dc, struct dc_state *context)
+ if (!subvp_pipe && pipe_mall_type == SUBVP_MAIN)
+ subvp_pipe = pipe;
+ }
+- if (found) {
++ if (found && subvp_pipe) {
+ phantom_stream = dc_state_get_paired_subvp_stream(context, subvp_pipe->stream);
+ main_timing = &subvp_pipe->stream->timing;
+ phantom_timing = &phantom_stream->timing;
+--
+2.43.0
+
--- /dev/null
+From d08eb057942b3b212e05761baf51166bf77cd21f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 29 Jul 2024 15:29:09 -0600
+Subject: drm/amd/display: Check null pointers before using dc->clk_mgr
+
+From: Alex Hung <alex.hung@amd.com>
+
+[ Upstream commit 95d9e0803e51d5a24276b7643b244c7477daf463 ]
+
+[WHY & HOW]
+dc->clk_mgr is null checked previously in the same function, indicating
+it might be null.
+
+Passing "dc" to "dc->hwss.apply_idle_power_optimizations", which
+dereferences null "dc->clk_mgr". (The function pointer resolves to
+"dcn35_apply_idle_power_optimizations".)
+
+This fixes 1 FORWARD_NULL issue reported by Coverity.
+
+Reviewed-by: Rodrigo Siqueira <rodrigo.siqueira@amd.com>
+Signed-off-by: Alex Hung <alex.hung@amd.com>
+Signed-off-by: Tom Chung <chiahsuan.chung@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/core/dc.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
+index 3bd18e862945f..daeb80abf435f 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
+@@ -5211,7 +5211,8 @@ void dc_allow_idle_optimizations_internal(struct dc *dc, bool allow, char const
+ if (allow == dc->idle_optimizations_allowed)
+ return;
+
+- if (dc->hwss.apply_idle_power_optimizations && dc->hwss.apply_idle_power_optimizations(dc, allow))
++ if (dc->hwss.apply_idle_power_optimizations && dc->clk_mgr != NULL &&
++ dc->hwss.apply_idle_power_optimizations(dc, allow))
+ dc->idle_optimizations_allowed = allow;
+ }
+
+--
+2.43.0
+
--- /dev/null
+From 7494a8c5a6b12d99e5176bc470b87b178f2bd9fa Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Jun 2024 17:38:16 -0600
+Subject: drm/amd/display: Check null pointers before using them
+
+From: Alex Hung <alex.hung@amd.com>
+
+[ Upstream commit 1ff12bcd7deaeed25efb5120433c6a45dd5504a8 ]
+
+[WHAT & HOW]
+These pointers are null checked previously in the same function,
+indicating they might be null as reported by Coverity. As a result,
+they need to be checked when used again.
+
+This fixes 3 FORWARD_NULL issue reported by Coverity.
+
+Reviewed-by: Rodrigo Siqueira <rodrigo.siqueira@amd.com>
+Signed-off-by: Jerry Zuo <jerry.zuo@amd.com>
+Signed-off-by: Alex Hung <alex.hung@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+index 3541d154cc8d0..9a578b1df141f 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+@@ -6951,6 +6951,9 @@ create_validate_stream_for_sink(struct amdgpu_dm_connector *aconnector,
+ int requested_bpc = drm_state ? drm_state->max_requested_bpc : 8;
+ enum dc_status dc_result = DC_OK;
+
++ if (!dm_state)
++ return NULL;
++
+ do {
+ stream = create_stream_for_sink(connector, drm_mode,
+ dm_state, old_stream,
+@@ -8963,7 +8966,7 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_state *state,
+ if (acrtc)
+ old_crtc_state = drm_atomic_get_old_crtc_state(state, &acrtc->base);
+
+- if (!acrtc->wb_enabled)
++ if (!acrtc || !acrtc->wb_enabled)
+ continue;
+
+ dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
+@@ -9362,9 +9365,10 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
+
+ DRM_INFO("[HDCP_DM] hdcp_update_display enable_encryption = %x\n", enable_encryption);
+
+- hdcp_update_display(
+- adev->dm.hdcp_workqueue, aconnector->dc_link->link_index, aconnector,
+- new_con_state->hdcp_content_type, enable_encryption);
++ if (aconnector->dc_link)
++ hdcp_update_display(
++ adev->dm.hdcp_workqueue, aconnector->dc_link->link_index, aconnector,
++ new_con_state->hdcp_content_type, enable_encryption);
+ }
+ }
+
+--
+2.43.0
+
--- /dev/null
+From 6f9e87a4cc4aaa15e752a72084b86a6193dd4564 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 20 Jun 2024 20:23:41 -0600
+Subject: drm/amd/display: Check phantom_stream before it is used
+
+From: Alex Hung <alex.hung@amd.com>
+
+[ Upstream commit 3718a619a8c0a53152e76bb6769b6c414e1e83f4 ]
+
+dcn32_enable_phantom_stream can return null, so returned value
+must be checked before used.
+
+This fixes 1 NULL_RETURNS issue reported by Coverity.
+
+Reviewed-by: Rodrigo Siqueira <rodrigo.siqueira@amd.com>
+Signed-off-by: Jerry Zuo <jerry.zuo@amd.com>
+Signed-off-by: Alex Hung <alex.hung@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
+index 9209bcad699a8..55fbe86383c04 100644
+--- a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
+@@ -1714,6 +1714,9 @@ void dcn32_add_phantom_pipes(struct dc *dc, struct dc_state *context,
+ // be a valid candidate for SubVP (i.e. has a plane, stream, doesn't
+ // already have phantom pipe assigned, etc.) by previous checks.
+ phantom_stream = dcn32_enable_phantom_stream(dc, context, pipes, pipe_cnt, index);
++ if (!phantom_stream)
++ return;
++
+ dcn32_enable_phantom_plane(dc, context, phantom_stream, index);
+
+ for (i = 0; i < dc->res_pool->pipe_count; i++) {
+--
+2.43.0
+
--- /dev/null
+From 3a9cb6560abc4458be1e1714180d74aef6d8227d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Jun 2024 20:05:14 -0600
+Subject: drm/amd/display: Check stream before comparing them
+
+From: Alex Hung <alex.hung@amd.com>
+
+[ Upstream commit 35ff747c86767937ee1e0ca987545b7eed7a0810 ]
+
+[WHAT & HOW]
+amdgpu_dm can pass a null stream to dc_is_stream_unchanged. It is
+necessary to check for null before dereferencing them.
+
+This fixes 1 FORWARD_NULL issue reported by Coverity.
+
+Reviewed-by: Rodrigo Siqueira <rodrigo.siqueira@amd.com>
+Signed-off-by: Jerry Zuo <jerry.zuo@amd.com>
+Signed-off-by: Alex Hung <alex.hung@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+index 7462c34793799..58f6155fecc5a 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+@@ -3134,6 +3134,8 @@ static bool are_stream_backends_same(
+ bool dc_is_stream_unchanged(
+ struct dc_stream_state *old_stream, struct dc_stream_state *stream)
+ {
++ if (!old_stream || !stream)
++ return false;
+
+ if (!are_stream_backends_same(old_stream, stream))
+ return false;
+--
+2.43.0
+
--- /dev/null
+From f586f182bb227a804c7b1da87eeabaae99407308 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 15 Aug 2024 18:45:22 -0400
+Subject: drm/amd/display: fix double free issue during amdgpu module unload
+
+From: Tim Huang <tim.huang@amd.com>
+
+[ Upstream commit 20b5a8f9f4670a8503aa9fa95ca632e77c6bf55d ]
+
+Flexible endpoints use DIGs from available inflexible endpoints,
+so only the encoders of inflexible links need to be freed.
+Otherwise, a double free issue may occur when unloading the
+amdgpu module.
+
+[ 279.190523] RIP: 0010:__slab_free+0x152/0x2f0
+[ 279.190577] Call Trace:
+[ 279.190580] <TASK>
+[ 279.190582] ? show_regs+0x69/0x80
+[ 279.190590] ? die+0x3b/0x90
+[ 279.190595] ? do_trap+0xc8/0xe0
+[ 279.190601] ? do_error_trap+0x73/0xa0
+[ 279.190605] ? __slab_free+0x152/0x2f0
+[ 279.190609] ? exc_invalid_op+0x56/0x70
+[ 279.190616] ? __slab_free+0x152/0x2f0
+[ 279.190642] ? asm_exc_invalid_op+0x1f/0x30
+[ 279.190648] ? dcn10_link_encoder_destroy+0x19/0x30 [amdgpu]
+[ 279.191096] ? __slab_free+0x152/0x2f0
+[ 279.191102] ? dcn10_link_encoder_destroy+0x19/0x30 [amdgpu]
+[ 279.191469] kfree+0x260/0x2b0
+[ 279.191474] dcn10_link_encoder_destroy+0x19/0x30 [amdgpu]
+[ 279.191821] link_destroy+0xd7/0x130 [amdgpu]
+[ 279.192248] dc_destruct+0x90/0x270 [amdgpu]
+[ 279.192666] dc_destroy+0x19/0x40 [amdgpu]
+[ 279.193020] amdgpu_dm_fini+0x16e/0x200 [amdgpu]
+[ 279.193432] dm_hw_fini+0x26/0x40 [amdgpu]
+[ 279.193795] amdgpu_device_fini_hw+0x24c/0x400 [amdgpu]
+[ 279.194108] amdgpu_driver_unload_kms+0x4f/0x70 [amdgpu]
+[ 279.194436] amdgpu_pci_remove+0x40/0x80 [amdgpu]
+[ 279.194632] pci_device_remove+0x3a/0xa0
+[ 279.194638] device_remove+0x40/0x70
+[ 279.194642] device_release_driver_internal+0x1ad/0x210
+[ 279.194647] driver_detach+0x4e/0xa0
+[ 279.194650] bus_remove_driver+0x6f/0xf0
+[ 279.194653] driver_unregister+0x33/0x60
+[ 279.194657] pci_unregister_driver+0x44/0x90
+[ 279.194662] amdgpu_exit+0x19/0x1f0 [amdgpu]
+[ 279.194939] __do_sys_delete_module.isra.0+0x198/0x2f0
+[ 279.194946] __x64_sys_delete_module+0x16/0x20
+[ 279.194950] do_syscall_64+0x58/0x120
+[ 279.194954] entry_SYSCALL_64_after_hwframe+0x6e/0x76
+[ 279.194980] </TASK>
+
+Reviewed-by: Rodrigo Siqueira <rodrigo.siqueira@amd.com>
+Signed-off-by: Tim Huang <tim.huang@amd.com>
+Reviewed-by: Roman Li <roman.li@amd.com>
+Signed-off-by: Roman Li <roman.li@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/link/link_factory.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/link/link_factory.c b/drivers/gpu/drm/amd/display/dc/link/link_factory.c
+index 72df9bdfb23ff..608491f860b29 100644
+--- a/drivers/gpu/drm/amd/display/dc/link/link_factory.c
++++ b/drivers/gpu/drm/amd/display/dc/link/link_factory.c
+@@ -385,7 +385,7 @@ static void link_destruct(struct dc_link *link)
+ if (link->panel_cntl)
+ link->panel_cntl->funcs->destroy(&link->panel_cntl);
+
+- if (link->link_enc) {
++ if (link->link_enc && !link->is_dig_mapping_flexible) {
+ /* Update link encoder resource tracking variables. These are used for
+ * the dynamic assignment of link encoders to streams. Virtual links
+ * are not assigned encoder resources on creation.
+--
+2.43.0
+
--- /dev/null
+From 8902693d3ceb14f9dcdf74c87347152bb229b481 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 20 Jul 2024 18:05:20 +0530
+Subject: drm/amd/display: Fix index out of bounds in DCN30 color
+ transformation
+
+From: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+
+[ Upstream commit d81873f9e715b72d4f8d391c8eb243946f784dfc ]
+
+This commit addresses a potential index out of bounds issue in the
+`cm3_helper_translate_curve_to_hw_format` function in the DCN30 color
+management module. The issue could occur when the index 'i' exceeds the
+number of transfer function points (TRANSFER_FUNC_POINTS).
+
+The fix adds a check to ensure 'i' is within bounds before accessing the
+transfer function points. If 'i' is out of bounds, the function returns
+false to indicate an error.
+
+drivers/gpu/drm/amd/amdgpu/../display/dc/dcn30/dcn30_cm_common.c:180 cm3_helper_translate_curve_to_hw_format() error: buffer overflow 'output_tf->tf_pts.red' 1025 <= s32max
+drivers/gpu/drm/amd/amdgpu/../display/dc/dcn30/dcn30_cm_common.c:181 cm3_helper_translate_curve_to_hw_format() error: buffer overflow 'output_tf->tf_pts.green' 1025 <= s32max
+drivers/gpu/drm/amd/amdgpu/../display/dc/dcn30/dcn30_cm_common.c:182 cm3_helper_translate_curve_to_hw_format() error: buffer overflow 'output_tf->tf_pts.blue' 1025 <= s32max
+
+Cc: Tom Chung <chiahsuan.chung@amd.com>
+Cc: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
+Cc: Roman Li <roman.li@amd.com>
+Cc: Alex Hung <alex.hung@amd.com>
+Cc: Aurabindo Pillai <aurabindo.pillai@amd.com>
+Cc: Harry Wentland <harry.wentland@amd.com>
+Cc: Hamza Mahfooz <hamza.mahfooz@amd.com>
+Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+Reviewed-by: Tom Chung <chiahsuan.chung@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c
+index edc77615d0973..0433f6b5dac78 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c
+@@ -177,6 +177,8 @@ bool cm3_helper_translate_curve_to_hw_format(
+ i += increment) {
+ if (j == hw_points)
+ break;
++ if (i >= TRANSFER_FUNC_POINTS)
++ return false;
+ rgb_resulted[j].red = output_tf->tf_pts.red[i];
+ rgb_resulted[j].green = output_tf->tf_pts.green[i];
+ rgb_resulted[j].blue = output_tf->tf_pts.blue[i];
+--
+2.43.0
+
--- /dev/null
+From 2637755aeaeef1b03c8b4cf994632c87e5da157c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 20 Jul 2024 18:44:02 +0530
+Subject: drm/amd/display: Fix index out of bounds in DCN30 degamma hardware
+ format translation
+
+From: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+
+[ Upstream commit bc50b614d59990747dd5aeced9ec22f9258991ff ]
+
+This commit addresses a potential index out of bounds issue in the
+`cm3_helper_translate_curve_to_degamma_hw_format` function in the DCN30
+color management module. The issue could occur when the index 'i'
+exceeds the number of transfer function points (TRANSFER_FUNC_POINTS).
+
+The fix adds a check to ensure 'i' is within bounds before accessing the
+transfer function points. If 'i' is out of bounds, the function returns
+false to indicate an error.
+
+Reported by smatch:
+drivers/gpu/drm/amd/amdgpu/../display/dc/dcn30/dcn30_cm_common.c:338 cm3_helper_translate_curve_to_degamma_hw_format() error: buffer overflow 'output_tf->tf_pts.red' 1025 <= s32max
+drivers/gpu/drm/amd/amdgpu/../display/dc/dcn30/dcn30_cm_common.c:339 cm3_helper_translate_curve_to_degamma_hw_format() error: buffer overflow 'output_tf->tf_pts.green' 1025 <= s32max
+drivers/gpu/drm/amd/amdgpu/../display/dc/dcn30/dcn30_cm_common.c:340 cm3_helper_translate_curve_to_degamma_hw_format() error: buffer overflow 'output_tf->tf_pts.blue' 1025 <= s32max
+
+Cc: Tom Chung <chiahsuan.chung@amd.com>
+Cc: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
+Cc: Roman Li <roman.li@amd.com>
+Cc: Alex Hung <alex.hung@amd.com>
+Cc: Aurabindo Pillai <aurabindo.pillai@amd.com>
+Cc: Harry Wentland <harry.wentland@amd.com>
+Cc: Hamza Mahfooz <hamza.mahfooz@amd.com>
+Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+Reviewed-by: Tom Chung <chiahsuan.chung@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c
+index b8327237ed441..edc77615d0973 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c
+@@ -335,6 +335,8 @@ bool cm3_helper_translate_curve_to_degamma_hw_format(
+ i += increment) {
+ if (j == hw_points - 1)
+ break;
++ if (i >= TRANSFER_FUNC_POINTS)
++ return false;
+ rgb_resulted[j].red = output_tf->tf_pts.red[i];
+ rgb_resulted[j].green = output_tf->tf_pts.green[i];
+ rgb_resulted[j].blue = output_tf->tf_pts.blue[i];
+--
+2.43.0
+
--- /dev/null
+From 90dce44ee6b6b61ee161f3818a2361651dfc7afe Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 20 Jul 2024 17:48:27 +0530
+Subject: drm/amd/display: Fix index out of bounds in degamma hardware format
+ translation
+
+From: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+
+[ Upstream commit b7e99058eb2e86aabd7a10761e76cae33d22b49f ]
+
+Fixes index out of bounds issue in
+`cm_helper_translate_curve_to_degamma_hw_format` function. The issue
+could occur when the index 'i' exceeds the number of transfer function
+points (TRANSFER_FUNC_POINTS).
+
+The fix adds a check to ensure 'i' is within bounds before accessing the
+transfer function points. If 'i' is out of bounds the function returns
+false to indicate an error.
+
+Reported by smatch:
+drivers/gpu/drm/amd/amdgpu/../display/dc/dcn10/dcn10_cm_common.c:594 cm_helper_translate_curve_to_degamma_hw_format() error: buffer overflow 'output_tf->tf_pts.red' 1025 <= s32max
+drivers/gpu/drm/amd/amdgpu/../display/dc/dcn10/dcn10_cm_common.c:595 cm_helper_translate_curve_to_degamma_hw_format() error: buffer overflow 'output_tf->tf_pts.green' 1025 <= s32max
+drivers/gpu/drm/amd/amdgpu/../display/dc/dcn10/dcn10_cm_common.c:596 cm_helper_translate_curve_to_degamma_hw_format() error: buffer overflow 'output_tf->tf_pts.blue' 1025 <= s32max
+
+Cc: Tom Chung <chiahsuan.chung@amd.com>
+Cc: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
+Cc: Roman Li <roman.li@amd.com>
+Cc: Alex Hung <alex.hung@amd.com>
+Cc: Aurabindo Pillai <aurabindo.pillai@amd.com>
+Cc: Harry Wentland <harry.wentland@amd.com>
+Cc: Hamza Mahfooz <hamza.mahfooz@amd.com>
+Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+Reviewed-by: Tom Chung <chiahsuan.chung@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c
+index 0b49362f71b06..eaed5d1c398aa 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c
+@@ -591,6 +591,8 @@ bool cm_helper_translate_curve_to_degamma_hw_format(
+ i += increment) {
+ if (j == hw_points - 1)
+ break;
++ if (i >= TRANSFER_FUNC_POINTS)
++ return false;
+ rgb_resulted[j].red = output_tf->tf_pts.red[i];
+ rgb_resulted[j].green = output_tf->tf_pts.green[i];
+ rgb_resulted[j].blue = output_tf->tf_pts.blue[i];
+--
+2.43.0
+
--- /dev/null
+From 01bdb1d36092eae870d7dc4734deddbbe4546343 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 26 Jul 2024 19:31:55 +0530
+Subject: drm/amd/display: Handle null 'stream_status' in
+ 'planes_changed_for_existing_stream'
+
+From: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+
+[ Upstream commit 8141f21b941710ecebe49220b69822cab3abd23d ]
+
+This commit adds a null check for 'stream_status' in the function
+'planes_changed_for_existing_stream'. Previously, the code assumed
+'stream_status' could be null, but did not handle the case where it was
+actually null. This could lead to a null pointer dereference.
+
+Reported by smatch:
+drivers/gpu/drm/amd/amdgpu/../display/dc/core/dc_resource.c:3784 planes_changed_for_existing_stream() error: we previously assumed 'stream_status' could be null (see line 3774)
+
+Cc: Tom Chung <chiahsuan.chung@amd.com>
+Cc: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
+Cc: Roman Li <roman.li@amd.com>
+Cc: Alex Hung <alex.hung@amd.com>
+Cc: Aurabindo Pillai <aurabindo.pillai@amd.com>
+Cc: Harry Wentland <harry.wentland@amd.com>
+Cc: Hamza Mahfooz <hamza.mahfooz@amd.com>
+Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+Reviewed-by: Tom Chung <chiahsuan.chung@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+index 786b56e96a816..7462c34793799 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+@@ -3662,8 +3662,10 @@ static bool planes_changed_for_existing_stream(struct dc_state *context,
+ }
+ }
+
+- if (!stream_status)
++ if (!stream_status) {
+ ASSERT(0);
++ return false;
++ }
+
+ for (i = 0; i < set_count; i++)
+ if (set[i].stream == stream)
+--
+2.43.0
+
--- /dev/null
+From 15b6e650cb40bb877b553f7d0a30b8bd5dcc0b9a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 15 Jul 2024 09:57:01 -0600
+Subject: drm/amd/display: Initialize get_bytes_per_element's default to 1
+
+From: Alex Hung <alex.hung@amd.com>
+
+[ Upstream commit 4067f4fa0423a89fb19a30b57231b384d77d2610 ]
+
+Variables, used as denominators and maybe not assigned to other values,
+should not be 0. bytes_per_element_y & bytes_per_element_c are
+initialized by get_bytes_per_element() which should never return 0.
+
+This fixes 10 DIVIDE_BY_ZERO issues reported by Coverity.
+
+Signed-off-by: Alex Hung <alex.hung@amd.com>
+Reviewed-by: Aurabindo Pillai <aurabindo.pillai@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Rodrigo Siqueira <rodrigo.siqueira@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c | 2 +-
+ .../gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c
+index 0fc9f3e3ffaef..f603486af6e30 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c
++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c
+@@ -78,7 +78,7 @@ static void calculate_ttu_cursor(struct display_mode_lib *mode_lib,
+
+ static unsigned int get_bytes_per_element(enum source_format_class source_format, bool is_chroma)
+ {
+- unsigned int ret_val = 0;
++ unsigned int ret_val = 1;
+
+ if (source_format == dm_444_16) {
+ if (!is_chroma)
+diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c
+index 618f4b682ab1b..9f28e4d3c664c 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c
++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c
+@@ -53,7 +53,7 @@ static void calculate_ttu_cursor(
+
+ static unsigned int get_bytes_per_element(enum source_format_class source_format, bool is_chroma)
+ {
+- unsigned int ret_val = 0;
++ unsigned int ret_val = 1;
+
+ if (source_format == dm_444_16) {
+ if (!is_chroma)
+--
+2.43.0
+
--- /dev/null
+From 10aa1c246de785f2329bb0ce0f95800c224d2a80 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Jun 2024 11:51:27 -0600
+Subject: drm/amd/display: Pass non-null to
+ dcn20_validate_apply_pipe_split_flags
+
+From: Alex Hung <alex.hung@amd.com>
+
+[ Upstream commit 5559598742fb4538e4c51c48ef70563c49c2af23 ]
+
+[WHAT & HOW]
+"dcn20_validate_apply_pipe_split_flags" dereferences merge, and thus it
+cannot be a null pointer. Let's pass a valid pointer to avoid null
+dereference.
+
+This fixes 2 FORWARD_NULL issues reported by Coverity.
+
+Reviewed-by: Rodrigo Siqueira <rodrigo.siqueira@amd.com>
+Signed-off-by: Jerry Zuo <jerry.zuo@amd.com>
+Signed-off-by: Alex Hung <alex.hung@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c | 3 ++-
+ drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c | 3 ++-
+ 2 files changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c
+index 6b380e037e3f8..c0d1b41eb9004 100644
+--- a/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c
+@@ -2033,6 +2033,7 @@ bool dcn20_fast_validate_bw(
+ {
+ bool out = false;
+ int split[MAX_PIPES] = { 0 };
++ bool merge[MAX_PIPES] = { false };
+ int pipe_cnt, i, pipe_idx, vlevel;
+
+ ASSERT(pipes);
+@@ -2057,7 +2058,7 @@ bool dcn20_fast_validate_bw(
+ if (vlevel > context->bw_ctx.dml.soc.num_states)
+ goto validate_fail;
+
+- vlevel = dcn20_validate_apply_pipe_split_flags(dc, context, vlevel, split, NULL);
++ vlevel = dcn20_validate_apply_pipe_split_flags(dc, context, vlevel, split, merge);
+
+ /*initialize pipe_just_split_from to invalid idx*/
+ for (i = 0; i < MAX_PIPES; i++)
+diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c
+index 8663cbc3d1cf5..347e6aaea582f 100644
+--- a/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c
+@@ -774,6 +774,7 @@ bool dcn21_fast_validate_bw(struct dc *dc,
+ {
+ bool out = false;
+ int split[MAX_PIPES] = { 0 };
++ bool merge[MAX_PIPES] = { false };
+ int pipe_cnt, i, pipe_idx, vlevel;
+
+ ASSERT(pipes);
+@@ -816,7 +817,7 @@ bool dcn21_fast_validate_bw(struct dc *dc,
+ goto validate_fail;
+ }
+
+- vlevel = dcn20_validate_apply_pipe_split_flags(dc, context, vlevel, split, NULL);
++ vlevel = dcn20_validate_apply_pipe_split_flags(dc, context, vlevel, split, merge);
+
+ for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) {
+ struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
+--
+2.43.0
+
--- /dev/null
+From 74cb516c5ef321e3636b64783a42545f4c3a975c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 18 Jul 2024 11:53:31 -0400
+Subject: drm/amd/display: Use gpuvm_min_page_size_kbytes for DML2 surfaces
+
+From: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
+
+[ Upstream commit 31663521ede2edb622ee1b397ae3ac666d6351c5 ]
+
+[Why]
+It's currently hard coded to 256 when it should be using the SOC
+provided values. This can result in corruption with linear surfaces
+where we prefetch more PTE than the buffer can hold.
+
+[How]
+Update the min page size correctly for the plane.
+
+Signed-off-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
+Reviewed-by: Jun Lei <jun.lei@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Rodrigo Siqueira <rodrigo.siqueira@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../display/dc/dml2/dml2_translation_helper.c | 20 +++++++++++++------
+ 1 file changed, 14 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c b/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c
+index edff6b447680c..d5dbfb33f93dc 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c
++++ b/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c
+@@ -828,7 +828,9 @@ static void get_scaler_data_for_plane(const struct dc_plane_state *in, struct dc
+ memcpy(out, &temp_pipe->plane_res.scl_data, sizeof(*out));
+ }
+
+-static void populate_dummy_dml_plane_cfg(struct dml_plane_cfg_st *out, unsigned int location, const struct dc_stream_state *in)
++static void populate_dummy_dml_plane_cfg(struct dml_plane_cfg_st *out, unsigned int location,
++ const struct dc_stream_state *in,
++ const struct soc_bounding_box_st *soc)
+ {
+ dml_uint_t width, height;
+
+@@ -845,7 +847,7 @@ static void populate_dummy_dml_plane_cfg(struct dml_plane_cfg_st *out, unsigned
+ out->CursorBPP[location] = dml_cur_32bit;
+ out->CursorWidth[location] = 256;
+
+- out->GPUVMMinPageSizeKBytes[location] = 256;
++ out->GPUVMMinPageSizeKBytes[location] = soc->gpuvm_min_page_size_kbytes;
+
+ out->ViewportWidth[location] = width;
+ out->ViewportHeight[location] = height;
+@@ -882,7 +884,9 @@ static void populate_dummy_dml_plane_cfg(struct dml_plane_cfg_st *out, unsigned
+ out->ScalerEnabled[location] = false;
+ }
+
+-static void populate_dml_plane_cfg_from_plane_state(struct dml_plane_cfg_st *out, unsigned int location, const struct dc_plane_state *in, struct dc_state *context)
++static void populate_dml_plane_cfg_from_plane_state(struct dml_plane_cfg_st *out, unsigned int location,
++ const struct dc_plane_state *in, struct dc_state *context,
++ const struct soc_bounding_box_st *soc)
+ {
+ struct scaler_data *scaler_data = kzalloc(sizeof(*scaler_data), GFP_KERNEL);
+ if (!scaler_data)
+@@ -893,7 +897,7 @@ static void populate_dml_plane_cfg_from_plane_state(struct dml_plane_cfg_st *out
+ out->CursorBPP[location] = dml_cur_32bit;
+ out->CursorWidth[location] = 256;
+
+- out->GPUVMMinPageSizeKBytes[location] = 256;
++ out->GPUVMMinPageSizeKBytes[location] = soc->gpuvm_min_page_size_kbytes;
+
+ out->ViewportWidth[location] = scaler_data->viewport.width;
+ out->ViewportHeight[location] = scaler_data->viewport.height;
+@@ -1174,7 +1178,8 @@ void map_dc_state_into_dml_display_cfg(struct dml2_context *dml2, struct dc_stat
+ disp_cfg_plane_location = dml_dispcfg->num_surfaces++;
+
+ populate_dummy_dml_surface_cfg(&dml_dispcfg->surface, disp_cfg_plane_location, context->streams[i]);
+- populate_dummy_dml_plane_cfg(&dml_dispcfg->plane, disp_cfg_plane_location, context->streams[i]);
++ populate_dummy_dml_plane_cfg(&dml_dispcfg->plane, disp_cfg_plane_location,
++ context->streams[i], &dml2->v20.dml_core_ctx.soc);
+
+ dml_dispcfg->plane.BlendingAndTiming[disp_cfg_plane_location] = disp_cfg_stream_location;
+
+@@ -1190,7 +1195,10 @@ void map_dc_state_into_dml_display_cfg(struct dml2_context *dml2, struct dc_stat
+ ASSERT(disp_cfg_plane_location >= 0 && disp_cfg_plane_location <= __DML2_WRAPPER_MAX_STREAMS_PLANES__);
+
+ populate_dml_surface_cfg_from_plane_state(dml2->v20.dml_core_ctx.project, &dml_dispcfg->surface, disp_cfg_plane_location, context->stream_status[i].plane_states[j]);
+- populate_dml_plane_cfg_from_plane_state(&dml_dispcfg->plane, disp_cfg_plane_location, context->stream_status[i].plane_states[j], context);
++ populate_dml_plane_cfg_from_plane_state(
++ &dml_dispcfg->plane, disp_cfg_plane_location,
++ context->stream_status[i].plane_states[j], context,
++ &dml2->v20.dml_core_ctx.soc);
+
+ if (stream_mall_type == SUBVP_MAIN) {
+ dml_dispcfg->plane.UseMALLForPStateChange[disp_cfg_plane_location] = dml_use_mall_pstate_change_sub_viewport;
+--
+2.43.0
+
--- /dev/null
+From fdead484e49c95c4bee7f8ca05eaf73092532e90 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 7 Aug 2024 17:15:12 +0800
+Subject: drm/amd/pm: ensure the fw_info is not null before using it
+
+From: Tim Huang <tim.huang@amd.com>
+
+[ Upstream commit 186fb12e7a7b038c2710ceb2fb74068f1b5d55a4 ]
+
+This resolves the dereference null return value warning
+reported by Coverity.
+
+Signed-off-by: Tim Huang <tim.huang@amd.com>
+Reviewed-by: Jesse Zhang <jesse.zhang@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c
+index 5794b64507bf9..56a2257525806 100644
+--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c
++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c
+@@ -1185,6 +1185,8 @@ static int init_overdrive_limits(struct pp_hwmgr *hwmgr,
+ fw_info = smu_atom_get_data_table(hwmgr->adev,
+ GetIndexIntoMasterTable(DATA, FirmwareInfo),
+ &size, &frev, &crev);
++ PP_ASSERT_WITH_CODE(fw_info != NULL,
++ "Missing firmware info!", return -EINVAL);
+
+ if ((fw_info->ucTableFormatRevision == 1)
+ && (le16_to_cpu(fw_info->usStructureSize) >= sizeof(ATOM_FIRMWARE_INFO_V1_4)))
+--
+2.43.0
+
--- /dev/null
+From eca008855174ca03f598be20cc15d16391300e7d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 21 Aug 2024 14:42:41 +0800
+Subject: drm/amdgpu: add list empty check to avoid null pointer issue
+
+From: Yang Wang <kevinyang.wang@amd.com>
+
+[ Upstream commit 4416377ae1fdc41a90b665943152ccd7ff61d3c5 ]
+
+Add list empty check to avoid null pointer issues in some corner cases.
+- list_for_each_entry_safe()
+
+Signed-off-by: Yang Wang <kevinyang.wang@amd.com>
+Reviewed-by: Tao Zhou <tao.zhou1@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c
+index 9baee7c246b6d..a513819b72311 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c
+@@ -80,6 +80,9 @@ static void aca_banks_release(struct aca_banks *banks)
+ {
+ struct aca_bank_node *node, *tmp;
+
++ if (list_empty(&banks->list))
++ return;
++
+ list_for_each_entry_safe(node, tmp, &banks->list, node) {
+ list_del(&node->node);
+ kvfree(node);
+@@ -562,9 +565,13 @@ static void aca_error_fini(struct aca_error *aerr)
+ struct aca_bank_error *bank_error, *tmp;
+
+ mutex_lock(&aerr->lock);
++ if (list_empty(&aerr->list))
++ goto out_unlock;
++
+ list_for_each_entry_safe(bank_error, tmp, &aerr->list, node)
+ aca_bank_error_remove(aerr, bank_error);
+
++out_unlock:
+ mutex_destroy(&aerr->lock);
+ }
+
+@@ -680,6 +687,9 @@ static void aca_manager_fini(struct aca_handle_manager *mgr)
+ {
+ struct aca_handle *handle, *tmp;
+
++ if (list_empty(&mgr->list))
++ return;
++
+ list_for_each_entry_safe(handle, tmp, &mgr->list, node)
+ amdgpu_aca_remove_handle(handle);
+ }
+--
+2.43.0
+
--- /dev/null
+From 3c9741dcf701d420303ebaa8105a889b62b35d0c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 30 Aug 2024 15:25:54 +0800
+Subject: drm/amdgpu: add raven1 gfxoff quirk
+
+From: Peng Liu <liupeng01@kylinos.cn>
+
+[ Upstream commit 0126c0ae11e8b52ecfde9d1b174ee2f32d6c3a5d ]
+
+Fix screen corruption with openkylin.
+
+Link: https://bbs.openkylin.top/t/topic/171497
+Signed-off-by: Peng Liu <liupeng01@kylinos.cn>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
+index 3c8c5abf35abd..c86a6363b2c3d 100644
+--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
+@@ -1172,6 +1172,8 @@ static const struct amdgpu_gfxoff_quirk amdgpu_gfxoff_quirk_list[] = {
+ { 0x1002, 0x15dd, 0x1002, 0x15dd, 0xc6 },
+ /* Apple MacBook Pro (15-inch, 2019) Radeon Pro Vega 20 4 GB */
+ { 0x1002, 0x69af, 0x106b, 0x019a, 0xc0 },
++ /* https://bbs.openkylin.top/t/topic/171497 */
++ { 0x1002, 0x15d8, 0x19e5, 0x3e14, 0xc2 },
+ { 0, 0, 0, 0, 0 },
+ };
+
+--
+2.43.0
+
--- /dev/null
+From f284b9fcbd8c159d528a7ecff7e5ee4e9d5df29e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 8 Aug 2024 13:40:23 -0400
+Subject: drm/amdgpu: Block MMR_READ IOCTL in reset
+
+From: Victor Skvortsov <victor.skvortsov@amd.com>
+
+[ Upstream commit 9e823f307074c0f82b5f6044943b0086e3079bed ]
+
+Register access from userspace should be blocked until
+reset is complete.
+
+Signed-off-by: Victor Skvortsov <victor.skvortsov@amd.com>
+Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 43 ++++++++++++++++++-------
+ 1 file changed, 31 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
+index 977cde6d13626..6d4e774b6cedc 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
+@@ -43,6 +43,7 @@
+ #include "amdgpu_gem.h"
+ #include "amdgpu_display.h"
+ #include "amdgpu_ras.h"
++#include "amdgpu_reset.h"
+ #include "amd_pcie.h"
+
+ void amdgpu_unregister_gpu_instance(struct amdgpu_device *adev)
+@@ -778,6 +779,7 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
+ ? -EFAULT : 0;
+ }
+ case AMDGPU_INFO_READ_MMR_REG: {
++ int ret = 0;
+ unsigned int n, alloc_size;
+ uint32_t *regs;
+ unsigned int se_num = (info->read_mmr_reg.instance >>
+@@ -787,24 +789,37 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
+ AMDGPU_INFO_MMR_SH_INDEX_SHIFT) &
+ AMDGPU_INFO_MMR_SH_INDEX_MASK;
+
++ if (!down_read_trylock(&adev->reset_domain->sem))
++ return -ENOENT;
++
+ /* set full masks if the userspace set all bits
+ * in the bitfields
+ */
+- if (se_num == AMDGPU_INFO_MMR_SE_INDEX_MASK)
++ if (se_num == AMDGPU_INFO_MMR_SE_INDEX_MASK) {
+ se_num = 0xffffffff;
+- else if (se_num >= AMDGPU_GFX_MAX_SE)
+- return -EINVAL;
+- if (sh_num == AMDGPU_INFO_MMR_SH_INDEX_MASK)
++ } else if (se_num >= AMDGPU_GFX_MAX_SE) {
++ ret = -EINVAL;
++ goto out;
++ }
++
++ if (sh_num == AMDGPU_INFO_MMR_SH_INDEX_MASK) {
+ sh_num = 0xffffffff;
+- else if (sh_num >= AMDGPU_GFX_MAX_SH_PER_SE)
+- return -EINVAL;
++ } else if (sh_num >= AMDGPU_GFX_MAX_SH_PER_SE) {
++ ret = -EINVAL;
++ goto out;
++ }
+
+- if (info->read_mmr_reg.count > 128)
+- return -EINVAL;
++ if (info->read_mmr_reg.count > 128) {
++ ret = -EINVAL;
++ goto out;
++ }
+
+ regs = kmalloc_array(info->read_mmr_reg.count, sizeof(*regs), GFP_KERNEL);
+- if (!regs)
+- return -ENOMEM;
++ if (!regs) {
++ ret = -ENOMEM;
++ goto out;
++ }
++
+ alloc_size = info->read_mmr_reg.count * sizeof(*regs);
+
+ amdgpu_gfx_off_ctrl(adev, false);
+@@ -816,13 +831,17 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
+ info->read_mmr_reg.dword_offset + i);
+ kfree(regs);
+ amdgpu_gfx_off_ctrl(adev, true);
+- return -EFAULT;
++ ret = -EFAULT;
++ goto out;
+ }
+ }
+ amdgpu_gfx_off_ctrl(adev, true);
+ n = copy_to_user(out, regs, min(size, alloc_size));
+ kfree(regs);
+- return n ? -EFAULT : 0;
++ ret = (n ? -EFAULT : 0);
++out:
++ up_read(&adev->reset_domain->sem);
++ return ret;
+ }
+ case AMDGPU_INFO_DEV_INFO: {
+ struct drm_amdgpu_info_device *dev_info;
+--
+2.43.0
+
--- /dev/null
+From ea14f7e443375ce5354949f73febe7aa27e3fdaf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 2 Jul 2024 11:54:30 +0200
+Subject: drm/amdgpu: disallow multiple BO_HANDLES chunks in one submit
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>
+
+[ Upstream commit fec5f8e8c6bcf83ed7a392801d7b44c5ecfc1e82 ]
+
+Before this commit, only submits with both a BO_HANDLES chunk and a
+'bo_list_handle' would be rejected (by amdgpu_cs_parser_bos).
+
+But if UMD sent multiple BO_HANDLES, what would happen is:
+* only the last one would be really used
+* all the others would leak memory as amdgpu_cs_p1_bo_handles would
+ overwrite the previous p->bo_list value
+
+This commit rejects submissions with multiple BO_HANDLES chunks to
+match the implementation of the parser.
+
+Signed-off-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>
+Reviewed-by: Christian König <christian.koenig@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+index 6dfdff58bffd1..78b3c067fea7e 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+@@ -263,6 +263,10 @@ static int amdgpu_cs_pass1(struct amdgpu_cs_parser *p,
+ if (size < sizeof(struct drm_amdgpu_bo_list_in))
+ goto free_partial_kdata;
+
++ /* Only a single BO list is allowed to simplify handling. */
++ if (p->bo_list)
++ ret = -EINVAL;
++
+ ret = amdgpu_cs_p1_bo_handles(p, p->chunks[i].kdata);
+ if (ret)
+ goto free_partial_kdata;
+--
+2.43.0
+
--- /dev/null
+From ab9c7b50eb4002c898db893d88c71083de991104 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 30 Aug 2024 15:27:08 +0800
+Subject: drm/amdgpu: enable gfxoff quirk on HP 705G4
+
+From: Peng Liu <liupeng01@kylinos.cn>
+
+[ Upstream commit 2c7795e245d993bcba2f716a8c93a5891ef910c9 ]
+
+Enabling gfxoff quirk results in perfectly usable
+graphical user interface on HP 705G4 DM with R5 2400G.
+
+Without the quirk, X server is completely unusable as
+every few seconds there is gpu reset due to ring gfx timeout.
+
+Signed-off-by: Peng Liu <liupeng01@kylinos.cn>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
+index c86a6363b2c3d..0594eab666a9b 100644
+--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
+@@ -1174,6 +1174,8 @@ static const struct amdgpu_gfxoff_quirk amdgpu_gfxoff_quirk_list[] = {
+ { 0x1002, 0x69af, 0x106b, 0x019a, 0xc0 },
+ /* https://bbs.openkylin.top/t/topic/171497 */
+ { 0x1002, 0x15d8, 0x19e5, 0x3e14, 0xc2 },
++ /* HP 705G4 DM with R5 2400G */
++ { 0x1002, 0x15dd, 0x103c, 0x8464, 0xd6 },
+ { 0, 0, 0, 0, 0 },
+ };
+
+--
+2.43.0
+
--- /dev/null
+From d7726729a2100aaf7a1070454c2df1ffb28dddcf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 1 Aug 2024 10:38:37 +0800
+Subject: drm/amdgpu: fix unchecked return value warning for amdgpu_gfx
+
+From: Tim Huang <tim.huang@amd.com>
+
+[ Upstream commit c0277b9d7c2ee9ee5dbc948548984f0fbb861301 ]
+
+This resolves the unchecded return value warning reported by Coverity.
+
+Signed-off-by: Tim Huang <tim.huang@amd.com>
+Reviewed-by: Jesse Zhang <jesse.zhang@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c | 18 ++++++++++++++----
+ 1 file changed, 14 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
+index e92bdc9a39d35..1935b211b527d 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
+@@ -816,8 +816,11 @@ int amdgpu_gfx_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *r
+ int r;
+
+ if (amdgpu_ras_is_supported(adev, ras_block->block)) {
+- if (!amdgpu_persistent_edc_harvesting_supported(adev))
+- amdgpu_ras_reset_error_status(adev, AMDGPU_RAS_BLOCK__GFX);
++ if (!amdgpu_persistent_edc_harvesting_supported(adev)) {
++ r = amdgpu_ras_reset_error_status(adev, AMDGPU_RAS_BLOCK__GFX);
++ if (r)
++ return r;
++ }
+
+ r = amdgpu_ras_block_late_init(adev, ras_block);
+ if (r)
+@@ -961,7 +964,10 @@ uint32_t amdgpu_kiq_rreg(struct amdgpu_device *adev, uint32_t reg, uint32_t xcc_
+ pr_err("critical bug! too many kiq readers\n");
+ goto failed_unlock;
+ }
+- amdgpu_ring_alloc(ring, 32);
++ r = amdgpu_ring_alloc(ring, 32);
++ if (r)
++ goto failed_unlock;
++
+ amdgpu_ring_emit_rreg(ring, reg, reg_val_offs);
+ r = amdgpu_fence_emit_polling(ring, &seq, MAX_KIQ_REG_WAIT);
+ if (r)
+@@ -1027,7 +1033,10 @@ void amdgpu_kiq_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v, uint3
+ }
+
+ spin_lock_irqsave(&kiq->ring_lock, flags);
+- amdgpu_ring_alloc(ring, 32);
++ r = amdgpu_ring_alloc(ring, 32);
++ if (r)
++ goto failed_unlock;
++
+ amdgpu_ring_emit_wreg(ring, reg, v);
+ r = amdgpu_fence_emit_polling(ring, &seq, MAX_KIQ_REG_WAIT);
+ if (r)
+@@ -1063,6 +1072,7 @@ void amdgpu_kiq_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v, uint3
+
+ failed_undo:
+ amdgpu_ring_undo(ring);
++failed_unlock:
+ spin_unlock_irqrestore(&kiq->ring_lock, flags);
+ failed_kiq_write:
+ dev_err(adev->dev, "failed to write reg:%x\n", reg);
+--
+2.43.0
+
--- /dev/null
+From c41c7229251589c515b35d1cad324ace9059fb3d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 1 Aug 2024 13:47:55 +0800
+Subject: drm/amdgpu: fix unchecked return value warning for amdgpu_atombios
+
+From: Tim Huang <tim.huang@amd.com>
+
+[ Upstream commit 92549780e32718d64a6d08bbbb3c6fffecb541c7 ]
+
+This resolves the unchecded return value warning reported by Coverity.
+
+Signed-off-by: Tim Huang <tim.huang@amd.com>
+Reviewed-by: Jesse Zhang <jesse.zhang@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c | 35 ++++++++++++--------
+ 1 file changed, 21 insertions(+), 14 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c
+index 7dc102f0bc1d3..0c8975ac5af9e 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c
+@@ -1018,8 +1018,9 @@ int amdgpu_atombios_get_clock_dividers(struct amdgpu_device *adev,
+ if (clock_type == COMPUTE_ENGINE_PLL_PARAM) {
+ args.v3.ulClockParams = cpu_to_le32((clock_type << 24) | clock);
+
+- amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args,
+- sizeof(args));
++ if (amdgpu_atom_execute_table(adev->mode_info.atom_context,
++ index, (uint32_t *)&args, sizeof(args)))
++ return -EINVAL;
+
+ dividers->post_div = args.v3.ucPostDiv;
+ dividers->enable_post_div = (args.v3.ucCntlFlag &
+@@ -1039,8 +1040,9 @@ int amdgpu_atombios_get_clock_dividers(struct amdgpu_device *adev,
+ if (strobe_mode)
+ args.v5.ucInputFlag = ATOM_PLL_INPUT_FLAG_PLL_STROBE_MODE_EN;
+
+- amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args,
+- sizeof(args));
++ if (amdgpu_atom_execute_table(adev->mode_info.atom_context,
++ index, (uint32_t *)&args, sizeof(args)))
++ return -EINVAL;
+
+ dividers->post_div = args.v5.ucPostDiv;
+ dividers->enable_post_div = (args.v5.ucCntlFlag &
+@@ -1058,8 +1060,9 @@ int amdgpu_atombios_get_clock_dividers(struct amdgpu_device *adev,
+ /* fusion */
+ args.v4.ulClock = cpu_to_le32(clock); /* 10 khz */
+
+- amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args,
+- sizeof(args));
++ if (amdgpu_atom_execute_table(adev->mode_info.atom_context,
++ index, (uint32_t *)&args, sizeof(args)))
++ return -EINVAL;
+
+ dividers->post_divider = dividers->post_div = args.v4.ucPostDiv;
+ dividers->real_clock = le32_to_cpu(args.v4.ulClock);
+@@ -1070,8 +1073,9 @@ int amdgpu_atombios_get_clock_dividers(struct amdgpu_device *adev,
+ args.v6_in.ulClock.ulComputeClockFlag = clock_type;
+ args.v6_in.ulClock.ulClockFreq = cpu_to_le32(clock); /* 10 khz */
+
+- amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args,
+- sizeof(args));
++ if (amdgpu_atom_execute_table(adev->mode_info.atom_context,
++ index, (uint32_t *)&args, sizeof(args)))
++ return -EINVAL;
+
+ dividers->whole_fb_div = le16_to_cpu(args.v6_out.ulFbDiv.usFbDiv);
+ dividers->frac_fb_div = le16_to_cpu(args.v6_out.ulFbDiv.usFbDivFrac);
+@@ -1113,8 +1117,9 @@ int amdgpu_atombios_get_memory_pll_dividers(struct amdgpu_device *adev,
+ if (strobe_mode)
+ args.ucInputFlag |= MPLL_INPUT_FLAG_STROBE_MODE_EN;
+
+- amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args,
+- sizeof(args));
++ if (amdgpu_atom_execute_table(adev->mode_info.atom_context,
++ index, (uint32_t *)&args, sizeof(args)))
++ return -EINVAL;
+
+ mpll_param->clkfrac = le16_to_cpu(args.ulFbDiv.usFbDivFrac);
+ mpll_param->clkf = le16_to_cpu(args.ulFbDiv.usFbDiv);
+@@ -1211,8 +1216,9 @@ int amdgpu_atombios_get_max_vddc(struct amdgpu_device *adev, u8 voltage_type,
+ args.v2.ucVoltageMode = 0;
+ args.v2.usVoltageLevel = 0;
+
+- amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args,
+- sizeof(args));
++ if (amdgpu_atom_execute_table(adev->mode_info.atom_context,
++ index, (uint32_t *)&args, sizeof(args)))
++ return -EINVAL;
+
+ *voltage = le16_to_cpu(args.v2.usVoltageLevel);
+ break;
+@@ -1221,8 +1227,9 @@ int amdgpu_atombios_get_max_vddc(struct amdgpu_device *adev, u8 voltage_type,
+ args.v3.ucVoltageMode = ATOM_GET_VOLTAGE_LEVEL;
+ args.v3.usVoltageLevel = cpu_to_le16(voltage_id);
+
+- amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args,
+- sizeof(args));
++ if (amdgpu_atom_execute_table(adev->mode_info.atom_context,
++ index, (uint32_t *)&args, sizeof(args)))
++ return -EINVAL;
+
+ *voltage = le16_to_cpu(args.v3.usVoltageLevel);
+ break;
+--
+2.43.0
+
--- /dev/null
+From d48d9048adce8926942b9f7750a67aefb6825b9f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 24 Jul 2024 18:20:34 -0400
+Subject: drm/amdgpu/gfx10: use rlc safe mode for soft recovery
+
+From: Alex Deucher <alexander.deucher@amd.com>
+
+[ Upstream commit ead60e9c4e29c8574cae1be4fe3af1d9a978fb0f ]
+
+Protect the MMIO access with safe mode.
+
+Acked-by: Vitaly Prosyak <vitaly.prosyak@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
+index 536287ddd2ec1..6204336750c6a 100644
+--- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
+@@ -8897,7 +8897,9 @@ static void gfx_v10_0_ring_soft_recovery(struct amdgpu_ring *ring,
+ value = REG_SET_FIELD(value, SQ_CMD, MODE, 0x01);
+ value = REG_SET_FIELD(value, SQ_CMD, CHECK_VMID, 1);
+ value = REG_SET_FIELD(value, SQ_CMD, VM_ID, vmid);
++ amdgpu_gfx_rlc_enter_safe_mode(adev, 0);
+ WREG32_SOC15(GC, 0, mmSQ_CMD, value);
++ amdgpu_gfx_rlc_exit_safe_mode(adev, 0);
+ }
+
+ static void
+--
+2.43.0
+
--- /dev/null
+From eefee339f47697cbe172d60ee24a5d5d2fb5fd76 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 12 Jul 2024 15:36:19 -0400
+Subject: drm/amdgpu/gfx11: enter safe mode before touching CP_INT_CNTL
+
+From: Alex Deucher <alexander.deucher@amd.com>
+
+[ Upstream commit b5be054c585110b2c5c1b180136800e8c41c7bb4 ]
+
+Need to enter safe mode before touching GC MMIO.
+
+Acked-by: Vitaly Prosyak <vitaly.prosyak@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
+index 4ba8eb45ac174..0bcdcb2101577 100644
+--- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
+@@ -4497,6 +4497,8 @@ static int gfx_v11_0_soft_reset(void *handle)
+ int r, i, j, k;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
++ gfx_v11_0_set_safe_mode(adev, 0);
++
+ tmp = RREG32_SOC15(GC, 0, regCP_INT_CNTL);
+ tmp = REG_SET_FIELD(tmp, CP_INT_CNTL, CMP_BUSY_INT_ENABLE, 0);
+ tmp = REG_SET_FIELD(tmp, CP_INT_CNTL, CNTX_BUSY_INT_ENABLE, 0);
+@@ -4504,8 +4506,6 @@ static int gfx_v11_0_soft_reset(void *handle)
+ tmp = REG_SET_FIELD(tmp, CP_INT_CNTL, GFX_IDLE_INT_ENABLE, 0);
+ WREG32_SOC15(GC, 0, regCP_INT_CNTL, tmp);
+
+- gfx_v11_0_set_safe_mode(adev, 0);
+-
+ mutex_lock(&adev->srbm_mutex);
+ for (i = 0; i < adev->gfx.mec.num_mec; ++i) {
+ for (j = 0; j < adev->gfx.mec.num_queue_per_pipe; j++) {
+--
+2.43.0
+
--- /dev/null
+From 06d094709cb66935ac8de8a0326a3f7913eb4679 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 24 Jul 2024 18:20:23 -0400
+Subject: drm/amdgpu/gfx11: use rlc safe mode for soft recovery
+
+From: Alex Deucher <alexander.deucher@amd.com>
+
+[ Upstream commit 3f2d35c325534c1b7ac5072173f0dc7ca969dec2 ]
+
+Protect the MMIO access with safe mode.
+
+Acked-by: Vitaly Prosyak <vitaly.prosyak@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
+index 0bcdcb2101577..6b5cd0dcd25f4 100644
+--- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
+@@ -5792,7 +5792,9 @@ static void gfx_v11_0_ring_soft_recovery(struct amdgpu_ring *ring,
+ value = REG_SET_FIELD(value, SQ_CMD, MODE, 0x01);
+ value = REG_SET_FIELD(value, SQ_CMD, CHECK_VMID, 1);
+ value = REG_SET_FIELD(value, SQ_CMD, VM_ID, vmid);
++ amdgpu_gfx_rlc_enter_safe_mode(adev, 0);
+ WREG32_SOC15(GC, 0, regSQ_CMD, value);
++ amdgpu_gfx_rlc_exit_safe_mode(adev, 0);
+ }
+
+ static void
+--
+2.43.0
+
--- /dev/null
+From 1b9adcb5f75046d24e96ecb4815fcead7e371fd6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 2 Jul 2024 10:24:59 -0400
+Subject: drm/amdgpu/gfx9: properly handle error ints on all pipes
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Alex Deucher <alexander.deucher@amd.com>
+
+[ Upstream commit 48695573d2feaf42812c1ad54e01caff0d1c2d71 ]
+
+Need to handle the interrupt enables for all pipes.
+
+Acked-by: Christian König <christian.koenig@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 44 +++++++++++++++++++++-
+ drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c | 50 +++++++++++++++++++++++--
+ 2 files changed, 89 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
+index 0594eab666a9b..b278453cad6d4 100644
+--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
+@@ -2477,7 +2477,7 @@ static void gfx_v9_0_enable_gui_idle_interrupt(struct amdgpu_device *adev,
+ tmp = REG_SET_FIELD(tmp, CP_INT_CNTL_RING0, CNTX_BUSY_INT_ENABLE, enable ? 1 : 0);
+ tmp = REG_SET_FIELD(tmp, CP_INT_CNTL_RING0, CNTX_EMPTY_INT_ENABLE, enable ? 1 : 0);
+ tmp = REG_SET_FIELD(tmp, CP_INT_CNTL_RING0, CMP_BUSY_INT_ENABLE, enable ? 1 : 0);
+- if(adev->gfx.num_gfx_rings)
++ if (adev->gfx.num_gfx_rings)
+ tmp = REG_SET_FIELD(tmp, CP_INT_CNTL_RING0, GFX_IDLE_INT_ENABLE, enable ? 1 : 0);
+
+ WREG32_SOC15(GC, 0, mmCP_INT_CNTL_RING0, tmp);
+@@ -5772,17 +5772,59 @@ static void gfx_v9_0_set_compute_eop_interrupt_state(struct amdgpu_device *adev,
+ }
+ }
+
++static u32 gfx_v9_0_get_cpc_int_cntl(struct amdgpu_device *adev,
++ int me, int pipe)
++{
++ /*
++ * amdgpu controls only the first MEC. That's why this function only
++ * handles the setting of interrupts for this specific MEC. All other
++ * pipes' interrupts are set by amdkfd.
++ */
++ if (me != 1)
++ return 0;
++
++ switch (pipe) {
++ case 0:
++ return SOC15_REG_OFFSET(GC, 0, mmCP_ME1_PIPE0_INT_CNTL);
++ case 1:
++ return SOC15_REG_OFFSET(GC, 0, mmCP_ME1_PIPE1_INT_CNTL);
++ case 2:
++ return SOC15_REG_OFFSET(GC, 0, mmCP_ME1_PIPE2_INT_CNTL);
++ case 3:
++ return SOC15_REG_OFFSET(GC, 0, mmCP_ME1_PIPE3_INT_CNTL);
++ default:
++ return 0;
++ }
++}
++
+ static int gfx_v9_0_set_priv_reg_fault_state(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *source,
+ unsigned type,
+ enum amdgpu_interrupt_state state)
+ {
++ u32 cp_int_cntl_reg, cp_int_cntl;
++ int i, j;
++
+ switch (state) {
+ case AMDGPU_IRQ_STATE_DISABLE:
+ case AMDGPU_IRQ_STATE_ENABLE:
+ WREG32_FIELD15(GC, 0, CP_INT_CNTL_RING0,
+ PRIV_REG_INT_ENABLE,
+ state == AMDGPU_IRQ_STATE_ENABLE ? 1 : 0);
++ for (i = 0; i < adev->gfx.mec.num_mec; i++) {
++ for (j = 0; j < adev->gfx.mec.num_pipe_per_mec; j++) {
++ /* MECs start at 1 */
++ cp_int_cntl_reg = gfx_v9_0_get_cpc_int_cntl(adev, i + 1, j);
++
++ if (cp_int_cntl_reg) {
++ cp_int_cntl = RREG32_SOC15_IP(GC, cp_int_cntl_reg);
++ cp_int_cntl = REG_SET_FIELD(cp_int_cntl, CP_ME1_PIPE0_INT_CNTL,
++ PRIV_REG_INT_ENABLE,
++ state == AMDGPU_IRQ_STATE_ENABLE ? 1 : 0);
++ WREG32_SOC15_IP(GC, cp_int_cntl_reg, cp_int_cntl);
++ }
++ }
++ }
+ break;
+ default:
+ break;
+diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c
+index f5b9f443cfdd7..2564a003526ae 100644
+--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c
++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c
+@@ -2824,21 +2824,63 @@ static void gfx_v9_4_3_xcc_set_compute_eop_interrupt_state(
+ }
+ }
+
++static u32 gfx_v9_4_3_get_cpc_int_cntl(struct amdgpu_device *adev,
++ int xcc_id, int me, int pipe)
++{
++ /*
++ * amdgpu controls only the first MEC. That's why this function only
++ * handles the setting of interrupts for this specific MEC. All other
++ * pipes' interrupts are set by amdkfd.
++ */
++ if (me != 1)
++ return 0;
++
++ switch (pipe) {
++ case 0:
++ return SOC15_REG_OFFSET(GC, GET_INST(GC, xcc_id), regCP_ME1_PIPE0_INT_CNTL);
++ case 1:
++ return SOC15_REG_OFFSET(GC, GET_INST(GC, xcc_id), regCP_ME1_PIPE1_INT_CNTL);
++ case 2:
++ return SOC15_REG_OFFSET(GC, GET_INST(GC, xcc_id), regCP_ME1_PIPE2_INT_CNTL);
++ case 3:
++ return SOC15_REG_OFFSET(GC, GET_INST(GC, xcc_id), regCP_ME1_PIPE3_INT_CNTL);
++ default:
++ return 0;
++ }
++}
++
+ static int gfx_v9_4_3_set_priv_reg_fault_state(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *source,
+ unsigned type,
+ enum amdgpu_interrupt_state state)
+ {
+- int i, num_xcc;
++ u32 mec_int_cntl_reg, mec_int_cntl;
++ int i, j, k, num_xcc;
+
+ num_xcc = NUM_XCC(adev->gfx.xcc_mask);
+ switch (state) {
+ case AMDGPU_IRQ_STATE_DISABLE:
+ case AMDGPU_IRQ_STATE_ENABLE:
+- for (i = 0; i < num_xcc; i++)
++ for (i = 0; i < num_xcc; i++) {
+ WREG32_FIELD15_PREREG(GC, GET_INST(GC, i), CP_INT_CNTL_RING0,
+- PRIV_REG_INT_ENABLE,
+- state == AMDGPU_IRQ_STATE_ENABLE ? 1 : 0);
++ PRIV_REG_INT_ENABLE,
++ state == AMDGPU_IRQ_STATE_ENABLE ? 1 : 0);
++ for (j = 0; j < adev->gfx.mec.num_mec; j++) {
++ for (k = 0; k < adev->gfx.mec.num_pipe_per_mec; k++) {
++ /* MECs start at 1 */
++ mec_int_cntl_reg = gfx_v9_4_3_get_cpc_int_cntl(adev, i, j + 1, k);
++
++ if (mec_int_cntl_reg) {
++ mec_int_cntl = RREG32_XCC(mec_int_cntl_reg, i);
++ mec_int_cntl = REG_SET_FIELD(mec_int_cntl, CP_ME1_PIPE0_INT_CNTL,
++ PRIV_REG_INT_ENABLE,
++ state == AMDGPU_IRQ_STATE_ENABLE ?
++ 1 : 0);
++ WREG32_XCC(mec_int_cntl_reg, mec_int_cntl, i);
++ }
++ }
++ }
++ }
+ break;
+ default:
+ break;
+--
+2.43.0
+
--- /dev/null
+From 3716fb348cb9d34ac5f1b89456fa9d236a417a5d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 24 Jul 2024 18:20:57 -0400
+Subject: drm/amdgpu/gfx9: use rlc safe mode for soft recovery
+
+From: Alex Deucher <alexander.deucher@amd.com>
+
+[ Upstream commit 3ec2ad7c34c412bd9264cd1ff235d0812be90e82 ]
+
+Protect the MMIO access with safe mode.
+
+Acked-by: Vitaly Prosyak <vitaly.prosyak@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
+index b278453cad6d4..d8d3d2c93d8ee 100644
+--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
+@@ -5701,7 +5701,9 @@ static void gfx_v9_0_ring_soft_recovery(struct amdgpu_ring *ring, unsigned vmid)
+ value = REG_SET_FIELD(value, SQ_CMD, MODE, 0x01);
+ value = REG_SET_FIELD(value, SQ_CMD, CHECK_VMID, 1);
+ value = REG_SET_FIELD(value, SQ_CMD, VM_ID, vmid);
++ amdgpu_gfx_rlc_enter_safe_mode(adev, 0);
+ WREG32_SOC15(GC, 0, mmSQ_CMD, value);
++ amdgpu_gfx_rlc_exit_safe_mode(adev, 0);
+ }
+
+ static void gfx_v9_0_set_gfx_eop_interrupt_state(struct amdgpu_device *adev,
+--
+2.43.0
+
--- /dev/null
+From 05572408f8d9c5e60c1df8fb8cf409c825533f62 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 14 Jul 2024 11:11:05 -0400
+Subject: drm/amdkfd: amdkfd_free_gtt_mem clear the correct pointer
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Philip Yang <Philip.Yang@amd.com>
+
+[ Upstream commit c86ad39140bbcb9dc75a10046c2221f657e8083b ]
+
+Pass pointer reference to amdgpu_bo_unref to clear the correct pointer,
+otherwise amdgpu_bo_unref clear the local variable, the original pointer
+not set to NULL, this could cause use-after-free bug.
+
+Signed-off-by: Philip Yang <Philip.Yang@amd.com>
+Reviewed-by: Felix Kuehling <felix.kuehling@amd.com>
+Acked-by: Christian König <christian.koenig@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 14 +++++++-------
+ drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h | 2 +-
+ drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 2 +-
+ drivers/gpu/drm/amd/amdkfd/kfd_device.c | 4 ++--
+ .../gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 2 +-
+ drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c | 2 +-
+ drivers/gpu/drm/amd/amdkfd/kfd_process.c | 2 +-
+ .../gpu/drm/amd/amdkfd/kfd_process_queue_manager.c | 4 ++--
+ 8 files changed, 16 insertions(+), 16 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
+index e3738d4172458..26ecca3e8e900 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
+@@ -360,15 +360,15 @@ int amdgpu_amdkfd_alloc_gtt_mem(struct amdgpu_device *adev, size_t size,
+ return r;
+ }
+
+-void amdgpu_amdkfd_free_gtt_mem(struct amdgpu_device *adev, void *mem_obj)
++void amdgpu_amdkfd_free_gtt_mem(struct amdgpu_device *adev, void **mem_obj)
+ {
+- struct amdgpu_bo *bo = (struct amdgpu_bo *) mem_obj;
++ struct amdgpu_bo **bo = (struct amdgpu_bo **) mem_obj;
+
+- amdgpu_bo_reserve(bo, true);
+- amdgpu_bo_kunmap(bo);
+- amdgpu_bo_unpin(bo);
+- amdgpu_bo_unreserve(bo);
+- amdgpu_bo_unref(&(bo));
++ amdgpu_bo_reserve(*bo, true);
++ amdgpu_bo_kunmap(*bo);
++ amdgpu_bo_unpin(*bo);
++ amdgpu_bo_unreserve(*bo);
++ amdgpu_bo_unref(bo);
+ }
+
+ int amdgpu_amdkfd_alloc_gws(struct amdgpu_device *adev, size_t size,
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
+index 1de021ebdd467..ee16d8a9ba559 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
+@@ -233,7 +233,7 @@ int amdgpu_amdkfd_bo_validate_and_fence(struct amdgpu_bo *bo,
+ int amdgpu_amdkfd_alloc_gtt_mem(struct amdgpu_device *adev, size_t size,
+ void **mem_obj, uint64_t *gpu_addr,
+ void **cpu_ptr, bool mqd_gfx9);
+-void amdgpu_amdkfd_free_gtt_mem(struct amdgpu_device *adev, void *mem_obj);
++void amdgpu_amdkfd_free_gtt_mem(struct amdgpu_device *adev, void **mem_obj);
+ int amdgpu_amdkfd_alloc_gws(struct amdgpu_device *adev, size_t size,
+ void **mem_obj);
+ void amdgpu_amdkfd_free_gws(struct amdgpu_device *adev, void *mem_obj);
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
+index fdf171ad4a3c6..4f260adce8c46 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
+@@ -423,7 +423,7 @@ static int kfd_ioctl_create_queue(struct file *filep, struct kfd_process *p,
+
+ err_create_queue:
+ if (wptr_bo)
+- amdgpu_amdkfd_free_gtt_mem(dev->adev, wptr_bo);
++ amdgpu_amdkfd_free_gtt_mem(dev->adev, (void **)&wptr_bo);
+ err_wptr_map_gart:
+ err_bind_process:
+ err_pdd:
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
+index afc57df421cd9..3343079f28c90 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
+@@ -863,7 +863,7 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd,
+ kfd_doorbell_error:
+ kfd_gtt_sa_fini(kfd);
+ kfd_gtt_sa_init_error:
+- amdgpu_amdkfd_free_gtt_mem(kfd->adev, kfd->gtt_mem);
++ amdgpu_amdkfd_free_gtt_mem(kfd->adev, &kfd->gtt_mem);
+ alloc_gtt_mem_failure:
+ dev_err(kfd_device,
+ "device %x:%x NOT added due to errors\n",
+@@ -881,7 +881,7 @@ void kgd2kfd_device_exit(struct kfd_dev *kfd)
+ kfd_doorbell_fini(kfd);
+ ida_destroy(&kfd->doorbell_ida);
+ kfd_gtt_sa_fini(kfd);
+- amdgpu_amdkfd_free_gtt_mem(kfd->adev, kfd->gtt_mem);
++ amdgpu_amdkfd_free_gtt_mem(kfd->adev, &kfd->gtt_mem);
+ }
+
+ kfree(kfd);
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
+index c08b6ee252898..dbef9eac2694f 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
+@@ -2633,7 +2633,7 @@ static void deallocate_hiq_sdma_mqd(struct kfd_node *dev,
+ {
+ WARN(!mqd, "No hiq sdma mqd trunk to free");
+
+- amdgpu_amdkfd_free_gtt_mem(dev->adev, mqd->gtt_mem);
++ amdgpu_amdkfd_free_gtt_mem(dev->adev, &mqd->gtt_mem);
+ }
+
+ void device_queue_manager_uninit(struct device_queue_manager *dqm)
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c
+index 8746a61a852dc..d501fd2222dc3 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c
+@@ -223,7 +223,7 @@ void kfd_free_mqd_cp(struct mqd_manager *mm, void *mqd,
+ struct kfd_mem_obj *mqd_mem_obj)
+ {
+ if (mqd_mem_obj->gtt_mem) {
+- amdgpu_amdkfd_free_gtt_mem(mm->dev->adev, mqd_mem_obj->gtt_mem);
++ amdgpu_amdkfd_free_gtt_mem(mm->dev->adev, &mqd_mem_obj->gtt_mem);
+ kfree(mqd_mem_obj);
+ } else {
+ kfd_gtt_sa_free(mm->dev, mqd_mem_obj);
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
+index 451bb058cc620..66150ea8e64d8 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
+@@ -1048,7 +1048,7 @@ static void kfd_process_destroy_pdds(struct kfd_process *p)
+
+ if (pdd->dev->kfd->shared_resources.enable_mes)
+ amdgpu_amdkfd_free_gtt_mem(pdd->dev->adev,
+- pdd->proc_ctx_bo);
++ &pdd->proc_ctx_bo);
+ /*
+ * before destroying pdd, make sure to report availability
+ * for auto suspend
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
+index a5bdc3258ae54..c97b4fc44859d 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
+@@ -201,9 +201,9 @@ static void pqm_clean_queue_resource(struct process_queue_manager *pqm,
+ }
+
+ if (dev->kfd->shared_resources.enable_mes) {
+- amdgpu_amdkfd_free_gtt_mem(dev->adev, pqn->q->gang_ctx_bo);
++ amdgpu_amdkfd_free_gtt_mem(dev->adev, &pqn->q->gang_ctx_bo);
+ if (pqn->q->wptr_bo)
+- amdgpu_amdkfd_free_gtt_mem(dev->adev, pqn->q->wptr_bo);
++ amdgpu_amdkfd_free_gtt_mem(dev->adev, (void **)&pqn->q->wptr_bo);
+ }
+ }
+
+--
+2.43.0
+
--- /dev/null
+From 67598afe98001e0008aefbc9727d2926b33a7209 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 20 Aug 2024 13:56:32 +0800
+Subject: drm/amdkfd: Check int source id for utcl2 poison event
+
+From: Hawking Zhang <Hawking.Zhang@amd.com>
+
+[ Upstream commit db6341a9168d2a24ded526277eeab29724d76e9d ]
+
+Traditional utcl2 fault_status polling does not
+work in SRIOV environment. The polling of fault
+status register from guest side will be dropped
+by hardware.
+
+Driver should switch to check utcl2 interrupt
+source id to identify utcl2 poison event. It is
+set to 1 when poisoned data interrupts are
+signaled.
+
+v2: drop the unused local variable (Tao)
+
+Signed-off-by: Hawking Zhang <Hawking.Zhang@amd.com>
+Reviewed-by: Tao Zhou <tao.zhou1@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../gpu/drm/amd/amdkfd/kfd_int_process_v9.c | 18 +-----------------
+ drivers/gpu/drm/amd/amdkfd/soc15_int.h | 1 +
+ 2 files changed, 2 insertions(+), 17 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c
+index 78dde62fb04ad..c282f5253c445 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c
+@@ -414,25 +414,9 @@ static void event_interrupt_wq_v9(struct kfd_node *dev,
+ client_id == SOC15_IH_CLIENTID_UTCL2) {
+ struct kfd_vm_fault_info info = {0};
+ uint16_t ring_id = SOC15_RING_ID_FROM_IH_ENTRY(ih_ring_entry);
+- uint32_t node_id = SOC15_NODEID_FROM_IH_ENTRY(ih_ring_entry);
+- uint32_t vmid_type = SOC15_VMID_TYPE_FROM_IH_ENTRY(ih_ring_entry);
+- int hub_inst = 0;
+ struct kfd_hsa_memory_exception_data exception_data;
+
+- /* gfxhub */
+- if (!vmid_type && dev->adev->gfx.funcs->ih_node_to_logical_xcc) {
+- hub_inst = dev->adev->gfx.funcs->ih_node_to_logical_xcc(dev->adev,
+- node_id);
+- if (hub_inst < 0)
+- hub_inst = 0;
+- }
+-
+- /* mmhub */
+- if (vmid_type && client_id == SOC15_IH_CLIENTID_VMC)
+- hub_inst = node_id / 4;
+-
+- if (amdgpu_amdkfd_ras_query_utcl2_poison_status(dev->adev,
+- hub_inst, vmid_type)) {
++ if (source_id == SOC15_INTSRC_VMC_UTCL2_POISON) {
+ event_interrupt_poison_consumption_v9(dev, pasid, client_id);
+ return;
+ }
+diff --git a/drivers/gpu/drm/amd/amdkfd/soc15_int.h b/drivers/gpu/drm/amd/amdkfd/soc15_int.h
+index 10138676f27fd..e5c0205f26181 100644
+--- a/drivers/gpu/drm/amd/amdkfd/soc15_int.h
++++ b/drivers/gpu/drm/amd/amdkfd/soc15_int.h
+@@ -29,6 +29,7 @@
+ #define SOC15_INTSRC_CP_BAD_OPCODE 183
+ #define SOC15_INTSRC_SQ_INTERRUPT_MSG 239
+ #define SOC15_INTSRC_VMC_FAULT 0
++#define SOC15_INTSRC_VMC_UTCL2_POISON 1
+ #define SOC15_INTSRC_SDMA_TRAP 224
+ #define SOC15_INTSRC_SDMA_ECC 220
+ #define SOC21_INTSRC_SDMA_TRAP 49
+--
+2.43.0
+
--- /dev/null
+From 416b2b78a2d2b5ec7daf9c298860cdfd931a5145 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 6 Sep 2024 11:29:55 +0800
+Subject: drm/amdkfd: Fix resource leak in criu restore queue
+
+From: Jesse Zhang <jesse.zhang@amd.com>
+
+[ Upstream commit aa47fe8d3595365a935921a90d00bc33ee374728 ]
+
+To avoid memory leaks, release q_extra_data when exiting the restore queue.
+v2: Correct the proto (Alex)
+
+Signed-off-by: Jesse Zhang <jesse.zhang@amd.com>
+Reviewed-by: Tim Huang <tim.huang@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
+index c97b4fc44859d..db2b71f7226f4 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
+@@ -984,6 +984,7 @@ int kfd_criu_restore_queue(struct kfd_process *p,
+ pr_debug("Queue id %d was restored successfully\n", queue_id);
+
+ kfree(q_data);
++ kfree(q_extra_data);
+
+ return ret;
+ }
+--
+2.43.0
+
--- /dev/null
+From dbfe4ad3ff1f05785d9f5662d3dc94c6ae7d14fc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 9 Jul 2024 13:15:40 +0200
+Subject: drm/msm/adreno: Assign msm_gpu->pdev earlier to avoid nullptrs
+
+From: Konrad Dybcio <konrad.dybcio@linaro.org>
+
+[ Upstream commit 16007768551d5bfe53426645401435ca8d2ef54f ]
+
+There are some cases, such as the one uncovered by Commit 46d4efcccc68
+("drm/msm/a6xx: Avoid a nullptr dereference when speedbin setting fails")
+where
+
+msm_gpu_cleanup() : platform_set_drvdata(gpu->pdev, NULL);
+
+is called on gpu->pdev == NULL, as the GPU device has not been fully
+initialized yet.
+
+Turns out that there's more than just the aforementioned path that
+causes this to happen (e.g. the case when there's speedbin data in the
+catalog, but opp-supported-hw is missing in DT).
+
+Assigning msm_gpu->pdev earlier seems like the least painful solution
+to this, therefore do so.
+
+Signed-off-by: Konrad Dybcio <konrad.dybcio@linaro.org>
+Patchwork: https://patchwork.freedesktop.org/patch/602742/
+Signed-off-by: Rob Clark <robdclark@chromium.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/msm/adreno/adreno_gpu.c | 1 +
+ drivers/gpu/drm/msm/msm_gpu.c | 1 -
+ 2 files changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+index d5d9361e11aa5..8e8f55225e1ea 100644
+--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
++++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+@@ -1079,6 +1079,7 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
+ adreno_gpu->chip_id = config->chip_id;
+
+ gpu->allow_relocs = config->info->family < ADRENO_6XX_GEN1;
++ gpu->pdev = pdev;
+
+ /* Only handle the core clock when GMU is not in use (or is absent). */
+ if (adreno_has_gmu_wrapper(adreno_gpu) ||
+diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
+index cd185b9636d26..56b6de049bd7b 100644
+--- a/drivers/gpu/drm/msm/msm_gpu.c
++++ b/drivers/gpu/drm/msm/msm_gpu.c
+@@ -929,7 +929,6 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
+ if (IS_ERR(gpu->gpu_cx))
+ gpu->gpu_cx = NULL;
+
+- gpu->pdev = pdev;
+ platform_set_drvdata(pdev, &gpu->adreno_smmu);
+
+ msm_devfreq_init(gpu);
+--
+2.43.0
+
--- /dev/null
+From 168e280227eb6a7ce3b4c50d2b0efc343091f448 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 1 Aug 2024 08:41:17 -0700
+Subject: drm/printer: Allow NULL data in devcoredump printer
+
+From: Matthew Brost <matthew.brost@intel.com>
+
+[ Upstream commit 53369581dc0c68a5700ed51e1660f44c4b2bb524 ]
+
+We want to determine the size of the devcoredump before writing it out.
+To that end, we will run the devcoredump printer with NULL data to get
+the size, alloc data based on the generated offset, then run the
+devcorecump again with a valid data pointer to print. This necessitates
+not writing data to the data pointer on the initial pass, when it is
+NULL.
+
+v5:
+ - Better commit message (Jonathan)
+ - Add kerenl doc with examples (Jani)
+
+Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
+Acked-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
+Signed-off-by: Matthew Brost <matthew.brost@intel.com>
+Reviewed-by: Jonathan Cavitt <jonathan.cavitt@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20240801154118.2547543-3-matthew.brost@intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/drm_print.c | 13 +++++----
+ include/drm/drm_print.h | 54 ++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 61 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/gpu/drm/drm_print.c b/drivers/gpu/drm/drm_print.c
+index cf2efb44722c9..1d122d4de70ec 100644
+--- a/drivers/gpu/drm/drm_print.c
++++ b/drivers/gpu/drm/drm_print.c
+@@ -100,8 +100,9 @@ void __drm_puts_coredump(struct drm_printer *p, const char *str)
+ copy = iterator->remain;
+
+ /* Copy out the bit of the string that we need */
+- memcpy(iterator->data,
+- str + (iterator->start - iterator->offset), copy);
++ if (iterator->data)
++ memcpy(iterator->data,
++ str + (iterator->start - iterator->offset), copy);
+
+ iterator->offset = iterator->start + copy;
+ iterator->remain -= copy;
+@@ -110,7 +111,8 @@ void __drm_puts_coredump(struct drm_printer *p, const char *str)
+
+ len = min_t(ssize_t, strlen(str), iterator->remain);
+
+- memcpy(iterator->data + pos, str, len);
++ if (iterator->data)
++ memcpy(iterator->data + pos, str, len);
+
+ iterator->offset += len;
+ iterator->remain -= len;
+@@ -140,8 +142,9 @@ void __drm_printfn_coredump(struct drm_printer *p, struct va_format *vaf)
+ if ((iterator->offset >= iterator->start) && (len < iterator->remain)) {
+ ssize_t pos = iterator->offset - iterator->start;
+
+- snprintf(((char *) iterator->data) + pos,
+- iterator->remain, "%pV", vaf);
++ if (iterator->data)
++ snprintf(((char *) iterator->data) + pos,
++ iterator->remain, "%pV", vaf);
+
+ iterator->offset += len;
+ iterator->remain -= len;
+diff --git a/include/drm/drm_print.h b/include/drm/drm_print.h
+index 089950ad8681a..8fad7d09bedae 100644
+--- a/include/drm/drm_print.h
++++ b/include/drm/drm_print.h
+@@ -220,7 +220,8 @@ drm_vprintf(struct drm_printer *p, const char *fmt, va_list *va)
+
+ /**
+ * struct drm_print_iterator - local struct used with drm_printer_coredump
+- * @data: Pointer to the devcoredump output buffer
++ * @data: Pointer to the devcoredump output buffer, can be NULL if using
++ * drm_printer_coredump to determine size of devcoredump
+ * @start: The offset within the buffer to start writing
+ * @remain: The number of bytes to write for this iteration
+ */
+@@ -265,6 +266,57 @@ struct drm_print_iterator {
+ * coredump_read, ...)
+ * }
+ *
++ * The above example has a time complexity of O(N^2), where N is the size of the
++ * devcoredump. This is acceptable for small devcoredumps but scales poorly for
++ * larger ones.
++ *
++ * Another use case for drm_coredump_printer is to capture the devcoredump into
++ * a saved buffer before the dev_coredump() callback. This involves two passes:
++ * one to determine the size of the devcoredump and another to print it to a
++ * buffer. Then, in dev_coredump(), copy from the saved buffer into the
++ * devcoredump read buffer.
++ *
++ * For example::
++ *
++ * char *devcoredump_saved_buffer;
++ *
++ * ssize_t __coredump_print(char *buffer, ssize_t count, ...)
++ * {
++ * struct drm_print_iterator iter;
++ * struct drm_printer p;
++ *
++ * iter.data = buffer;
++ * iter.start = 0;
++ * iter.remain = count;
++ *
++ * p = drm_coredump_printer(&iter);
++ *
++ * drm_printf(p, "foo=%d\n", foo);
++ * ...
++ * return count - iter.remain;
++ * }
++ *
++ * void coredump_print(...)
++ * {
++ * ssize_t count;
++ *
++ * count = __coredump_print(NULL, INT_MAX, ...);
++ * devcoredump_saved_buffer = kvmalloc(count, GFP_KERNEL);
++ * __coredump_print(devcoredump_saved_buffer, count, ...);
++ * }
++ *
++ * void coredump_read(char *buffer, loff_t offset, size_t count,
++ * void *data, size_t datalen)
++ * {
++ * ...
++ * memcpy(buffer, devcoredump_saved_buffer + offset, count);
++ * ...
++ * }
++ *
++ * The above example has a time complexity of O(N*2), where N is the size of the
++ * devcoredump. This scales better than the previous example for larger
++ * devcoredumps.
++ *
+ * RETURNS:
+ * The &drm_printer object
+ */
+--
+2.43.0
+
--- /dev/null
+From 638094311e34f49390d48489255ba890335e4fad Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 30 Jul 2024 17:58:12 +0200
+Subject: drm/radeon/r100: Handle unknown family in r100_cp_init_microcode()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Geert Uytterhoeven <geert+renesas@glider.be>
+
+[ Upstream commit c6dbab46324b1742b50dc2fb5c1fee2c28129439 ]
+
+With -Werror:
+
+ In function ‘r100_cp_init_microcode’,
+ inlined from ‘r100_cp_init’ at drivers/gpu/drm/radeon/r100.c:1136:7:
+ include/linux/printk.h:465:44: error: ‘%s’ directive argument is null [-Werror=format-overflow=]
+ 465 | #define printk(fmt, ...) printk_index_wrap(_printk, fmt, ##__VA_ARGS__)
+ | ^
+ include/linux/printk.h:437:17: note: in definition of macro ‘printk_index_wrap’
+ 437 | _p_func(_fmt, ##__VA_ARGS__); \
+ | ^~~~~~~
+ include/linux/printk.h:508:9: note: in expansion of macro ‘printk’
+ 508 | printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
+ | ^~~~~~
+ drivers/gpu/drm/radeon/r100.c:1062:17: note: in expansion of macro ‘pr_err’
+ 1062 | pr_err("radeon_cp: Failed to load firmware \"%s\"\n", fw_name);
+ | ^~~~~~
+
+Fix this by converting the if/else if/... construct into a proper
+switch() statement with a default to handle the error case.
+
+As a bonus, the generated code is ca. 100 bytes smaller (with gcc 11.4.0
+targeting arm32).
+
+Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/radeon/r100.c | 70 ++++++++++++++++++++++-------------
+ 1 file changed, 45 insertions(+), 25 deletions(-)
+
+diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
+index 0b1e19345f43a..bfd42e3e161e9 100644
+--- a/drivers/gpu/drm/radeon/r100.c
++++ b/drivers/gpu/drm/radeon/r100.c
+@@ -1016,45 +1016,65 @@ static int r100_cp_init_microcode(struct radeon_device *rdev)
+
+ DRM_DEBUG_KMS("\n");
+
+- if ((rdev->family == CHIP_R100) || (rdev->family == CHIP_RV100) ||
+- (rdev->family == CHIP_RV200) || (rdev->family == CHIP_RS100) ||
+- (rdev->family == CHIP_RS200)) {
++ switch (rdev->family) {
++ case CHIP_R100:
++ case CHIP_RV100:
++ case CHIP_RV200:
++ case CHIP_RS100:
++ case CHIP_RS200:
+ DRM_INFO("Loading R100 Microcode\n");
+ fw_name = FIRMWARE_R100;
+- } else if ((rdev->family == CHIP_R200) ||
+- (rdev->family == CHIP_RV250) ||
+- (rdev->family == CHIP_RV280) ||
+- (rdev->family == CHIP_RS300)) {
++ break;
++
++ case CHIP_R200:
++ case CHIP_RV250:
++ case CHIP_RV280:
++ case CHIP_RS300:
+ DRM_INFO("Loading R200 Microcode\n");
+ fw_name = FIRMWARE_R200;
+- } else if ((rdev->family == CHIP_R300) ||
+- (rdev->family == CHIP_R350) ||
+- (rdev->family == CHIP_RV350) ||
+- (rdev->family == CHIP_RV380) ||
+- (rdev->family == CHIP_RS400) ||
+- (rdev->family == CHIP_RS480)) {
++ break;
++
++ case CHIP_R300:
++ case CHIP_R350:
++ case CHIP_RV350:
++ case CHIP_RV380:
++ case CHIP_RS400:
++ case CHIP_RS480:
+ DRM_INFO("Loading R300 Microcode\n");
+ fw_name = FIRMWARE_R300;
+- } else if ((rdev->family == CHIP_R420) ||
+- (rdev->family == CHIP_R423) ||
+- (rdev->family == CHIP_RV410)) {
++ break;
++
++ case CHIP_R420:
++ case CHIP_R423:
++ case CHIP_RV410:
+ DRM_INFO("Loading R400 Microcode\n");
+ fw_name = FIRMWARE_R420;
+- } else if ((rdev->family == CHIP_RS690) ||
+- (rdev->family == CHIP_RS740)) {
++ break;
++
++ case CHIP_RS690:
++ case CHIP_RS740:
+ DRM_INFO("Loading RS690/RS740 Microcode\n");
+ fw_name = FIRMWARE_RS690;
+- } else if (rdev->family == CHIP_RS600) {
++ break;
++
++ case CHIP_RS600:
+ DRM_INFO("Loading RS600 Microcode\n");
+ fw_name = FIRMWARE_RS600;
+- } else if ((rdev->family == CHIP_RV515) ||
+- (rdev->family == CHIP_R520) ||
+- (rdev->family == CHIP_RV530) ||
+- (rdev->family == CHIP_R580) ||
+- (rdev->family == CHIP_RV560) ||
+- (rdev->family == CHIP_RV570)) {
++ break;
++
++ case CHIP_RV515:
++ case CHIP_R520:
++ case CHIP_RV530:
++ case CHIP_R580:
++ case CHIP_RV560:
++ case CHIP_RV570:
+ DRM_INFO("Loading R500 Microcode\n");
+ fw_name = FIRMWARE_R520;
++ break;
++
++ default:
++ DRM_ERROR("Unsupported Radeon family %u\n", rdev->family);
++ return -EINVAL;
+ }
+
+ err = request_firmware(&rdev->me_fw, fw_name, rdev->dev);
+--
+2.43.0
+
--- /dev/null
+From 42aa6221cd6f0d02ca188473a9238d6854f5b0d7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 16 Feb 2024 15:50:40 +0300
+Subject: drm/stm: Avoid use-after-free issues with crtc and plane
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Katya Orlova <e.orlova@ispras.ru>
+
+[ Upstream commit 19dd9780b7ac673be95bf6fd6892a184c9db611f ]
+
+ltdc_load() calls functions drm_crtc_init_with_planes(),
+drm_universal_plane_init() and drm_encoder_init(). These functions
+should not be called with parameters allocated with devm_kzalloc()
+to avoid use-after-free issues [1].
+
+Use allocations managed by the DRM framework.
+
+Found by Linux Verification Center (linuxtesting.org).
+
+[1]
+https://lore.kernel.org/lkml/u366i76e3qhh3ra5oxrtngjtm2u5lterkekcz6y2jkndhuxzli@diujon4h7qwb/
+
+Signed-off-by: Katya Orlova <e.orlova@ispras.ru>
+Acked-by: Raphaël Gallais-Pou <raphael.gallais-pou@foss.st.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20240216125040.8968-1-e.orlova@ispras.ru
+Signed-off-by: Raphael Gallais-Pou <raphael.gallais-pou@foss.st.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/stm/drv.c | 3 +-
+ drivers/gpu/drm/stm/ltdc.c | 73 ++++++++++----------------------------
+ 2 files changed, 20 insertions(+), 56 deletions(-)
+
+diff --git a/drivers/gpu/drm/stm/drv.c b/drivers/gpu/drm/stm/drv.c
+index 4d2db079ad4ff..e1232f74dfa53 100644
+--- a/drivers/gpu/drm/stm/drv.c
++++ b/drivers/gpu/drm/stm/drv.c
+@@ -25,6 +25,7 @@
+ #include <drm/drm_module.h>
+ #include <drm/drm_probe_helper.h>
+ #include <drm/drm_vblank.h>
++#include <drm/drm_managed.h>
+
+ #include "ltdc.h"
+
+@@ -75,7 +76,7 @@ static int drv_load(struct drm_device *ddev)
+
+ DRM_DEBUG("%s\n", __func__);
+
+- ldev = devm_kzalloc(ddev->dev, sizeof(*ldev), GFP_KERNEL);
++ ldev = drmm_kzalloc(ddev, sizeof(*ldev), GFP_KERNEL);
+ if (!ldev)
+ return -ENOMEM;
+
+diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c
+index 5aec1e58c968c..056642d12265c 100644
+--- a/drivers/gpu/drm/stm/ltdc.c
++++ b/drivers/gpu/drm/stm/ltdc.c
+@@ -36,6 +36,7 @@
+ #include <drm/drm_probe_helper.h>
+ #include <drm/drm_simple_kms_helper.h>
+ #include <drm/drm_vblank.h>
++#include <drm/drm_managed.h>
+
+ #include <video/videomode.h>
+
+@@ -1199,7 +1200,6 @@ static void ltdc_crtc_atomic_print_state(struct drm_printer *p,
+ }
+
+ static const struct drm_crtc_funcs ltdc_crtc_funcs = {
+- .destroy = drm_crtc_cleanup,
+ .set_config = drm_atomic_helper_set_config,
+ .page_flip = drm_atomic_helper_page_flip,
+ .reset = drm_atomic_helper_crtc_reset,
+@@ -1212,7 +1212,6 @@ static const struct drm_crtc_funcs ltdc_crtc_funcs = {
+ };
+
+ static const struct drm_crtc_funcs ltdc_crtc_with_crc_support_funcs = {
+- .destroy = drm_crtc_cleanup,
+ .set_config = drm_atomic_helper_set_config,
+ .page_flip = drm_atomic_helper_page_flip,
+ .reset = drm_atomic_helper_crtc_reset,
+@@ -1545,7 +1544,6 @@ static void ltdc_plane_atomic_print_state(struct drm_printer *p,
+ static const struct drm_plane_funcs ltdc_plane_funcs = {
+ .update_plane = drm_atomic_helper_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
+- .destroy = drm_plane_cleanup,
+ .reset = drm_atomic_helper_plane_reset,
+ .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+@@ -1572,7 +1570,6 @@ static struct drm_plane *ltdc_plane_create(struct drm_device *ddev,
+ const u64 *modifiers = ltdc_format_modifiers;
+ u32 lofs = index * LAY_OFS;
+ u32 val;
+- int ret;
+
+ /* Allocate the biggest size according to supported color formats */
+ formats = devm_kzalloc(dev, (ldev->caps.pix_fmt_nb +
+@@ -1615,14 +1612,10 @@ static struct drm_plane *ltdc_plane_create(struct drm_device *ddev,
+ }
+ }
+
+- plane = devm_kzalloc(dev, sizeof(*plane), GFP_KERNEL);
+- if (!plane)
+- return NULL;
+-
+- ret = drm_universal_plane_init(ddev, plane, possible_crtcs,
+- <dc_plane_funcs, formats, nb_fmt,
+- modifiers, type, NULL);
+- if (ret < 0)
++ plane = drmm_universal_plane_alloc(ddev, struct drm_plane, dev,
++ possible_crtcs, <dc_plane_funcs, formats,
++ nb_fmt, modifiers, type, NULL);
++ if (IS_ERR(plane))
+ return NULL;
+
+ if (ldev->caps.ycbcr_input) {
+@@ -1645,15 +1638,6 @@ static struct drm_plane *ltdc_plane_create(struct drm_device *ddev,
+ return plane;
+ }
+
+-static void ltdc_plane_destroy_all(struct drm_device *ddev)
+-{
+- struct drm_plane *plane, *plane_temp;
+-
+- list_for_each_entry_safe(plane, plane_temp,
+- &ddev->mode_config.plane_list, head)
+- drm_plane_cleanup(plane);
+-}
+-
+ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc)
+ {
+ struct ltdc_device *ldev = ddev->dev_private;
+@@ -1679,14 +1663,14 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc)
+
+ /* Init CRTC according to its hardware features */
+ if (ldev->caps.crc)
+- ret = drm_crtc_init_with_planes(ddev, crtc, primary, NULL,
+- <dc_crtc_with_crc_support_funcs, NULL);
++ ret = drmm_crtc_init_with_planes(ddev, crtc, primary, NULL,
++ <dc_crtc_with_crc_support_funcs, NULL);
+ else
+- ret = drm_crtc_init_with_planes(ddev, crtc, primary, NULL,
+- <dc_crtc_funcs, NULL);
++ ret = drmm_crtc_init_with_planes(ddev, crtc, primary, NULL,
++ <dc_crtc_funcs, NULL);
+ if (ret) {
+ DRM_ERROR("Can not initialize CRTC\n");
+- goto cleanup;
++ return ret;
+ }
+
+ drm_crtc_helper_add(crtc, <dc_crtc_helper_funcs);
+@@ -1700,9 +1684,8 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc)
+ for (i = 1; i < ldev->caps.nb_layers; i++) {
+ overlay = ltdc_plane_create(ddev, DRM_PLANE_TYPE_OVERLAY, i);
+ if (!overlay) {
+- ret = -ENOMEM;
+ DRM_ERROR("Can not create overlay plane %d\n", i);
+- goto cleanup;
++ return -ENOMEM;
+ }
+ if (ldev->caps.dynamic_zorder)
+ drm_plane_create_zpos_property(overlay, i, 0, ldev->caps.nb_layers - 1);
+@@ -1715,10 +1698,6 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc)
+ }
+
+ return 0;
+-
+-cleanup:
+- ltdc_plane_destroy_all(ddev);
+- return ret;
+ }
+
+ static void ltdc_encoder_disable(struct drm_encoder *encoder)
+@@ -1778,23 +1757,19 @@ static int ltdc_encoder_init(struct drm_device *ddev, struct drm_bridge *bridge)
+ struct drm_encoder *encoder;
+ int ret;
+
+- encoder = devm_kzalloc(ddev->dev, sizeof(*encoder), GFP_KERNEL);
+- if (!encoder)
+- return -ENOMEM;
++ encoder = drmm_simple_encoder_alloc(ddev, struct drm_encoder, dev,
++ DRM_MODE_ENCODER_DPI);
++ if (IS_ERR(encoder))
++ return PTR_ERR(encoder);
+
+ encoder->possible_crtcs = CRTC_MASK;
+ encoder->possible_clones = 0; /* No cloning support */
+
+- drm_simple_encoder_init(ddev, encoder, DRM_MODE_ENCODER_DPI);
+-
+ drm_encoder_helper_add(encoder, <dc_encoder_helper_funcs);
+
+ ret = drm_bridge_attach(encoder, bridge, NULL, 0);
+- if (ret) {
+- if (ret != -EPROBE_DEFER)
+- drm_encoder_cleanup(encoder);
++ if (ret)
+ return ret;
+- }
+
+ DRM_DEBUG_DRIVER("Bridge encoder:%d created\n", encoder->base.id);
+
+@@ -1964,8 +1939,7 @@ int ltdc_load(struct drm_device *ddev)
+ goto err;
+
+ if (panel) {
+- bridge = drm_panel_bridge_add_typed(panel,
+- DRM_MODE_CONNECTOR_DPI);
++ bridge = drmm_panel_bridge_add(ddev, panel);
+ if (IS_ERR(bridge)) {
+ DRM_ERROR("panel-bridge endpoint %d\n", i);
+ ret = PTR_ERR(bridge);
+@@ -2047,7 +2021,7 @@ int ltdc_load(struct drm_device *ddev)
+ }
+ }
+
+- crtc = devm_kzalloc(dev, sizeof(*crtc), GFP_KERNEL);
++ crtc = drmm_kzalloc(ddev, sizeof(*crtc), GFP_KERNEL);
+ if (!crtc) {
+ DRM_ERROR("Failed to allocate crtc\n");
+ ret = -ENOMEM;
+@@ -2074,9 +2048,6 @@ int ltdc_load(struct drm_device *ddev)
+
+ return 0;
+ err:
+- for (i = 0; i < nb_endpoints; i++)
+- drm_of_panel_bridge_remove(ddev->dev->of_node, 0, i);
+-
+ clk_disable_unprepare(ldev->pixel_clk);
+
+ return ret;
+@@ -2084,16 +2055,8 @@ int ltdc_load(struct drm_device *ddev)
+
+ void ltdc_unload(struct drm_device *ddev)
+ {
+- struct device *dev = ddev->dev;
+- int nb_endpoints, i;
+-
+ DRM_DEBUG_DRIVER("\n");
+
+- nb_endpoints = of_graph_get_endpoint_count(dev->of_node);
+-
+- for (i = 0; i < nb_endpoints; i++)
+- drm_of_panel_bridge_remove(ddev->dev->of_node, 0, i);
+-
+ pm_runtime_disable(ddev->dev);
+ }
+
+--
+2.43.0
+
--- /dev/null
+From 17786c82acde9ca57fb5ab0b229c524acf894393 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 12 Jul 2024 15:13:44 +0200
+Subject: drm/stm: ltdc: reset plane transparency after plane disable
+
+From: Yannick Fertre <yannick.fertre@foss.st.com>
+
+[ Upstream commit 02fa62d41c8abff945bae5bfc3ddcf4721496aca ]
+
+The plane's opacity should be reseted while the plane
+is disabled. It prevents from seeing a possible global
+or layer background color set earlier.
+
+Signed-off-by: Yannick Fertre <yannick.fertre@foss.st.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20240712131344.98113-1-yannick.fertre@foss.st.com
+Signed-off-by: Raphael Gallais-Pou <raphael.gallais-pou@foss.st.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/stm/ltdc.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c
+index 056642d12265c..0832b749b66e7 100644
+--- a/drivers/gpu/drm/stm/ltdc.c
++++ b/drivers/gpu/drm/stm/ltdc.c
+@@ -1513,6 +1513,9 @@ static void ltdc_plane_atomic_disable(struct drm_plane *plane,
+ /* Disable layer */
+ regmap_write_bits(ldev->regmap, LTDC_L1CR + lofs, LXCR_LEN | LXCR_CLUTEN | LXCR_HMEN, 0);
+
++ /* Reset the layer transparency to hide any related background color */
++ regmap_write_bits(ldev->regmap, LTDC_L1CACR + lofs, LXCACR_CONSTA, 0x00);
++
+ /* Commit shadow registers = update plane at next vblank */
+ if (ldev->caps.plane_reg_shadow)
+ regmap_write_bits(ldev->regmap, LTDC_L1RCR + lofs,
+--
+2.43.0
+
--- /dev/null
+From ad6e9a25aa93423cebf61c569d849df0fd99ccb9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 20 Aug 2024 10:29:55 -0700
+Subject: drm/xe: Drop warn on xe_guc_pc_gucrc_disable in guc pc fini
+
+From: Matthew Brost <matthew.brost@intel.com>
+
+[ Upstream commit a323782567812ee925e9b7926445532c7afe331b ]
+
+Not a big deal if CT is down as driver is unloading, no need to warn.
+
+Signed-off-by: Matthew Brost <matthew.brost@intel.com>
+Reviewed-by: Jagmeet Randhawa <jagmeet.randhawa@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20240820172958.1095143-4-matthew.brost@intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/xe_guc_pc.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/xe/xe_guc_pc.c b/drivers/gpu/drm/xe/xe_guc_pc.c
+index 23382ced4ea74..69f8b6fdaeaea 100644
+--- a/drivers/gpu/drm/xe/xe_guc_pc.c
++++ b/drivers/gpu/drm/xe/xe_guc_pc.c
+@@ -897,7 +897,7 @@ static void xe_guc_pc_fini(struct drm_device *drm, void *arg)
+ struct xe_guc_pc *pc = arg;
+
+ XE_WARN_ON(xe_force_wake_get(gt_to_fw(pc_to_gt(pc)), XE_FORCEWAKE_ALL));
+- XE_WARN_ON(xe_guc_pc_gucrc_disable(pc));
++ xe_guc_pc_gucrc_disable(pc);
+ XE_WARN_ON(xe_guc_pc_stop(pc));
+ xe_force_wake_put(gt_to_fw(pc_to_gt(pc)), XE_FORCEWAKE_ALL);
+ }
+--
+2.43.0
+
--- /dev/null
+From b6aed06ec0735572dd40b9228925c51607bc08cc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 22 Jul 2024 12:14:51 +0530
+Subject: drm/xe/hdcp: Check GSC structure validity
+
+From: Suraj Kandpal <suraj.kandpal@intel.com>
+
+[ Upstream commit b4224f6bae3801d589f815672ec62800a1501b0d ]
+
+Sometimes xe_gsc is not initialized when checked at HDCP capability
+check. Add gsc structure check to avoid null pointer error.
+
+Signed-off-by: Suraj Kandpal <suraj.kandpal@intel.com>
+Reviewed-by: Dnyaneshwar Bhadane <dnyaneshwar.bhadane@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20240722064451.3610512-4-suraj.kandpal@intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/display/xe_hdcp_gsc.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/xe/display/xe_hdcp_gsc.c b/drivers/gpu/drm/xe/display/xe_hdcp_gsc.c
+index b3d3c065dd9d8..2f935771658e6 100644
+--- a/drivers/gpu/drm/xe/display/xe_hdcp_gsc.c
++++ b/drivers/gpu/drm/xe/display/xe_hdcp_gsc.c
+@@ -39,10 +39,14 @@ bool intel_hdcp_gsc_check_status(struct xe_device *xe)
+ {
+ struct xe_tile *tile = xe_device_get_root_tile(xe);
+ struct xe_gt *gt = tile->media_gt;
++ struct xe_gsc *gsc = >->uc.gsc;
+ bool ret = true;
+
+- if (!xe_uc_fw_is_enabled(>->uc.gsc.fw))
++ if (!gsc && !xe_uc_fw_is_enabled(&gsc->fw)) {
++ drm_dbg_kms(&xe->drm,
++ "GSC Components not ready for HDCP2.x\n");
+ return false;
++ }
+
+ xe_pm_runtime_get(xe);
+ if (xe_force_wake_get(gt_to_fw(gt), XE_FW_GSC)) {
+@@ -52,7 +56,7 @@ bool intel_hdcp_gsc_check_status(struct xe_device *xe)
+ goto out;
+ }
+
+- if (!xe_gsc_proxy_init_done(>->uc.gsc))
++ if (!xe_gsc_proxy_init_done(gsc))
+ ret = false;
+
+ xe_force_wake_put(gt_to_fw(gt), XE_FW_GSC);
+--
+2.43.0
+
--- /dev/null
+From 44b6d959fa09eac2cad49b6fb151a2be866b59d1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 17 Aug 2024 02:47:31 +0000
+Subject: drm/xe: Use topology to determine page fault queue size
+
+From: Stuart Summers <stuart.summers@intel.com>
+
+[ Upstream commit 3338e4f90c143cf32f77d64f464cb7f2c2d24700 ]
+
+Currently the page fault queue size is hard coded. However
+the hardware supports faulting for each EU and each CS.
+For some applications running on hardware with a large
+number of EUs and CSs, this can result in an overflow of
+the page fault queue.
+
+Add a small calculation to determine the page fault queue
+size based on the number of EUs and CSs in the platform as
+detmined by fuses.
+
+Signed-off-by: Stuart Summers <stuart.summers@intel.com>
+Reviewed-by: Matthew Brost <matthew.brost@intel.com>
+Signed-off-by: Matthew Brost <matthew.brost@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/24d582a3b48c97793b8b6a402f34b4b469471636.1723862633.git.stuart.summers@intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/xe_gt_pagefault.c | 54 +++++++++++++++++++++-------
+ drivers/gpu/drm/xe/xe_gt_types.h | 9 +++--
+ 2 files changed, 49 insertions(+), 14 deletions(-)
+
+diff --git a/drivers/gpu/drm/xe/xe_gt_pagefault.c b/drivers/gpu/drm/xe/xe_gt_pagefault.c
+index 67e8efcaa93f1..ee78b4e47dfcb 100644
+--- a/drivers/gpu/drm/xe/xe_gt_pagefault.c
++++ b/drivers/gpu/drm/xe/xe_gt_pagefault.c
+@@ -307,7 +307,7 @@ static bool get_pagefault(struct pf_queue *pf_queue, struct pagefault *pf)
+ PFD_VIRTUAL_ADDR_LO_SHIFT;
+
+ pf_queue->tail = (pf_queue->tail + PF_MSG_LEN_DW) %
+- PF_QUEUE_NUM_DW;
++ pf_queue->num_dw;
+ ret = true;
+ }
+ spin_unlock_irq(&pf_queue->lock);
+@@ -319,7 +319,8 @@ static bool pf_queue_full(struct pf_queue *pf_queue)
+ {
+ lockdep_assert_held(&pf_queue->lock);
+
+- return CIRC_SPACE(pf_queue->head, pf_queue->tail, PF_QUEUE_NUM_DW) <=
++ return CIRC_SPACE(pf_queue->head, pf_queue->tail,
++ pf_queue->num_dw) <=
+ PF_MSG_LEN_DW;
+ }
+
+@@ -332,22 +333,23 @@ int xe_guc_pagefault_handler(struct xe_guc *guc, u32 *msg, u32 len)
+ u32 asid;
+ bool full;
+
+- /*
+- * The below logic doesn't work unless PF_QUEUE_NUM_DW % PF_MSG_LEN_DW == 0
+- */
+- BUILD_BUG_ON(PF_QUEUE_NUM_DW % PF_MSG_LEN_DW);
+-
+ if (unlikely(len != PF_MSG_LEN_DW))
+ return -EPROTO;
+
+ asid = FIELD_GET(PFD_ASID, msg[1]);
+ pf_queue = gt->usm.pf_queue + (asid % NUM_PF_QUEUE);
+
++ /*
++ * The below logic doesn't work unless PF_QUEUE_NUM_DW % PF_MSG_LEN_DW == 0
++ */
++ xe_gt_assert(gt, !(pf_queue->num_dw % PF_MSG_LEN_DW));
++
+ spin_lock_irqsave(&pf_queue->lock, flags);
+ full = pf_queue_full(pf_queue);
+ if (!full) {
+ memcpy(pf_queue->data + pf_queue->head, msg, len * sizeof(u32));
+- pf_queue->head = (pf_queue->head + len) % PF_QUEUE_NUM_DW;
++ pf_queue->head = (pf_queue->head + len) %
++ pf_queue->num_dw;
+ queue_work(gt->usm.pf_wq, &pf_queue->worker);
+ } else {
+ drm_warn(&xe->drm, "PF Queue full, shouldn't be possible");
+@@ -406,26 +408,54 @@ static void pagefault_fini(void *arg)
+ {
+ struct xe_gt *gt = arg;
+ struct xe_device *xe = gt_to_xe(gt);
++ int i;
+
+ if (!xe->info.has_usm)
+ return;
+
+ destroy_workqueue(gt->usm.acc_wq);
+ destroy_workqueue(gt->usm.pf_wq);
++
++ for (i = 0; i < NUM_PF_QUEUE; ++i)
++ kfree(gt->usm.pf_queue[i].data);
++}
++
++static int xe_alloc_pf_queue(struct xe_gt *gt, struct pf_queue *pf_queue)
++{
++ xe_dss_mask_t all_dss;
++ int num_dss, num_eus;
++
++ bitmap_or(all_dss, gt->fuse_topo.g_dss_mask, gt->fuse_topo.c_dss_mask,
++ XE_MAX_DSS_FUSE_BITS);
++
++ num_dss = bitmap_weight(all_dss, XE_MAX_DSS_FUSE_BITS);
++ num_eus = bitmap_weight(gt->fuse_topo.eu_mask_per_dss,
++ XE_MAX_EU_FUSE_BITS) * num_dss;
++
++ /* user can issue separate page faults per EU and per CS */
++ pf_queue->num_dw =
++ (num_eus + XE_NUM_HW_ENGINES) * PF_MSG_LEN_DW;
++
++ pf_queue->gt = gt;
++ pf_queue->data = kzalloc(pf_queue->num_dw, GFP_KERNEL);
++ spin_lock_init(&pf_queue->lock);
++ INIT_WORK(&pf_queue->worker, pf_queue_work_func);
++
++ return 0;
+ }
+
+ int xe_gt_pagefault_init(struct xe_gt *gt)
+ {
+ struct xe_device *xe = gt_to_xe(gt);
+- int i;
++ int i, ret = 0;
+
+ if (!xe->info.has_usm)
+ return 0;
+
+ for (i = 0; i < NUM_PF_QUEUE; ++i) {
+- gt->usm.pf_queue[i].gt = gt;
+- spin_lock_init(>->usm.pf_queue[i].lock);
+- INIT_WORK(>->usm.pf_queue[i].worker, pf_queue_work_func);
++ ret = xe_alloc_pf_queue(gt, >->usm.pf_queue[i]);
++ if (ret)
++ return ret;
+ }
+ for (i = 0; i < NUM_ACC_QUEUE; ++i) {
+ gt->usm.acc_queue[i].gt = gt;
+diff --git a/drivers/gpu/drm/xe/xe_gt_types.h b/drivers/gpu/drm/xe/xe_gt_types.h
+index cfdc761ff7f46..2dbea50cd8f98 100644
+--- a/drivers/gpu/drm/xe/xe_gt_types.h
++++ b/drivers/gpu/drm/xe/xe_gt_types.h
+@@ -229,9 +229,14 @@ struct xe_gt {
+ struct pf_queue {
+ /** @usm.pf_queue.gt: back pointer to GT */
+ struct xe_gt *gt;
+-#define PF_QUEUE_NUM_DW 128
+ /** @usm.pf_queue.data: data in the page fault queue */
+- u32 data[PF_QUEUE_NUM_DW];
++ u32 *data;
++ /**
++ * @usm.pf_queue.num_dw: number of DWORDS in the page
++ * fault queue. Dynamically calculated based on the number
++ * of compute resources available.
++ */
++ u32 num_dw;
+ /**
+ * @usm.pf_queue.tail: tail pointer in DWs for page fault queue,
+ * moved by worker which processes faults (consumer).
+--
+2.43.0
+
--- /dev/null
+From 6bd74c3a8b3e468d6c892b613191222ba19ac1a1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 6 Aug 2024 16:23:48 +0300
+Subject: e1000e: avoid failing the system during pm_suspend
+
+From: Vitaly Lifshits <vitaly.lifshits@intel.com>
+
+[ Upstream commit 0a6ad4d9e1690c7faa3a53f762c877e477093657 ]
+
+Occasionally when the system goes into pm_suspend, the suspend might fail
+due to a PHY access error on the network adapter. Previously, this would
+have caused the whole system to fail to go to a low power state.
+An example of this was reported in the following Bugzilla:
+https://bugzilla.kernel.org/show_bug.cgi?id=205015
+
+[ 1663.694828] e1000e 0000:00:19.0 eth0: Failed to disable ULP
+[ 1664.731040] asix 2-3:1.0 eth1: link up, 100Mbps, full-duplex, lpa 0xC1E1
+[ 1665.093513] e1000e 0000:00:19.0 eth0: Hardware Error
+[ 1665.596760] e1000e 0000:00:19.0: pci_pm_resume+0x0/0x80 returned 0 after 2975399 usecs
+
+and then the system never recovers from it, and all the following suspend failed due to this
+[22909.393854] PM: pci_pm_suspend(): e1000e_pm_suspend+0x0/0x760 [e1000e] returns -2
+[22909.393858] PM: dpm_run_callback(): pci_pm_suspend+0x0/0x160 returns -2
+[22909.393861] PM: Device 0000:00:1f.6 failed to suspend async: error -2
+
+This can be avoided by changing the return values of __e1000_shutdown and
+e1000e_pm_suspend functions so that they always return 0 (success). This
+is consistent with what other drivers do.
+
+If the e1000e driver encounters a hardware error during suspend, potential
+side effects include slightly higher power draw or non-working wake on
+LAN. This is preferred to a system-level suspend failure, and a warning
+message is written to the system log, so that the user can be aware that
+the LAN controller experienced a problem during suspend.
+
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=205015
+Suggested-by: Dima Ruinskiy <dima.ruinskiy@intel.com>
+Signed-off-by: Vitaly Lifshits <vitaly.lifshits@intel.com>
+Tested-by: Mor Bar-Gabay <morx.bar.gabay@intel.com>
+Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/intel/e1000e/netdev.c | 19 +++++++++++--------
+ 1 file changed, 11 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
+index 3cd161c6672be..e23eedc791d66 100644
+--- a/drivers/net/ethernet/intel/e1000e/netdev.c
++++ b/drivers/net/ethernet/intel/e1000e/netdev.c
+@@ -6671,8 +6671,10 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime)
+ if (adapter->flags2 & FLAG2_HAS_PHY_WAKEUP) {
+ /* enable wakeup by the PHY */
+ retval = e1000_init_phy_wakeup(adapter, wufc);
+- if (retval)
+- return retval;
++ if (retval) {
++ e_err("Failed to enable wakeup\n");
++ goto skip_phy_configurations;
++ }
+ } else {
+ /* enable wakeup by the MAC */
+ ew32(WUFC, wufc);
+@@ -6693,8 +6695,10 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime)
+ * or broadcast.
+ */
+ retval = e1000_enable_ulp_lpt_lp(hw, !runtime);
+- if (retval)
+- return retval;
++ if (retval) {
++ e_err("Failed to enable ULP\n");
++ goto skip_phy_configurations;
++ }
+ }
+ }
+
+@@ -6726,6 +6730,7 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime)
+ hw->phy.ops.release(hw);
+ }
+
++skip_phy_configurations:
+ /* Release control of h/w to f/w. If f/w is AMT enabled, this
+ * would have already happened in close and is redundant.
+ */
+@@ -6968,15 +6973,13 @@ static int e1000e_pm_suspend(struct device *dev)
+ e1000e_pm_freeze(dev);
+
+ rc = __e1000_shutdown(pdev, false);
+- if (rc) {
+- e1000e_pm_thaw(dev);
+- } else {
++ if (!rc) {
+ /* Introduce S0ix implementation */
+ if (adapter->flags2 & FLAG2_ENABLE_S0IX_FLOWS)
+ e1000e_s0ix_entry_flow(adapter);
+ }
+
+- return rc;
++ return 0;
+ }
+
+ static int e1000e_pm_resume(struct device *dev)
+--
+2.43.0
+
--- /dev/null
+From 075a93f14384b131bb526b1d28f986563d0e880a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 22 Aug 2024 10:35:24 +0800
+Subject: ext4: avoid use-after-free in ext4_ext_show_leaf()
+
+From: Baokun Li <libaokun1@huawei.com>
+
+[ Upstream commit 4e2524ba2ca5f54bdbb9e5153bea00421ef653f5 ]
+
+In ext4_find_extent(), path may be freed by error or be reallocated, so
+using a previously saved *ppath may have been freed and thus may trigger
+use-after-free, as follows:
+
+ext4_split_extent
+ path = *ppath;
+ ext4_split_extent_at(ppath)
+ path = ext4_find_extent(ppath)
+ ext4_split_extent_at(ppath)
+ // ext4_find_extent fails to free path
+ // but zeroout succeeds
+ ext4_ext_show_leaf(inode, path)
+ eh = path[depth].p_hdr
+ // path use-after-free !!!
+
+Similar to ext4_split_extent_at(), we use *ppath directly as an input to
+ext4_ext_show_leaf(). Fix a spelling error by the way.
+
+Same problem in ext4_ext_handle_unwritten_extents(). Since 'path' is only
+used in ext4_ext_show_leaf(), remove 'path' and use *ppath directly.
+
+This issue is triggered only when EXT_DEBUG is defined and therefore does
+not affect functionality.
+
+Signed-off-by: Baokun Li <libaokun1@huawei.com>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
+Tested-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
+Link: https://patch.msgid.link/20240822023545.1994557-5-libaokun@huaweicloud.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/extents.c | 9 ++++-----
+ 1 file changed, 4 insertions(+), 5 deletions(-)
+
+diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
+index e067f2dd0335c..7954430f886d8 100644
+--- a/fs/ext4/extents.c
++++ b/fs/ext4/extents.c
+@@ -3287,7 +3287,7 @@ static int ext4_split_extent_at(handle_t *handle,
+ }
+
+ /*
+- * ext4_split_extents() splits an extent and mark extent which is covered
++ * ext4_split_extent() splits an extent and mark extent which is covered
+ * by @map as split_flags indicates
+ *
+ * It may result in splitting the extent into multiple extents (up to three)
+@@ -3363,7 +3363,7 @@ static int ext4_split_extent(handle_t *handle,
+ goto out;
+ }
+
+- ext4_ext_show_leaf(inode, path);
++ ext4_ext_show_leaf(inode, *ppath);
+ out:
+ return err ? err : allocated;
+ }
+@@ -3828,14 +3828,13 @@ ext4_ext_handle_unwritten_extents(handle_t *handle, struct inode *inode,
+ struct ext4_ext_path **ppath, int flags,
+ unsigned int allocated, ext4_fsblk_t newblock)
+ {
+- struct ext4_ext_path __maybe_unused *path = *ppath;
+ int ret = 0;
+ int err = 0;
+
+ ext_debug(inode, "logical block %llu, max_blocks %u, flags 0x%x, allocated %u\n",
+ (unsigned long long)map->m_lblk, map->m_len, flags,
+ allocated);
+- ext4_ext_show_leaf(inode, path);
++ ext4_ext_show_leaf(inode, *ppath);
+
+ /*
+ * When writing into unwritten space, we should not fail to
+@@ -3932,7 +3931,7 @@ ext4_ext_handle_unwritten_extents(handle_t *handle, struct inode *inode,
+ if (allocated > map->m_len)
+ allocated = map->m_len;
+ map->m_len = allocated;
+- ext4_ext_show_leaf(inode, path);
++ ext4_ext_show_leaf(inode, *ppath);
+ out2:
+ return err ? err : allocated;
+ }
+--
+2.43.0
+
--- /dev/null
+From 4fa00095d061d1115320ef696fdbfae86d5a88f1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 5 Aug 2024 22:12:41 +0200
+Subject: ext4: don't set SB_RDONLY after filesystem errors
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit d3476f3dad4ad68ae5f6b008ea6591d1520da5d8 ]
+
+When the filesystem is mounted with errors=remount-ro, we were setting
+SB_RDONLY flag to stop all filesystem modifications. We knew this misses
+proper locking (sb->s_umount) and does not go through proper filesystem
+remount procedure but it has been the way this worked since early ext2
+days and it was good enough for catastrophic situation damage
+mitigation. Recently, syzbot has found a way (see link) to trigger
+warnings in filesystem freezing because the code got confused by
+SB_RDONLY changing under its hands. Since these days we set
+EXT4_FLAGS_SHUTDOWN on the superblock which is enough to stop all
+filesystem modifications, modifying SB_RDONLY shouldn't be needed. So
+stop doing that.
+
+Link: https://lore.kernel.org/all/000000000000b90a8e061e21d12f@google.com
+Reported-by: Christian Brauner <brauner@kernel.org>
+Signed-off-by: Jan Kara <jack@suse.cz>
+Reviewed-by: Christian Brauner <brauner@kernel.org>
+Link: https://patch.msgid.link/20240805201241.27286-1-jack@suse.cz
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/super.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/fs/ext4/super.c b/fs/ext4/super.c
+index edc692984404d..04b78c479fd7a 100644
+--- a/fs/ext4/super.c
++++ b/fs/ext4/super.c
+@@ -735,11 +735,12 @@ static void ext4_handle_error(struct super_block *sb, bool force_ro, int error,
+
+ ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only");
+ /*
+- * Make sure updated value of ->s_mount_flags will be visible before
+- * ->s_flags update
++ * EXT4_FLAGS_SHUTDOWN was set which stops all filesystem
++ * modifications. We don't set SB_RDONLY because that requires
++ * sb->s_umount semaphore and setting it without proper remount
++ * procedure is confusing code such as freeze_super() leading to
++ * deadlocks and other problems.
+ */
+- smp_wmb();
+- sb->s_flags |= SB_RDONLY;
+ }
+
+ static void update_super_work(struct work_struct *work)
+--
+2.43.0
+
--- /dev/null
+From 7acd96814e7cbdea933e4011cdc3a5cc79cc08c6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 21 Aug 2024 12:23:21 -0300
+Subject: ext4: ext4_search_dir should return a proper error
+
+From: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+
+[ Upstream commit cd69f8f9de280e331c9e6ff689ced0a688a9ce8f ]
+
+ext4_search_dir currently returns -1 in case of a failure, while it returns
+0 when the name is not found. In such failure cases, it should return an
+error code instead.
+
+This becomes even more important when ext4_find_inline_entry returns an
+error code as well in the next commit.
+
+-EFSCORRUPTED seems appropriate as such error code as these failures would
+be caused by unexpected record lengths and is in line with other instances
+of ext4_check_dir_entry failures.
+
+In the case of ext4_dx_find_entry, the current use of ERR_BAD_DX_DIR was
+left as is to reduce the risk of regressions.
+
+Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Link: https://patch.msgid.link/20240821152324.3621860-2-cascardo@igalia.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/namei.c | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
+index 1311ad0464b2a..12af7c7e09c1a 100644
+--- a/fs/ext4/namei.c
++++ b/fs/ext4/namei.c
+@@ -1526,7 +1526,7 @@ static bool ext4_match(struct inode *parent,
+ }
+
+ /*
+- * Returns 0 if not found, -1 on failure, and 1 on success
++ * Returns 0 if not found, -EFSCORRUPTED on failure, and 1 on success
+ */
+ int ext4_search_dir(struct buffer_head *bh, char *search_buf, int buf_size,
+ struct inode *dir, struct ext4_filename *fname,
+@@ -1547,7 +1547,7 @@ int ext4_search_dir(struct buffer_head *bh, char *search_buf, int buf_size,
+ * a full check */
+ if (ext4_check_dir_entry(dir, NULL, de, bh, search_buf,
+ buf_size, offset))
+- return -1;
++ return -EFSCORRUPTED;
+ *res_dir = de;
+ return 1;
+ }
+@@ -1555,7 +1555,7 @@ int ext4_search_dir(struct buffer_head *bh, char *search_buf, int buf_size,
+ de_len = ext4_rec_len_from_disk(de->rec_len,
+ dir->i_sb->s_blocksize);
+ if (de_len <= 0)
+- return -1;
++ return -EFSCORRUPTED;
+ offset += de_len;
+ de = (struct ext4_dir_entry_2 *) ((char *) de + de_len);
+ }
+@@ -1707,8 +1707,10 @@ static struct buffer_head *__ext4_find_entry(struct inode *dir,
+ goto cleanup_and_exit;
+ } else {
+ brelse(bh);
+- if (i < 0)
++ if (i < 0) {
++ ret = ERR_PTR(i);
+ goto cleanup_and_exit;
++ }
+ }
+ next:
+ if (++block >= nblocks)
+@@ -1802,7 +1804,7 @@ static struct buffer_head * ext4_dx_find_entry(struct inode *dir,
+ if (retval == 1)
+ goto success;
+ brelse(bh);
+- if (retval == -1) {
++ if (retval < 0) {
+ bh = ERR_PTR(ERR_BAD_DX_DIR);
+ goto errout;
+ }
+--
+2.43.0
+
--- /dev/null
+From baeb28afb2bcc0f4f022dc99679ff8b461d00a9f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 29 Aug 2024 15:22:09 +0000
+Subject: ext4: fix i_data_sem unlock order in ext4_ind_migrate()
+
+From: Artem Sadovnikov <ancowi69@gmail.com>
+
+[ Upstream commit cc749e61c011c255d81b192a822db650c68b313f ]
+
+Fuzzing reports a possible deadlock in jbd2_log_wait_commit.
+
+This issue is triggered when an EXT4_IOC_MIGRATE ioctl is set to require
+synchronous updates because the file descriptor is opened with O_SYNC.
+This can lead to the jbd2_journal_stop() function calling
+jbd2_might_wait_for_commit(), potentially causing a deadlock if the
+EXT4_IOC_MIGRATE call races with a write(2) system call.
+
+This problem only arises when CONFIG_PROVE_LOCKING is enabled. In this
+case, the jbd2_might_wait_for_commit macro locks jbd2_handle in the
+jbd2_journal_stop function while i_data_sem is locked. This triggers
+lockdep because the jbd2_journal_start function might also lock the same
+jbd2_handle simultaneously.
+
+Found by Linux Verification Center (linuxtesting.org) with syzkaller.
+
+Reviewed-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
+Co-developed-by: Mikhail Ukhin <mish.uxin2012@yandex.ru>
+Signed-off-by: Mikhail Ukhin <mish.uxin2012@yandex.ru>
+Signed-off-by: Artem Sadovnikov <ancowi69@gmail.com>
+Rule: add
+Link: https://lore.kernel.org/stable/20240404095000.5872-1-mish.uxin2012%40yandex.ru
+Link: https://patch.msgid.link/20240829152210.2754-1-ancowi69@gmail.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/migrate.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c
+index d98ac2af8199f..a5e1492bbaaa5 100644
+--- a/fs/ext4/migrate.c
++++ b/fs/ext4/migrate.c
+@@ -663,8 +663,8 @@ int ext4_ind_migrate(struct inode *inode)
+ if (unlikely(ret2 && !ret))
+ ret = ret2;
+ errout:
+- ext4_journal_stop(handle);
+ up_write(&EXT4_I(inode)->i_data_sem);
++ ext4_journal_stop(handle);
+ out_unlock:
+ ext4_writepages_up_write(inode->i_sb, alloc_ctx);
+ return ret;
+--
+2.43.0
+
--- /dev/null
+From 869de8716716b84fdc41777009b8cda6617b6e31 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 27 Aug 2024 17:25:13 +0200
+Subject: fbdev: efifb: Register sysfs groups through driver core
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Thomas Weißschuh <linux@weissschuh.net>
+
+[ Upstream commit 95cdd538e0e5677efbdf8aade04ec098ab98f457 ]
+
+The driver core can register and cleanup sysfs groups already.
+Make use of that functionality to simplify the error handling and
+cleanup.
+
+Also avoid a UAF race during unregistering where the sysctl attributes
+were usable after the info struct was freed.
+
+Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
+Signed-off-by: Helge Deller <deller@gmx.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/video/fbdev/efifb.c | 11 ++---------
+ 1 file changed, 2 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c
+index 8dd82afb3452b..595b8e27bea66 100644
+--- a/drivers/video/fbdev/efifb.c
++++ b/drivers/video/fbdev/efifb.c
+@@ -561,15 +561,10 @@ static int efifb_probe(struct platform_device *dev)
+ break;
+ }
+
+- err = sysfs_create_groups(&dev->dev.kobj, efifb_groups);
+- if (err) {
+- pr_err("efifb: cannot add sysfs attrs\n");
+- goto err_unmap;
+- }
+ err = fb_alloc_cmap(&info->cmap, 256, 0);
+ if (err < 0) {
+ pr_err("efifb: cannot allocate colormap\n");
+- goto err_groups;
++ goto err_unmap;
+ }
+
+ err = devm_aperture_acquire_for_platform_device(dev, par->base, par->size);
+@@ -587,8 +582,6 @@ static int efifb_probe(struct platform_device *dev)
+
+ err_fb_dealloc_cmap:
+ fb_dealloc_cmap(&info->cmap);
+-err_groups:
+- sysfs_remove_groups(&dev->dev.kobj, efifb_groups);
+ err_unmap:
+ if (mem_flags & (EFI_MEMORY_UC | EFI_MEMORY_WC))
+ iounmap(info->screen_base);
+@@ -608,12 +601,12 @@ static void efifb_remove(struct platform_device *pdev)
+
+ /* efifb_destroy takes care of info cleanup */
+ unregister_framebuffer(info);
+- sysfs_remove_groups(&pdev->dev.kobj, efifb_groups);
+ }
+
+ static struct platform_driver efifb_driver = {
+ .driver = {
+ .name = "efi-framebuffer",
++ .dev_groups = efifb_groups,
+ },
+ .probe = efifb_probe,
+ .remove_new = efifb_remove,
+--
+2.43.0
+
--- /dev/null
+From fe740ec834a2e786e8ed8d06e137719480949c13 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 11 Sep 2024 22:29:52 +0800
+Subject: fbdev: pxafb: Fix possible use after free in pxafb_task()
+
+From: Kaixin Wang <kxwang23@m.fudan.edu.cn>
+
+[ Upstream commit 4a6921095eb04a900e0000da83d9475eb958e61e ]
+
+In the pxafb_probe function, it calls the pxafb_init_fbinfo function,
+after which &fbi->task is associated with pxafb_task. Moreover,
+within this pxafb_init_fbinfo function, the pxafb_blank function
+within the &pxafb_ops struct is capable of scheduling work.
+
+If we remove the module which will call pxafb_remove to make cleanup,
+it will call unregister_framebuffer function which can call
+do_unregister_framebuffer to free fbi->fb through
+put_fb_info(fb_info), while the work mentioned above will be used.
+The sequence of operations that may lead to a UAF bug is as follows:
+
+CPU0 CPU1
+
+ | pxafb_task
+pxafb_remove |
+unregister_framebuffer(info) |
+do_unregister_framebuffer(fb_info) |
+put_fb_info(fb_info) |
+// free fbi->fb | set_ctrlr_state(fbi, state)
+ | __pxafb_lcd_power(fbi, 0)
+ | fbi->lcd_power(on, &fbi->fb.var)
+ | //use fbi->fb
+
+Fix it by ensuring that the work is canceled before proceeding
+with the cleanup in pxafb_remove.
+
+Note that only root user can remove the driver at runtime.
+
+Signed-off-by: Kaixin Wang <kxwang23@m.fudan.edu.cn>
+Signed-off-by: Helge Deller <deller@gmx.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/video/fbdev/pxafb.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/video/fbdev/pxafb.c b/drivers/video/fbdev/pxafb.c
+index 2ef56fa28aff3..5ce02495cda63 100644
+--- a/drivers/video/fbdev/pxafb.c
++++ b/drivers/video/fbdev/pxafb.c
+@@ -2403,6 +2403,7 @@ static void pxafb_remove(struct platform_device *dev)
+ info = &fbi->fb;
+
+ pxafb_overlay_exit(fbi);
++ cancel_work_sync(&fbi->task);
+ unregister_framebuffer(info);
+
+ pxafb_disable_controller(fbi);
+--
+2.43.0
+
--- /dev/null
+From 4440a200086dfcd3f1388fd63052757d5147c90e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 26 Aug 2024 13:55:03 +0800
+Subject: fs/inode: Prevent dump_mapping() accessing invalid dentry.d_name.name
+
+From: Li Zhijian <lizhijian@fujitsu.com>
+
+[ Upstream commit 7f7b850689ac06a62befe26e1fd1806799e7f152 ]
+
+It's observed that a crash occurs during hot-remove a memory device,
+in which user is accessing the hugetlb. See calltrace as following:
+
+------------[ cut here ]------------
+WARNING: CPU: 1 PID: 14045 at arch/x86/mm/fault.c:1278 do_user_addr_fault+0x2a0/0x790
+Modules linked in: kmem device_dax cxl_mem cxl_pmem cxl_port cxl_pci dax_hmem dax_pmem nd_pmem cxl_acpi nd_btt cxl_core crc32c_intel nvme virtiofs fuse nvme_core nfit libnvdimm dm_multipath scsi_dh_rdac scsi_dh_emc s
+mirror dm_region_hash dm_log dm_mod
+CPU: 1 PID: 14045 Comm: daxctl Not tainted 6.10.0-rc2-lizhijian+ #492
+Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014
+RIP: 0010:do_user_addr_fault+0x2a0/0x790
+Code: 48 8b 00 a8 04 0f 84 b5 fe ff ff e9 1c ff ff ff 4c 89 e9 4c 89 e2 be 01 00 00 00 bf 02 00 00 00 e8 b5 ef 24 00 e9 42 fe ff ff <0f> 0b 48 83 c4 08 4c 89 ea 48 89 ee 4c 89 e7 5b 5d 41 5c 41 5d 41
+RSP: 0000:ffffc90000a575f0 EFLAGS: 00010046
+RAX: ffff88800c303600 RBX: 0000000000000000 RCX: 0000000000000000
+RDX: 0000000000001000 RSI: ffffffff82504162 RDI: ffffffff824b2c36
+RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000
+R10: 0000000000000000 R11: 0000000000000000 R12: ffffc90000a57658
+R13: 0000000000001000 R14: ffff88800bc2e040 R15: 0000000000000000
+FS: 00007f51cb57d880(0000) GS:ffff88807fd00000(0000) knlGS:0000000000000000
+CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+CR2: 0000000000001000 CR3: 00000000072e2004 CR4: 00000000001706f0
+DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
+DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
+Call Trace:
+ <TASK>
+ ? __warn+0x8d/0x190
+ ? do_user_addr_fault+0x2a0/0x790
+ ? report_bug+0x1c3/0x1d0
+ ? handle_bug+0x3c/0x70
+ ? exc_invalid_op+0x14/0x70
+ ? asm_exc_invalid_op+0x16/0x20
+ ? do_user_addr_fault+0x2a0/0x790
+ ? exc_page_fault+0x31/0x200
+ exc_page_fault+0x68/0x200
+<...snip...>
+BUG: unable to handle page fault for address: 0000000000001000
+ #PF: supervisor read access in kernel mode
+ #PF: error_code(0x0000) - not-present page
+ PGD 800000000ad92067 P4D 800000000ad92067 PUD 7677067 PMD 0
+ Oops: Oops: 0000 [#1] PREEMPT SMP PTI
+ ---[ end trace 0000000000000000 ]---
+ BUG: unable to handle page fault for address: 0000000000001000
+ #PF: supervisor read access in kernel mode
+ #PF: error_code(0x0000) - not-present page
+ PGD 800000000ad92067 P4D 800000000ad92067 PUD 7677067 PMD 0
+ Oops: Oops: 0000 [#1] PREEMPT SMP PTI
+ CPU: 1 PID: 14045 Comm: daxctl Kdump: loaded Tainted: G W 6.10.0-rc2-lizhijian+ #492
+ Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014
+ RIP: 0010:dentry_name+0x1f4/0x440
+<...snip...>
+? dentry_name+0x2fa/0x440
+vsnprintf+0x1f3/0x4f0
+vprintk_store+0x23a/0x540
+vprintk_emit+0x6d/0x330
+_printk+0x58/0x80
+dump_mapping+0x10b/0x1a0
+? __pfx_free_object_rcu+0x10/0x10
+__dump_page+0x26b/0x3e0
+? vprintk_emit+0xe0/0x330
+? _printk+0x58/0x80
+? dump_page+0x17/0x50
+dump_page+0x17/0x50
+do_migrate_range+0x2f7/0x7f0
+? do_migrate_range+0x42/0x7f0
+? offline_pages+0x2f4/0x8c0
+offline_pages+0x60a/0x8c0
+memory_subsys_offline+0x9f/0x1c0
+? lockdep_hardirqs_on+0x77/0x100
+? _raw_spin_unlock_irqrestore+0x38/0x60
+device_offline+0xe3/0x110
+state_store+0x6e/0xc0
+kernfs_fop_write_iter+0x143/0x200
+vfs_write+0x39f/0x560
+ksys_write+0x65/0xf0
+do_syscall_64+0x62/0x130
+
+Previously, some sanity check have been done in dump_mapping() before
+the print facility parsing '%pd' though, it's still possible to run into
+an invalid dentry.d_name.name.
+
+Since dump_mapping() only needs to dump the filename only, retrieve it
+by itself in a safer way to prevent an unnecessary crash.
+
+Note that either retrieving the filename with '%pd' or
+strncpy_from_kernel_nofault(), the filename could be unreliable.
+
+Signed-off-by: Li Zhijian <lizhijian@fujitsu.com>
+Link: https://lore.kernel.org/r/20240826055503.1522320-1-lizhijian@fujitsu.com
+Reviewed-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Christian Brauner <brauner@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/inode.c | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+diff --git a/fs/inode.c b/fs/inode.c
+index 3df67672986aa..aeb07c3b8f24e 100644
+--- a/fs/inode.c
++++ b/fs/inode.c
+@@ -593,6 +593,7 @@ void dump_mapping(const struct address_space *mapping)
+ struct hlist_node *dentry_first;
+ struct dentry *dentry_ptr;
+ struct dentry dentry;
++ char fname[64] = {};
+ unsigned long ino;
+
+ /*
+@@ -629,11 +630,14 @@ void dump_mapping(const struct address_space *mapping)
+ return;
+ }
+
++ if (strncpy_from_kernel_nofault(fname, dentry.d_name.name, 63) < 0)
++ strscpy(fname, "<invalid>");
+ /*
+- * if dentry is corrupted, the %pd handler may still crash,
+- * but it's unlikely that we reach here with a corrupt mapping
++ * Even if strncpy_from_kernel_nofault() succeeded,
++ * the fname could be unreliable
+ */
+- pr_warn("aops:%ps ino:%lx dentry name:\"%pd\"\n", a_ops, ino, &dentry);
++ pr_warn("aops:%ps ino:%lx dentry name(?):\"%s\"\n",
++ a_ops, ino, fname);
+ }
+
+ void clear_inode(struct inode *inode)
+--
+2.43.0
+
--- /dev/null
+From 739f139d34f66b21dfb3d65ec7c99173ec0b0c35 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 9 Sep 2024 13:37:40 -0700
+Subject: HID: i2c-hid: ensure various commands do not interfere with each
+ other
+
+From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+
+[ Upstream commit b4ed18a3d56eabd18cfd9841ff05111e3cfbe8f9 ]
+
+i2c-hid uses 2 shared buffers: command and "raw" input buffer for
+sending requests to peripherals and read data from peripherals when
+executing variety of commands. Such commands include reading of HID
+registers, requesting particular power mode, getting and setting
+reports and so on. Because all such requests use the same 2 buffers
+they should not execute simultaneously.
+
+Fix this by introducing "cmd_lock" mutex and acquire it whenever
+we needs to access ihid->cmdbuf or idid->rawbuf.
+
+Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hid/i2c-hid/i2c-hid-core.c | 42 +++++++++++++++++++-----------
+ 1 file changed, 27 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c
+index 632eaf9e11a6b..2f8a9d3f1e861 100644
+--- a/drivers/hid/i2c-hid/i2c-hid-core.c
++++ b/drivers/hid/i2c-hid/i2c-hid-core.c
+@@ -105,6 +105,7 @@ struct i2c_hid {
+
+ wait_queue_head_t wait; /* For waiting the interrupt */
+
++ struct mutex cmd_lock; /* protects cmdbuf and rawbuf */
+ struct mutex reset_lock;
+
+ struct i2chid_ops *ops;
+@@ -220,6 +221,8 @@ static int i2c_hid_xfer(struct i2c_hid *ihid,
+ static int i2c_hid_read_register(struct i2c_hid *ihid, __le16 reg,
+ void *buf, size_t len)
+ {
++ guard(mutex)(&ihid->cmd_lock);
++
+ *(__le16 *)ihid->cmdbuf = reg;
+
+ return i2c_hid_xfer(ihid, ihid->cmdbuf, sizeof(__le16), buf, len);
+@@ -252,6 +255,8 @@ static int i2c_hid_get_report(struct i2c_hid *ihid,
+
+ i2c_hid_dbg(ihid, "%s\n", __func__);
+
++ guard(mutex)(&ihid->cmd_lock);
++
+ /* Command register goes first */
+ *(__le16 *)ihid->cmdbuf = ihid->hdesc.wCommandRegister;
+ length += sizeof(__le16);
+@@ -342,6 +347,8 @@ static int i2c_hid_set_or_send_report(struct i2c_hid *ihid,
+ if (!do_set && le16_to_cpu(ihid->hdesc.wMaxOutputLength) == 0)
+ return -ENOSYS;
+
++ guard(mutex)(&ihid->cmd_lock);
++
+ if (do_set) {
+ /* Command register goes first */
+ *(__le16 *)ihid->cmdbuf = ihid->hdesc.wCommandRegister;
+@@ -384,6 +391,8 @@ static int i2c_hid_set_power_command(struct i2c_hid *ihid, int power_state)
+ {
+ size_t length;
+
++ guard(mutex)(&ihid->cmd_lock);
++
+ /* SET_POWER uses command register */
+ *(__le16 *)ihid->cmdbuf = ihid->hdesc.wCommandRegister;
+ length = sizeof(__le16);
+@@ -440,25 +449,27 @@ static int i2c_hid_start_hwreset(struct i2c_hid *ihid)
+ if (ret)
+ return ret;
+
+- /* Prepare reset command. Command register goes first. */
+- *(__le16 *)ihid->cmdbuf = ihid->hdesc.wCommandRegister;
+- length += sizeof(__le16);
+- /* Next is RESET command itself */
+- length += i2c_hid_encode_command(ihid->cmdbuf + length,
+- I2C_HID_OPCODE_RESET, 0, 0);
++ scoped_guard(mutex, &ihid->cmd_lock) {
++ /* Prepare reset command. Command register goes first. */
++ *(__le16 *)ihid->cmdbuf = ihid->hdesc.wCommandRegister;
++ length += sizeof(__le16);
++ /* Next is RESET command itself */
++ length += i2c_hid_encode_command(ihid->cmdbuf + length,
++ I2C_HID_OPCODE_RESET, 0, 0);
+
+- set_bit(I2C_HID_RESET_PENDING, &ihid->flags);
++ set_bit(I2C_HID_RESET_PENDING, &ihid->flags);
+
+- ret = i2c_hid_xfer(ihid, ihid->cmdbuf, length, NULL, 0);
+- if (ret) {
+- dev_err(&ihid->client->dev,
+- "failed to reset device: %d\n", ret);
+- goto err_clear_reset;
+- }
++ ret = i2c_hid_xfer(ihid, ihid->cmdbuf, length, NULL, 0);
++ if (ret) {
++ dev_err(&ihid->client->dev,
++ "failed to reset device: %d\n", ret);
++ break;
++ }
+
+- return 0;
++ return 0;
++ }
+
+-err_clear_reset:
++ /* Clean up if sending reset command failed */
+ clear_bit(I2C_HID_RESET_PENDING, &ihid->flags);
+ i2c_hid_set_power(ihid, I2C_HID_PWR_SLEEP);
+ return ret;
+@@ -1200,6 +1211,7 @@ int i2c_hid_core_probe(struct i2c_client *client, struct i2chid_ops *ops,
+ ihid->is_panel_follower = drm_is_panel_follower(&client->dev);
+
+ init_waitqueue_head(&ihid->wait);
++ mutex_init(&ihid->cmd_lock);
+ mutex_init(&ihid->reset_lock);
+ INIT_WORK(&ihid->panel_follower_prepare_work, ihid_core_panel_prepare_work);
+
+--
+2.43.0
+
--- /dev/null
+From 63ca16d492ef1a3ee1d959bbabdee64bd57d1294 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 5 Aug 2024 16:51:47 +0200
+Subject: HID: Ignore battery for all ELAN I2C-HID devices
+
+From: Hans de Goede <hdegoede@redhat.com>
+
+[ Upstream commit bcc31692a1d1e21f0d06c5f727c03ee299d2264e ]
+
+Before this change there were 16 vid:pid based quirks to ignore the battery
+reported by Elan I2C-HID touchscreens on various Asus and HP laptops.
+
+And a report has been received that the 04F3:2A00 I2C touchscreen on
+the HP ProBook x360 11 G5 EE/86CF also reports a non present battery.
+
+Since I2C-HID devices are always builtin to laptops they are not battery
+owered so it should be safe to just ignore the battery on all Elan I2C-HID
+devices, rather then adding a 17th quirk for the 04F3:2A00 touchscreen.
+
+As reported in the changelog of commit a3a5a37efba1 ("HID: Ignore battery
+for ELAN touchscreens 2F2C and 4116"), which added 2 new Elan touchscreen
+quirks about a month ago, the HID reported battery seems to be related
+to a stylus being used. But even when a stylus is in use it does not
+properly report the charge of the stylus battery, instead the reported
+battery charge jumps from 0% to 1%. So it is best to just ignore the
+HID battery.
+
+Closes: https://bugzilla.redhat.com/show_bug.cgi?id=2302776
+Cc: Louis Dalibard <ontake@ontake.dev>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hid/hid-ids.h | 16 ----------------
+ drivers/hid/hid-input.c | 37 +++++--------------------------------
+ 2 files changed, 5 insertions(+), 48 deletions(-)
+
+diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
+index 781c5aa298598..53655f81d9950 100644
+--- a/drivers/hid/hid-ids.h
++++ b/drivers/hid/hid-ids.h
+@@ -417,24 +417,8 @@
+ #define USB_DEVICE_ID_TOSHIBA_CLICK_L9W 0x0401
+ #define USB_DEVICE_ID_HP_X2 0x074d
+ #define USB_DEVICE_ID_HP_X2_10_COVER 0x0755
+-#define I2C_DEVICE_ID_HP_ENVY_X360_15 0x2d05
+-#define I2C_DEVICE_ID_HP_ENVY_X360_15T_DR100 0x29CF
+-#define I2C_DEVICE_ID_HP_ENVY_X360_EU0009NV 0x2CF9
+-#define I2C_DEVICE_ID_HP_SPECTRE_X360_15 0x2817
+-#define I2C_DEVICE_ID_HP_SPECTRE_X360_13_AW0020NG 0x29DF
+-#define I2C_DEVICE_ID_ASUS_TP420IA_TOUCHSCREEN 0x2BC8
+-#define I2C_DEVICE_ID_ASUS_GV301RA_TOUCHSCREEN 0x2C82
+-#define I2C_DEVICE_ID_ASUS_UX3402_TOUCHSCREEN 0x2F2C
+-#define I2C_DEVICE_ID_ASUS_UX6404_TOUCHSCREEN 0x4116
+ #define USB_DEVICE_ID_ASUS_UX550VE_TOUCHSCREEN 0x2544
+ #define USB_DEVICE_ID_ASUS_UX550_TOUCHSCREEN 0x2706
+-#define I2C_DEVICE_ID_SURFACE_GO_TOUCHSCREEN 0x261A
+-#define I2C_DEVICE_ID_SURFACE_GO2_TOUCHSCREEN 0x2A1C
+-#define I2C_DEVICE_ID_LENOVO_YOGA_C630_TOUCHSCREEN 0x279F
+-#define I2C_DEVICE_ID_HP_SPECTRE_X360_13T_AW100 0x29F5
+-#define I2C_DEVICE_ID_HP_SPECTRE_X360_14T_EA100_V1 0x2BED
+-#define I2C_DEVICE_ID_HP_SPECTRE_X360_14T_EA100_V2 0x2BEE
+-#define I2C_DEVICE_ID_HP_ENVY_X360_15_EU0556NG 0x2D02
+ #define I2C_DEVICE_ID_CHROMEBOOK_TROGDOR_POMPOM 0x2F81
+
+ #define USB_VENDOR_ID_ELECOM 0x056e
+diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
+index c9094a4f281e9..fda9dce3da998 100644
+--- a/drivers/hid/hid-input.c
++++ b/drivers/hid/hid-input.c
+@@ -373,14 +373,6 @@ static const struct hid_device_id hid_battery_quirks[] = {
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH,
+ USB_DEVICE_ID_LOGITECH_DINOVO_EDGE_KBD),
+ HID_BATTERY_QUIRK_IGNORE },
+- { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_ASUS_TP420IA_TOUCHSCREEN),
+- HID_BATTERY_QUIRK_IGNORE },
+- { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_ASUS_GV301RA_TOUCHSCREEN),
+- HID_BATTERY_QUIRK_IGNORE },
+- { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_ASUS_UX3402_TOUCHSCREEN),
+- HID_BATTERY_QUIRK_IGNORE },
+- { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_ASUS_UX6404_TOUCHSCREEN),
+- HID_BATTERY_QUIRK_IGNORE },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ASUS_UX550_TOUCHSCREEN),
+ HID_BATTERY_QUIRK_IGNORE },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ASUS_UX550VE_TOUCHSCREEN),
+@@ -391,32 +383,13 @@ static const struct hid_device_id hid_battery_quirks[] = {
+ HID_BATTERY_QUIRK_AVOID_QUERY },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_SW),
+ HID_BATTERY_QUIRK_AVOID_QUERY },
+- { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_ENVY_X360_15),
+- HID_BATTERY_QUIRK_IGNORE },
+- { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_ENVY_X360_15T_DR100),
+- HID_BATTERY_QUIRK_IGNORE },
+- { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_ENVY_X360_EU0009NV),
+- HID_BATTERY_QUIRK_IGNORE },
+- { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_SPECTRE_X360_15),
+- HID_BATTERY_QUIRK_IGNORE },
+- { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_SPECTRE_X360_13_AW0020NG),
+- HID_BATTERY_QUIRK_IGNORE },
+- { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_SURFACE_GO_TOUCHSCREEN),
+- HID_BATTERY_QUIRK_IGNORE },
+- { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_SURFACE_GO2_TOUCHSCREEN),
+- HID_BATTERY_QUIRK_IGNORE },
+- { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_LENOVO_YOGA_C630_TOUCHSCREEN),
+- HID_BATTERY_QUIRK_IGNORE },
+- { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_SPECTRE_X360_13T_AW100),
+- HID_BATTERY_QUIRK_IGNORE },
+- { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_SPECTRE_X360_14T_EA100_V1),
+- HID_BATTERY_QUIRK_IGNORE },
+- { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_SPECTRE_X360_14T_EA100_V2),
+- HID_BATTERY_QUIRK_IGNORE },
+- { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_ENVY_X360_15_EU0556NG),
+- HID_BATTERY_QUIRK_IGNORE },
+ { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_CHROMEBOOK_TROGDOR_POMPOM),
+ HID_BATTERY_QUIRK_AVOID_QUERY },
++ /*
++ * Elan I2C-HID touchscreens seem to all report a non present battery,
++ * set HID_BATTERY_QUIRK_IGNORE for all Elan I2C-HID devices.
++ */
++ { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, HID_ANY_ID), HID_BATTERY_QUIRK_IGNORE },
+ {}
+ };
+
+--
+2.43.0
+
--- /dev/null
+From 47d3956433b7cfc2f62e8c8f1486ba8ac19928bd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 18 Aug 2024 16:27:29 +0900
+Subject: HID: multitouch: Add support for Thinkpad X12 Gen 2 Kbd Portfolio
+
+From: Vishnu Sankar <vishnuocv@gmail.com>
+
+[ Upstream commit 65b72ea91a257a5f0cb5a26b01194d3dd4b85298 ]
+
+This applies similar quirks used by previous generation device, so that
+Trackpoint and buttons on the touchpad works. New USB KBD PID 0x61AE for
+Thinkpad X12 Tab is added.
+
+Signed-off-by: Vishnu Sankar <vishnuocv@gmail.com>
+Reviewed-by: Mark Pearson <mpearson-lenovo@squebb.ca>
+Signed-off-by: Jiri Kosina <jkosina@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hid/hid-ids.h | 1 +
+ drivers/hid/hid-multitouch.c | 6 ++++++
+ 2 files changed, 7 insertions(+)
+
+diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
+index 53655f81d9950..06104a4e0fdc1 100644
+--- a/drivers/hid/hid-ids.h
++++ b/drivers/hid/hid-ids.h
+@@ -794,6 +794,7 @@
+ #define USB_DEVICE_ID_LENOVO_X1_TAB 0x60a3
+ #define USB_DEVICE_ID_LENOVO_X1_TAB3 0x60b5
+ #define USB_DEVICE_ID_LENOVO_X12_TAB 0x60fe
++#define USB_DEVICE_ID_LENOVO_X12_TAB2 0x61ae
+ #define USB_DEVICE_ID_LENOVO_OPTICAL_USB_MOUSE_600E 0x600e
+ #define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D 0x608d
+ #define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019 0x6019
+diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
+index 99812c0f830b5..c4a6908bbe540 100644
+--- a/drivers/hid/hid-multitouch.c
++++ b/drivers/hid/hid-multitouch.c
+@@ -2113,6 +2113,12 @@ static const struct hid_device_id mt_devices[] = {
+ USB_VENDOR_ID_LENOVO,
+ USB_DEVICE_ID_LENOVO_X12_TAB) },
+
++ /* Lenovo X12 TAB Gen 2 */
++ { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT_NSMU,
++ HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8,
++ USB_VENDOR_ID_LENOVO,
++ USB_DEVICE_ID_LENOVO_X12_TAB2) },
++
+ /* Logitech devices */
+ { .driver_data = MT_CLS_NSMU,
+ HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_MULTITOUCH_WIN_8,
+--
+2.43.0
+
--- /dev/null
+From d52ab9c4b7a578238c64e413ccf1346a91a3bc68 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 12 Aug 2024 18:26:38 +0300
+Subject: hwmon: (nct6775) add G15CF to ASUS WMI monitoring list
+
+From: Denis Pauk <pauk.denis@gmail.com>
+
+[ Upstream commit 1f432e4cf1dd3ecfec5ed80051b4611632a0fd51 ]
+
+Boards G15CF has got a nct6775 chip, but by default there's no use of it
+because of resource conflict with WMI method.
+
+Add the board to the WMI monitoring list.
+
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=204807
+Signed-off-by: Denis Pauk <pauk.denis@gmail.com>
+Tested-by: Attila <attila@fulop.one>
+Message-ID: <20240812152652.1303-1-pauk.denis@gmail.com>
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/nct6775-platform.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/hwmon/nct6775-platform.c b/drivers/hwmon/nct6775-platform.c
+index 9aa4dcf4a6f33..096f1daa8f2bc 100644
+--- a/drivers/hwmon/nct6775-platform.c
++++ b/drivers/hwmon/nct6775-platform.c
+@@ -1269,6 +1269,7 @@ static const char * const asus_msi_boards[] = {
+ "EX-B760M-V5 D4",
+ "EX-H510M-V3",
+ "EX-H610M-V3 D4",
++ "G15CF",
+ "PRIME A620M-A",
+ "PRIME B560-PLUS",
+ "PRIME B560-PLUS AC-HES",
+--
+2.43.0
+
--- /dev/null
+From b3788b864f693d2888ddd6c742c5ac771278309e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 10 Jul 2024 15:39:49 +0300
+Subject: ice: Adjust over allocation of memory in ice_sched_add_root_node()
+ and ice_sched_add_node()
+
+From: Aleksandr Mishin <amishin@t-argos.ru>
+
+[ Upstream commit 62fdaf9e8056e9a9e6fe63aa9c816ec2122d60c6 ]
+
+In ice_sched_add_root_node() and ice_sched_add_node() there are calls to
+devm_kcalloc() in order to allocate memory for array of pointers to
+'ice_sched_node' structure. But incorrect types are used as sizeof()
+arguments in these calls (structures instead of pointers) which leads to
+over allocation of memory.
+
+Adjust over allocation of memory by correcting types in devm_kcalloc()
+sizeof() arguments.
+
+Found by Linux Verification Center (linuxtesting.org) with SVACE.
+
+Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
+Signed-off-by: Aleksandr Mishin <amishin@t-argos.ru>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Tested-by: Pucha Himasekhar Reddy <himasekharx.reddy.pucha@intel.com> (A Contingent worker at Intel)
+Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/intel/ice/ice_sched.c | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/ethernet/intel/ice/ice_sched.c b/drivers/net/ethernet/intel/ice/ice_sched.c
+index ecf8f5d602921..6ca13c5dcb14e 100644
+--- a/drivers/net/ethernet/intel/ice/ice_sched.c
++++ b/drivers/net/ethernet/intel/ice/ice_sched.c
+@@ -28,9 +28,8 @@ ice_sched_add_root_node(struct ice_port_info *pi,
+ if (!root)
+ return -ENOMEM;
+
+- /* coverity[suspicious_sizeof] */
+ root->children = devm_kcalloc(ice_hw_to_dev(hw), hw->max_children[0],
+- sizeof(*root), GFP_KERNEL);
++ sizeof(*root->children), GFP_KERNEL);
+ if (!root->children) {
+ devm_kfree(ice_hw_to_dev(hw), root);
+ return -ENOMEM;
+@@ -186,10 +185,9 @@ ice_sched_add_node(struct ice_port_info *pi, u8 layer,
+ if (!node)
+ return -ENOMEM;
+ if (hw->max_children[layer]) {
+- /* coverity[suspicious_sizeof] */
+ node->children = devm_kcalloc(ice_hw_to_dev(hw),
+ hw->max_children[layer],
+- sizeof(*node), GFP_KERNEL);
++ sizeof(*node->children), GFP_KERNEL);
+ if (!node->children) {
+ devm_kfree(ice_hw_to_dev(hw), node);
+ return -ENOMEM;
+--
+2.43.0
+
--- /dev/null
+From cc962e0f2acb2fbb394be46d69e316e002c4cf61 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 10 Sep 2024 07:39:03 +0300
+Subject: iomap: handle a post-direct I/O invalidate race in
+ iomap_write_delalloc_release
+
+From: Christoph Hellwig <hch@lst.de>
+
+[ Upstream commit 7a9d43eace888a0ee6095035997bb138425844d3 ]
+
+When direct I/O completions invalidates the page cache it holds neither the
+i_rwsem nor the invalidate_lock so it can be racing with
+iomap_write_delalloc_release. If the search for the end of the region that
+contains data returns the start offset we hit such a race and just need to
+look for the end of the newly created hole instead.
+
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Link: https://lore.kernel.org/r/20240910043949.3481298-2-hch@lst.de
+Reviewed-by: Darrick J. Wong <djwong@kernel.org>
+Signed-off-by: Christian Brauner <brauner@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/iomap/buffered-io.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c
+index e817564e80e01..b9b035a5e7793 100644
+--- a/fs/iomap/buffered-io.c
++++ b/fs/iomap/buffered-io.c
+@@ -1226,7 +1226,15 @@ static int iomap_write_delalloc_release(struct inode *inode,
+ error = data_end;
+ goto out_unlock;
+ }
+- WARN_ON_ONCE(data_end <= start_byte);
++
++ /*
++ * If we race with post-direct I/O invalidation of the page cache,
++ * there might be no data left at start_byte.
++ */
++ if (data_end == start_byte)
++ continue;
++
++ WARN_ON_ONCE(data_end < start_byte);
+ WARN_ON_ONCE(data_end > scan_end_byte);
+
+ error = iomap_write_delalloc_scan(inode, &punch_start_byte,
+--
+2.43.0
+
--- /dev/null
+From 506b47157936f2319779a4e56bea3fb8168799c5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 6 Sep 2024 12:47:52 -0300
+Subject: iommu/arm-smmu-v3: Do not use devm for the cd table allocations
+
+From: Jason Gunthorpe <jgg@nvidia.com>
+
+[ Upstream commit 47b2de35cab2b683f69d03515c2658c2d8515323 ]
+
+The master->cd_table is entirely contained within the struct
+arm_smmu_master which is guaranteed to be freed by the core code under
+arm_smmu_release_device().
+
+There is no reason to use devm here, arm_smmu_free_cd_tables() is reliably
+called to free the CD related memory. Remove it and save some memory.
+
+Tested-by: Nicolin Chen <nicolinc@nvidia.com>
+Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
+Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
+Link: https://lore.kernel.org/r/5-v4-6416877274e1+1af-smmuv3_tidy_jgg@nvidia.com
+Signed-off-by: Will Deacon <will@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 29 +++++++++------------
+ 1 file changed, 13 insertions(+), 16 deletions(-)
+
+diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+index 1f38669b711d3..a5425519fecb8 100644
+--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
++++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+@@ -1173,8 +1173,8 @@ static int arm_smmu_alloc_cd_leaf_table(struct arm_smmu_device *smmu,
+ {
+ size_t size = CTXDESC_L2_ENTRIES * (CTXDESC_CD_DWORDS << 3);
+
+- l1_desc->l2ptr = dmam_alloc_coherent(smmu->dev, size,
+- &l1_desc->l2ptr_dma, GFP_KERNEL);
++ l1_desc->l2ptr = dma_alloc_coherent(smmu->dev, size,
++ &l1_desc->l2ptr_dma, GFP_KERNEL);
+ if (!l1_desc->l2ptr) {
+ dev_warn(smmu->dev,
+ "failed to allocate context descriptor table\n");
+@@ -1373,17 +1373,17 @@ static int arm_smmu_alloc_cd_tables(struct arm_smmu_master *master)
+ cd_table->num_l1_ents = DIV_ROUND_UP(max_contexts,
+ CTXDESC_L2_ENTRIES);
+
+- cd_table->l1_desc = devm_kcalloc(smmu->dev, cd_table->num_l1_ents,
+- sizeof(*cd_table->l1_desc),
+- GFP_KERNEL);
++ cd_table->l1_desc = kcalloc(cd_table->num_l1_ents,
++ sizeof(*cd_table->l1_desc),
++ GFP_KERNEL);
+ if (!cd_table->l1_desc)
+ return -ENOMEM;
+
+ l1size = cd_table->num_l1_ents * (CTXDESC_L1_DESC_DWORDS << 3);
+ }
+
+- cd_table->cdtab = dmam_alloc_coherent(smmu->dev, l1size, &cd_table->cdtab_dma,
+- GFP_KERNEL);
++ cd_table->cdtab = dma_alloc_coherent(smmu->dev, l1size,
++ &cd_table->cdtab_dma, GFP_KERNEL);
+ if (!cd_table->cdtab) {
+ dev_warn(smmu->dev, "failed to allocate context descriptor\n");
+ ret = -ENOMEM;
+@@ -1394,7 +1394,7 @@ static int arm_smmu_alloc_cd_tables(struct arm_smmu_master *master)
+
+ err_free_l1:
+ if (cd_table->l1_desc) {
+- devm_kfree(smmu->dev, cd_table->l1_desc);
++ kfree(cd_table->l1_desc);
+ cd_table->l1_desc = NULL;
+ }
+ return ret;
+@@ -1414,21 +1414,18 @@ static void arm_smmu_free_cd_tables(struct arm_smmu_master *master)
+ if (!cd_table->l1_desc[i].l2ptr)
+ continue;
+
+- dmam_free_coherent(smmu->dev, size,
+- cd_table->l1_desc[i].l2ptr,
+- cd_table->l1_desc[i].l2ptr_dma);
++ dma_free_coherent(smmu->dev, size,
++ cd_table->l1_desc[i].l2ptr,
++ cd_table->l1_desc[i].l2ptr_dma);
+ }
+- devm_kfree(smmu->dev, cd_table->l1_desc);
+- cd_table->l1_desc = NULL;
++ kfree(cd_table->l1_desc);
+
+ l1size = cd_table->num_l1_ents * (CTXDESC_L1_DESC_DWORDS << 3);
+ } else {
+ l1size = cd_table->num_l1_ents * (CTXDESC_CD_DWORDS << 3);
+ }
+
+- dmam_free_coherent(smmu->dev, l1size, cd_table->cdtab, cd_table->cdtab_dma);
+- cd_table->cdtab_dma = 0;
+- cd_table->cdtab = NULL;
++ dma_free_coherent(smmu->dev, l1size, cd_table->cdtab, cd_table->cdtab_dma);
+ }
+
+ bool arm_smmu_free_asid(struct arm_smmu_ctx_desc *cd)
+--
+2.43.0
+
--- /dev/null
+From d09bc3b95c6a1bcae51e0a4f3e48c3561d0839e8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 30 Aug 2024 11:03:47 +0000
+Subject: iommu/arm-smmu-v3: Match Stall behaviour for S2
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Mostafa Saleh <smostafa@google.com>
+
+[ Upstream commit ce7cb08e22e09f43649b025c849a3ae3b80833c4 ]
+
+According to the spec (ARM IHI 0070 F.b), in
+"5.5 Fault configuration (A, R, S bits)":
+ A STE with stage 2 translation enabled and STE.S2S == 0 is
+ considered ILLEGAL if SMMU_IDR0.STALL_MODEL == 0b10.
+
+Also described in the pseudocode “SteIllegal()”
+ if STE.Config == '11x' then
+ [..]
+ if eff_idr0_stall_model == '10' && STE.S2S == '0' then
+ // stall_model forcing stall, but S2S == 0
+ return TRUE;
+
+Which means, S2S must be set when stall model is
+"ARM_SMMU_FEAT_STALL_FORCE", but currently the driver ignores that.
+
+Although, the driver can do the minimum and only set S2S for
+“ARM_SMMU_FEAT_STALL_FORCE”, it is more consistent to match S1
+behaviour, which also sets it for “ARM_SMMU_FEAT_STALL” if the
+master has requested stalls.
+
+Also, since S2 stalls are enabled now, report them to the IOMMU layer
+and for VFIO devices it will fail anyway as VFIO doesn’t register an
+iopf handler.
+
+Signed-off-by: Mostafa Saleh <smostafa@google.com>
+Link: https://lore.kernel.org/r/20240830110349.797399-2-smostafa@google.com
+Signed-off-by: Will Deacon <will@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 8 +++-----
+ drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 1 +
+ 2 files changed, 4 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+index f456bcf1890ba..1f38669b711d3 100644
+--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
++++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+@@ -1000,7 +1000,8 @@ void arm_smmu_get_ste_used(const __le64 *ent, __le64 *used_bits)
+ used_bits[2] |=
+ cpu_to_le64(STRTAB_STE_2_S2VMID | STRTAB_STE_2_VTCR |
+ STRTAB_STE_2_S2AA64 | STRTAB_STE_2_S2ENDI |
+- STRTAB_STE_2_S2PTW | STRTAB_STE_2_S2R);
++ STRTAB_STE_2_S2PTW | STRTAB_STE_2_S2S |
++ STRTAB_STE_2_S2R);
+ used_bits[3] |= cpu_to_le64(STRTAB_STE_3_S2TTB_MASK);
+ }
+
+@@ -1629,6 +1630,7 @@ void arm_smmu_make_s2_domain_ste(struct arm_smmu_ste *target,
+ STRTAB_STE_2_S2ENDI |
+ #endif
+ STRTAB_STE_2_S2PTW |
++ (master->stall_enabled ? STRTAB_STE_2_S2S : 0) |
+ STRTAB_STE_2_S2R);
+
+ target->data[3] = cpu_to_le64(pgtbl_cfg->arm_lpae_s2_cfg.vttbr &
+@@ -1722,10 +1724,6 @@ static int arm_smmu_handle_evt(struct arm_smmu_device *smmu, u64 *evt)
+ return -EOPNOTSUPP;
+ }
+
+- /* Stage-2 is always pinned at the moment */
+- if (evt[1] & EVTQ_1_S2)
+- return -EFAULT;
+-
+ if (!(evt[1] & EVTQ_1_STALL))
+ return -EOPNOTSUPP;
+
+diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+index 1242a086c9f94..d9c2f763eaba4 100644
+--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
++++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+@@ -264,6 +264,7 @@ struct arm_smmu_ste {
+ #define STRTAB_STE_2_S2AA64 (1UL << 51)
+ #define STRTAB_STE_2_S2ENDI (1UL << 52)
+ #define STRTAB_STE_2_S2PTW (1UL << 54)
++#define STRTAB_STE_2_S2S (1UL << 57)
+ #define STRTAB_STE_2_S2R (1UL << 58)
+
+ #define STRTAB_STE_3_S2TTB_MASK GENMASK_ULL(51, 4)
+--
+2.43.0
+
--- /dev/null
+From d4fb37fe391a28495b9b69288dcba5dcd69e7c74 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 2 Sep 2024 10:27:13 +0800
+Subject: iommu/vt-d: Always reserve a domain ID for identity setup
+
+From: Lu Baolu <baolu.lu@linux.intel.com>
+
+[ Upstream commit 2c13012e09190174614fd6901857a1b8c199e17d ]
+
+We will use a global static identity domain. Reserve a static domain ID
+for it.
+
+Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
+Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
+Reviewed-by: Kevin Tian <kevin.tian@intel.com>
+Reviewed-by: Jerry Snitselaar <jsnitsel@redhat.com>
+Link: https://lore.kernel.org/r/20240809055431.36513-4-baolu.lu@linux.intel.com
+Signed-off-by: Joerg Roedel <jroedel@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iommu/intel/iommu.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
+index e9bea0305c268..eed67326976d3 100644
+--- a/drivers/iommu/intel/iommu.c
++++ b/drivers/iommu/intel/iommu.c
+@@ -1462,10 +1462,10 @@ static int iommu_init_domains(struct intel_iommu *iommu)
+ * entry for first-level or pass-through translation modes should
+ * be programmed with a domain id different from those used for
+ * second-level or nested translation. We reserve a domain id for
+- * this purpose.
++ * this purpose. This domain id is also used for identity domain
++ * in legacy mode.
+ */
+- if (sm_supported(iommu))
+- set_bit(FLPT_DEFAULT_DID, iommu->domain_ids);
++ set_bit(FLPT_DEFAULT_DID, iommu->domain_ids);
+
+ return 0;
+ }
+--
+2.43.0
+
--- /dev/null
+From fa7afc980c224a064fab1c9b906f095eb1a82bb2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 2 Sep 2024 10:27:18 +0800
+Subject: iommu/vt-d: Fix potential lockup if qi_submit_sync called with 0
+ count
+
+From: Sanjay K Kumar <sanjay.k.kumar@intel.com>
+
+[ Upstream commit 3cf74230c139f208b7fb313ae0054386eee31a81 ]
+
+If qi_submit_sync() is invoked with 0 invalidation descriptors (for
+instance, for DMA draining purposes), we can run into a bug where a
+submitting thread fails to detect the completion of invalidation_wait.
+Subsequently, this led to a soft lockup. Currently, there is no impact
+by this bug on the existing users because no callers are submitting
+invalidations with 0 descriptors. This fix will enable future users
+(such as DMA drain) calling qi_submit_sync() with 0 count.
+
+Suppose thread T1 invokes qi_submit_sync() with non-zero descriptors, while
+concurrently, thread T2 calls qi_submit_sync() with zero descriptors. Both
+threads then enter a while loop, waiting for their respective descriptors
+to complete. T1 detects its completion (i.e., T1's invalidation_wait status
+changes to QI_DONE by HW) and proceeds to call reclaim_free_desc() to
+reclaim all descriptors, potentially including adjacent ones of other
+threads that are also marked as QI_DONE.
+
+During this time, while T2 is waiting to acquire the qi->q_lock, the IOMMU
+hardware may complete the invalidation for T2, setting its status to
+QI_DONE. However, if T1's execution of reclaim_free_desc() frees T2's
+invalidation_wait descriptor and changes its status to QI_FREE, T2 will
+not observe the QI_DONE status for its invalidation_wait and will
+indefinitely remain stuck.
+
+This soft lockup does not occur when only non-zero descriptors are
+submitted.In such cases, invalidation descriptors are interspersed among
+wait descriptors with the status QI_IN_USE, acting as barriers. These
+barriers prevent the reclaim code from mistakenly freeing descriptors
+belonging to other submitters.
+
+Considered the following example timeline:
+ T1 T2
+========================================
+ ID1
+ WD1
+ while(WD1!=QI_DONE)
+ unlock
+ lock
+ WD1=QI_DONE* WD2
+ while(WD2!=QI_DONE)
+ unlock
+ lock
+ WD1==QI_DONE?
+ ID1=QI_DONE WD2=DONE*
+ reclaim()
+ ID1=FREE
+ WD1=FREE
+ WD2=FREE
+ unlock
+ soft lockup! T2 never sees QI_DONE in WD2
+
+Where:
+ID = invalidation descriptor
+WD = wait descriptor
+* Written by hardware
+
+The root of the problem is that the descriptor status QI_DONE flag is used
+for two conflicting purposes:
+1. signal a descriptor is ready for reclaim (to be freed)
+2. signal by the hardware that a wait descriptor is complete
+
+The solution (in this patch) is state separation by using QI_FREE flag
+for #1.
+
+Once a thread's invalidation descriptors are complete, their status would
+be set to QI_FREE. The reclaim_free_desc() function would then only
+free descriptors marked as QI_FREE instead of those marked as
+QI_DONE. This change ensures that T2 (from the previous example) will
+correctly observe the completion of its invalidation_wait (marked as
+QI_DONE).
+
+Signed-off-by: Sanjay K Kumar <sanjay.k.kumar@intel.com>
+Signed-off-by: Jacob Pan <jacob.jun.pan@linux.intel.com>
+Reviewed-by: Kevin Tian <kevin.tian@intel.com>
+Link: https://lore.kernel.org/r/20240728210059.1964602-1-jacob.jun.pan@linux.intel.com
+Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
+Signed-off-by: Joerg Roedel <jroedel@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iommu/intel/dmar.c | 16 +++++++++++-----
+ 1 file changed, 11 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/iommu/intel/dmar.c b/drivers/iommu/intel/dmar.c
+index 1c8d3141cb55c..01e157d89a163 100644
+--- a/drivers/iommu/intel/dmar.c
++++ b/drivers/iommu/intel/dmar.c
+@@ -1204,9 +1204,7 @@ static void free_iommu(struct intel_iommu *iommu)
+ */
+ static inline void reclaim_free_desc(struct q_inval *qi)
+ {
+- while (qi->desc_status[qi->free_tail] == QI_DONE ||
+- qi->desc_status[qi->free_tail] == QI_ABORT) {
+- qi->desc_status[qi->free_tail] = QI_FREE;
++ while (qi->desc_status[qi->free_tail] == QI_FREE && qi->free_tail != qi->free_head) {
+ qi->free_tail = (qi->free_tail + 1) % QI_LENGTH;
+ qi->free_cnt++;
+ }
+@@ -1463,8 +1461,16 @@ int qi_submit_sync(struct intel_iommu *iommu, struct qi_desc *desc,
+ raw_spin_lock(&qi->q_lock);
+ }
+
+- for (i = 0; i < count; i++)
+- qi->desc_status[(index + i) % QI_LENGTH] = QI_DONE;
++ /*
++ * The reclaim code can free descriptors from multiple submissions
++ * starting from the tail of the queue. When count == 0, the
++ * status of the standalone wait descriptor at the tail of the queue
++ * must be set to QI_FREE to allow the reclaim code to proceed.
++ * It is also possible that descriptors from one of the previous
++ * submissions has to be reclaimed by a subsequent submission.
++ */
++ for (i = 0; i <= count; i++)
++ qi->desc_status[(index + i) % QI_LENGTH] = QI_FREE;
+
+ reclaim_free_desc(qi);
+ raw_spin_unlock_irqrestore(&qi->q_lock, flags);
+--
+2.43.0
+
--- /dev/null
+From 650f16adf17f37178fd7a66be0448d0f57232896 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 2 Sep 2024 10:27:20 +0800
+Subject: iommu/vt-d: Unconditionally flush device TLB for pasid table updates
+
+From: Lu Baolu <baolu.lu@linux.intel.com>
+
+[ Upstream commit 1f5e307ca16c0c19186cbd56ac460a687e6daba0 ]
+
+The caching mode of an IOMMU is irrelevant to the behavior of the device
+TLB. Previously, commit <304b3bde24b5> ("iommu/vt-d: Remove caching mode
+check before device TLB flush") removed this redundant check in the
+domain unmap path.
+
+Checking the caching mode before flushing the device TLB after a pasid
+table entry is updated is unnecessary and can lead to inconsistent
+behavior.
+
+Extends this consistency by removing the caching mode check in the pasid
+table update path.
+
+Suggested-by: Yi Liu <yi.l.liu@intel.com>
+Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
+Link: https://lore.kernel.org/r/20240820030208.20020-1-baolu.lu@linux.intel.com
+Signed-off-by: Joerg Roedel <jroedel@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iommu/intel/pasid.c | 12 +++---------
+ 1 file changed, 3 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c
+index aabcdf7565817..57dd3530f68d4 100644
+--- a/drivers/iommu/intel/pasid.c
++++ b/drivers/iommu/intel/pasid.c
+@@ -261,9 +261,7 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
+ else
+ iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH);
+
+- /* Device IOTLB doesn't need to be flushed in caching mode. */
+- if (!cap_caching_mode(iommu->cap))
+- devtlb_invalidation_with_pasid(iommu, dev, pasid);
++ devtlb_invalidation_with_pasid(iommu, dev, pasid);
+ }
+
+ /*
+@@ -490,9 +488,7 @@ int intel_pasid_setup_dirty_tracking(struct intel_iommu *iommu,
+
+ iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH);
+
+- /* Device IOTLB doesn't need to be flushed in caching mode. */
+- if (!cap_caching_mode(iommu->cap))
+- devtlb_invalidation_with_pasid(iommu, dev, pasid);
++ devtlb_invalidation_with_pasid(iommu, dev, pasid);
+
+ return 0;
+ }
+@@ -569,9 +565,7 @@ void intel_pasid_setup_page_snoop_control(struct intel_iommu *iommu,
+ pasid_cache_invalidation_with_pasid(iommu, did, pasid);
+ qi_flush_piotlb(iommu, did, pasid, 0, -1, 0);
+
+- /* Device IOTLB doesn't need to be flushed in caching mode. */
+- if (!cap_caching_mode(iommu->cap))
+- devtlb_invalidation_with_pasid(iommu, dev, pasid);
++ devtlb_invalidation_with_pasid(iommu, dev, pasid);
+ }
+
+ /**
+--
+2.43.0
+
--- /dev/null
+From d1700d76af7f427e715be75551db719a5090102f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 9 Aug 2024 16:54:02 -0700
+Subject: ipv4: Check !in_dev earlier for ioctl(SIOCSIFADDR).
+
+From: Kuniyuki Iwashima <kuniyu@amazon.com>
+
+[ Upstream commit e3af3d3c5b26c33a7950e34e137584f6056c4319 ]
+
+dev->ip_ptr could be NULL if we set an invalid MTU.
+
+Even then, if we issue ioctl(SIOCSIFADDR) for a new IPv4 address,
+devinet_ioctl() allocates struct in_ifaddr and fails later in
+inet_set_ifa() because in_dev is NULL.
+
+Let's move the check earlier.
+
+Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Link: https://patch.msgid.link/20240809235406.50187-2-kuniyu@amazon.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/devinet.c | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
+index d09f557eaa779..73effd2d2994a 100644
+--- a/net/ipv4/devinet.c
++++ b/net/ipv4/devinet.c
+@@ -574,10 +574,6 @@ static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
+
+ ASSERT_RTNL();
+
+- if (!in_dev) {
+- inet_free_ifa(ifa);
+- return -ENOBUFS;
+- }
+ ipv4_devconf_setall(in_dev);
+ neigh_parms_data_state_setall(in_dev->arp_parms);
+ if (ifa->ifa_dev != in_dev) {
+@@ -1184,6 +1180,8 @@ int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr)
+
+ if (!ifa) {
+ ret = -ENOBUFS;
++ if (!in_dev)
++ break;
+ ifa = inet_alloc_ifa();
+ if (!ifa)
+ break;
+--
+2.43.0
+
--- /dev/null
+From b2409888d74e3c40100804867972aac8a9626697 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 14 Aug 2024 15:52:22 +0300
+Subject: ipv4: Mask upper DSCP bits and ECN bits in NETLINK_FIB_LOOKUP family
+
+From: Ido Schimmel <idosch@nvidia.com>
+
+[ Upstream commit 8fed54758cd248cd311a2b5c1e180abef1866237 ]
+
+The NETLINK_FIB_LOOKUP netlink family can be used to perform a FIB
+lookup according to user provided parameters and communicate the result
+back to user space.
+
+However, unlike other users of the FIB lookup API, the upper DSCP bits
+and the ECN bits of the DS field are not masked, which can result in the
+wrong result being returned.
+
+Solve this by masking the upper DSCP bits and the ECN bits using
+IPTOS_RT_MASK.
+
+The structure that communicates the request and the response is not
+exported to user space, so it is unlikely that this netlink family is
+actually in use [1].
+
+[1] https://lore.kernel.org/netdev/ZpqpB8vJU%2FQ6LSqa@debian/
+
+Signed-off-by: Ido Schimmel <idosch@nvidia.com>
+Reviewed-by: Guillaume Nault <gnault@redhat.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/fib_frontend.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
+index 7ad2cafb92763..da540ddb7af65 100644
+--- a/net/ipv4/fib_frontend.c
++++ b/net/ipv4/fib_frontend.c
+@@ -1343,7 +1343,7 @@ static void nl_fib_lookup(struct net *net, struct fib_result_nl *frn)
+ struct flowi4 fl4 = {
+ .flowi4_mark = frn->fl_mark,
+ .daddr = frn->fl_addr,
+- .flowi4_tos = frn->fl_tos,
++ .flowi4_tos = frn->fl_tos & IPTOS_RT_MASK,
+ .flowi4_scope = frn->fl_scope,
+ };
+ struct fib_table *tb;
+--
+2.43.0
+
--- /dev/null
+From ed3814699d296976778712cef1bd3ca3406d88bd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 24 Aug 2024 09:25:23 +0800
+Subject: jfs: check if leafidx greater than num leaves per dmap tree
+
+From: Edward Adam Davis <eadavis@qq.com>
+
+[ Upstream commit d64ff0d2306713ff084d4b09f84ed1a8c75ecc32 ]
+
+syzbot report a out of bounds in dbSplit, it because dmt_leafidx greater
+than num leaves per dmap tree, add a checking for dmt_leafidx in dbFindLeaf.
+
+Shaggy:
+Modified sanity check to apply to control pages as well as leaf pages.
+
+Reported-and-tested-by: syzbot+dca05492eff41f604890@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=dca05492eff41f604890
+Signed-off-by: Edward Adam Davis <eadavis@qq.com>
+Signed-off-by: Dave Kleikamp <dave.kleikamp@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/jfs/jfs_dmap.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c
+index 8847e8c5d5b45..974ecf5e0d952 100644
+--- a/fs/jfs/jfs_dmap.c
++++ b/fs/jfs/jfs_dmap.c
+@@ -2944,9 +2944,10 @@ static void dbAdjTree(dmtree_t *tp, int leafno, int newval, bool is_ctl)
+ static int dbFindLeaf(dmtree_t *tp, int l2nb, int *leafidx, bool is_ctl)
+ {
+ int ti, n = 0, k, x = 0;
+- int max_size;
++ int max_size, max_idx;
+
+ max_size = is_ctl ? CTLTREESIZE : TREESIZE;
++ max_idx = is_ctl ? LPERCTL : LPERDMAP;
+
+ /* first check the root of the tree to see if there is
+ * sufficient free space.
+@@ -2978,6 +2979,8 @@ static int dbFindLeaf(dmtree_t *tp, int l2nb, int *leafidx, bool is_ctl)
+ */
+ assert(n < 4);
+ }
++ if (le32_to_cpu(tp->dmt_leafidx) >= max_idx)
++ return -ENOSPC;
+
+ /* set the return to the leftmost leaf describing sufficient
+ * free space.
+--
+2.43.0
+
--- /dev/null
+From 9a08cd131f6f2a683c63f3a64af7609874c60460 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 24 Aug 2024 10:50:48 +0800
+Subject: jfs: Fix uaf in dbFreeBits
+
+From: Edward Adam Davis <eadavis@qq.com>
+
+[ Upstream commit d6c1b3599b2feb5c7291f5ac3a36e5fa7cedb234 ]
+
+[syzbot reported]
+==================================================================
+BUG: KASAN: slab-use-after-free in __mutex_lock_common kernel/locking/mutex.c:587 [inline]
+BUG: KASAN: slab-use-after-free in __mutex_lock+0xfe/0xd70 kernel/locking/mutex.c:752
+Read of size 8 at addr ffff8880229254b0 by task syz-executor357/5216
+
+CPU: 0 UID: 0 PID: 5216 Comm: syz-executor357 Not tainted 6.11.0-rc3-syzkaller-00156-gd7a5aa4b3c00 #0
+Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 06/27/2024
+Call Trace:
+ <TASK>
+ __dump_stack lib/dump_stack.c:93 [inline]
+ dump_stack_lvl+0x241/0x360 lib/dump_stack.c:119
+ print_address_description mm/kasan/report.c:377 [inline]
+ print_report+0x169/0x550 mm/kasan/report.c:488
+ kasan_report+0x143/0x180 mm/kasan/report.c:601
+ __mutex_lock_common kernel/locking/mutex.c:587 [inline]
+ __mutex_lock+0xfe/0xd70 kernel/locking/mutex.c:752
+ dbFreeBits+0x7ea/0xd90 fs/jfs/jfs_dmap.c:2390
+ dbFreeDmap fs/jfs/jfs_dmap.c:2089 [inline]
+ dbFree+0x35b/0x680 fs/jfs/jfs_dmap.c:409
+ dbDiscardAG+0x8a9/0xa20 fs/jfs/jfs_dmap.c:1650
+ jfs_ioc_trim+0x433/0x670 fs/jfs/jfs_discard.c:100
+ jfs_ioctl+0x2d0/0x3e0 fs/jfs/ioctl.c:131
+ vfs_ioctl fs/ioctl.c:51 [inline]
+ __do_sys_ioctl fs/ioctl.c:907 [inline]
+ __se_sys_ioctl+0xfc/0x170 fs/ioctl.c:893
+ do_syscall_x64 arch/x86/entry/common.c:52 [inline]
+ do_syscall_64+0xf3/0x230 arch/x86/entry/common.c:83
+
+Freed by task 5218:
+ kasan_save_stack mm/kasan/common.c:47 [inline]
+ kasan_save_track+0x3f/0x80 mm/kasan/common.c:68
+ kasan_save_free_info+0x40/0x50 mm/kasan/generic.c:579
+ poison_slab_object+0xe0/0x150 mm/kasan/common.c:240
+ __kasan_slab_free+0x37/0x60 mm/kasan/common.c:256
+ kasan_slab_free include/linux/kasan.h:184 [inline]
+ slab_free_hook mm/slub.c:2252 [inline]
+ slab_free mm/slub.c:4473 [inline]
+ kfree+0x149/0x360 mm/slub.c:4594
+ dbUnmount+0x11d/0x190 fs/jfs/jfs_dmap.c:278
+ jfs_mount_rw+0x4ac/0x6a0 fs/jfs/jfs_mount.c:247
+ jfs_remount+0x3d1/0x6b0 fs/jfs/super.c:454
+ reconfigure_super+0x445/0x880 fs/super.c:1083
+ vfs_cmd_reconfigure fs/fsopen.c:263 [inline]
+ vfs_fsconfig_locked fs/fsopen.c:292 [inline]
+ __do_sys_fsconfig fs/fsopen.c:473 [inline]
+ __se_sys_fsconfig+0xb6e/0xf80 fs/fsopen.c:345
+ do_syscall_x64 arch/x86/entry/common.c:52 [inline]
+ do_syscall_64+0xf3/0x230 arch/x86/entry/common.c:83
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+
+[Analysis]
+There are two paths (dbUnmount and jfs_ioc_trim) that generate race
+condition when accessing bmap, which leads to the occurrence of uaf.
+
+Use the lock s_umount to synchronize them, in order to avoid uaf caused
+by race condition.
+
+Reported-and-tested-by: syzbot+3c010e21296f33a5dc16@syzkaller.appspotmail.com
+Signed-off-by: Edward Adam Davis <eadavis@qq.com>
+Signed-off-by: Dave Kleikamp <dave.kleikamp@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/jfs/jfs_discard.c | 11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+diff --git a/fs/jfs/jfs_discard.c b/fs/jfs/jfs_discard.c
+index 575cb2ba74fc8..5f4b305030ad5 100644
+--- a/fs/jfs/jfs_discard.c
++++ b/fs/jfs/jfs_discard.c
+@@ -65,7 +65,7 @@ void jfs_issue_discard(struct inode *ip, u64 blkno, u64 nblocks)
+ int jfs_ioc_trim(struct inode *ip, struct fstrim_range *range)
+ {
+ struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
+- struct bmap *bmp = JFS_SBI(ip->i_sb)->bmap;
++ struct bmap *bmp;
+ struct super_block *sb = ipbmap->i_sb;
+ int agno, agno_end;
+ u64 start, end, minlen;
+@@ -83,10 +83,15 @@ int jfs_ioc_trim(struct inode *ip, struct fstrim_range *range)
+ if (minlen == 0)
+ minlen = 1;
+
++ down_read(&sb->s_umount);
++ bmp = JFS_SBI(ip->i_sb)->bmap;
++
+ if (minlen > bmp->db_agsize ||
+ start >= bmp->db_mapsize ||
+- range->len < sb->s_blocksize)
++ range->len < sb->s_blocksize) {
++ up_read(&sb->s_umount);
+ return -EINVAL;
++ }
+
+ if (end >= bmp->db_mapsize)
+ end = bmp->db_mapsize - 1;
+@@ -100,6 +105,8 @@ int jfs_ioc_trim(struct inode *ip, struct fstrim_range *range)
+ trimmed += dbDiscardAG(ip, agno, minlen);
+ agno++;
+ }
++
++ up_read(&sb->s_umount);
+ range->len = trimmed << sb->s_blocksize_bits;
+
+ return 0;
+--
+2.43.0
+
--- /dev/null
+From 4e3bdbb5e4b491c34e070d8fbf2bf312873854d9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 4 Sep 2024 09:07:58 +0800
+Subject: jfs: Fix uninit-value access of new_ea in ea_buffer
+
+From: Zhao Mengmeng <zhaomengmeng@kylinos.cn>
+
+[ Upstream commit 2b59ffad47db1c46af25ccad157bb3b25147c35c ]
+
+syzbot reports that lzo1x_1_do_compress is using uninit-value:
+
+=====================================================
+BUG: KMSAN: uninit-value in lzo1x_1_do_compress+0x19f9/0x2510 lib/lzo/lzo1x_compress.c:178
+
+...
+
+Uninit was stored to memory at:
+ ea_put fs/jfs/xattr.c:639 [inline]
+
+...
+
+Local variable ea_buf created at:
+ __jfs_setxattr+0x5d/0x1ae0 fs/jfs/xattr.c:662
+ __jfs_xattr_set+0xe6/0x1f0 fs/jfs/xattr.c:934
+
+=====================================================
+
+The reason is ea_buf->new_ea is not initialized properly.
+
+Fix this by using memset to empty its content at the beginning
+in ea_get().
+
+Reported-by: syzbot+02341e0daa42a15ce130@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=02341e0daa42a15ce130
+Signed-off-by: Zhao Mengmeng <zhaomengmeng@kylinos.cn>
+Signed-off-by: Dave Kleikamp <dave.kleikamp@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/jfs/xattr.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c
+index 2999ed5d83f5e..0fb05e314edf6 100644
+--- a/fs/jfs/xattr.c
++++ b/fs/jfs/xattr.c
+@@ -434,6 +434,8 @@ static int ea_get(struct inode *inode, struct ea_buffer *ea_buf, int min_size)
+ int rc;
+ int quota_allocation = 0;
+
++ memset(&ea_buf->new_ea, 0, sizeof(ea_buf->new_ea));
++
+ /* When fsck.jfs clears a bad ea, it doesn't clear the size */
+ if (ji->ea.flag == 0)
+ ea_size = 0;
+--
+2.43.0
+
--- /dev/null
+From 3b066e418e9284399e809109e7755d49a917e473 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 10 Jul 2024 00:12:44 +0000
+Subject: jfs: UBSAN: shift-out-of-bounds in dbFindBits
+
+From: Remington Brasga <rbrasga@uci.edu>
+
+[ Upstream commit b0b2fc815e514221f01384f39fbfbff65d897e1c ]
+
+Fix issue with UBSAN throwing shift-out-of-bounds warning.
+
+Reported-by: syzbot+e38d703eeb410b17b473@syzkaller.appspotmail.com
+Signed-off-by: Remington Brasga <rbrasga@uci.edu>
+Signed-off-by: Dave Kleikamp <dave.kleikamp@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/jfs/jfs_dmap.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c
+index 0625d1c0d0649..8847e8c5d5b45 100644
+--- a/fs/jfs/jfs_dmap.c
++++ b/fs/jfs/jfs_dmap.c
+@@ -3022,7 +3022,7 @@ static int dbFindBits(u32 word, int l2nb)
+
+ /* scan the word for nb free bits at nb alignments.
+ */
+- for (bitno = 0; mask != 0; bitno += nb, mask >>= nb) {
++ for (bitno = 0; mask != 0; bitno += nb, mask = (mask >> nb)) {
+ if ((mask & word) == mask)
+ break;
+ }
+--
+2.43.0
+
--- /dev/null
+From ed22f4a307562dc43b055644a9cf43cbc19f0430 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Sep 2024 20:28:08 +0900
+Subject: ksmbd: add refcnt to ksmbd_conn struct
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit ee426bfb9d09b29987369b897fe9b6485ac2be27 ]
+
+When sending an oplock break request, opinfo->conn is used,
+But freed ->conn can be used on multichannel.
+This patch add a reference count to the ksmbd_conn struct
+so that it can be freed when it is no longer used.
+
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/connection.c | 4 ++-
+ fs/smb/server/connection.h | 1 +
+ fs/smb/server/oplock.c | 55 +++++++++++---------------------------
+ fs/smb/server/vfs_cache.c | 3 +++
+ 4 files changed, 23 insertions(+), 40 deletions(-)
+
+diff --git a/fs/smb/server/connection.c b/fs/smb/server/connection.c
+index 7889df8112b4e..cac80e7bfefc7 100644
+--- a/fs/smb/server/connection.c
++++ b/fs/smb/server/connection.c
+@@ -39,7 +39,8 @@ void ksmbd_conn_free(struct ksmbd_conn *conn)
+ xa_destroy(&conn->sessions);
+ kvfree(conn->request_buf);
+ kfree(conn->preauth_info);
+- kfree(conn);
++ if (atomic_dec_and_test(&conn->refcnt))
++ kfree(conn);
+ }
+
+ /**
+@@ -68,6 +69,7 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)
+ conn->um = NULL;
+ atomic_set(&conn->req_running, 0);
+ atomic_set(&conn->r_count, 0);
++ atomic_set(&conn->refcnt, 1);
+ conn->total_credits = 1;
+ conn->outstanding_credits = 0;
+
+diff --git a/fs/smb/server/connection.h b/fs/smb/server/connection.h
+index b93e5437793e0..82343afc8d049 100644
+--- a/fs/smb/server/connection.h
++++ b/fs/smb/server/connection.h
+@@ -106,6 +106,7 @@ struct ksmbd_conn {
+ bool signing_negotiated;
+ __le16 signing_algorithm;
+ bool binding;
++ atomic_t refcnt;
+ };
+
+ struct ksmbd_conn_ops {
+diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c
+index e546ffa57b55a..8ee86478287f9 100644
+--- a/fs/smb/server/oplock.c
++++ b/fs/smb/server/oplock.c
+@@ -51,6 +51,7 @@ static struct oplock_info *alloc_opinfo(struct ksmbd_work *work,
+ init_waitqueue_head(&opinfo->oplock_brk);
+ atomic_set(&opinfo->refcount, 1);
+ atomic_set(&opinfo->breaking_cnt, 0);
++ atomic_inc(&opinfo->conn->refcnt);
+
+ return opinfo;
+ }
+@@ -124,6 +125,8 @@ static void free_opinfo(struct oplock_info *opinfo)
+ {
+ if (opinfo->is_lease)
+ free_lease(opinfo);
++ if (opinfo->conn && atomic_dec_and_test(&opinfo->conn->refcnt))
++ kfree(opinfo->conn);
+ kfree(opinfo);
+ }
+
+@@ -163,9 +166,7 @@ static struct oplock_info *opinfo_get_list(struct ksmbd_inode *ci)
+ !atomic_inc_not_zero(&opinfo->refcount))
+ opinfo = NULL;
+ else {
+- atomic_inc(&opinfo->conn->r_count);
+ if (ksmbd_conn_releasing(opinfo->conn)) {
+- atomic_dec(&opinfo->conn->r_count);
+ atomic_dec(&opinfo->refcount);
+ opinfo = NULL;
+ }
+@@ -177,26 +178,11 @@ static struct oplock_info *opinfo_get_list(struct ksmbd_inode *ci)
+ return opinfo;
+ }
+
+-static void opinfo_conn_put(struct oplock_info *opinfo)
++void opinfo_put(struct oplock_info *opinfo)
+ {
+- struct ksmbd_conn *conn;
+-
+ if (!opinfo)
+ return;
+
+- conn = opinfo->conn;
+- /*
+- * Checking waitqueue to dropping pending requests on
+- * disconnection. waitqueue_active is safe because it
+- * uses atomic operation for condition.
+- */
+- if (!atomic_dec_return(&conn->r_count) && waitqueue_active(&conn->r_count_q))
+- wake_up(&conn->r_count_q);
+- opinfo_put(opinfo);
+-}
+-
+-void opinfo_put(struct oplock_info *opinfo)
+-{
+ if (!atomic_dec_and_test(&opinfo->refcount))
+ return;
+
+@@ -1127,14 +1113,11 @@ void smb_send_parent_lease_break_noti(struct ksmbd_file *fp,
+ if (!atomic_inc_not_zero(&opinfo->refcount))
+ continue;
+
+- atomic_inc(&opinfo->conn->r_count);
+- if (ksmbd_conn_releasing(opinfo->conn)) {
+- atomic_dec(&opinfo->conn->r_count);
++ if (ksmbd_conn_releasing(opinfo->conn))
+ continue;
+- }
+
+ oplock_break(opinfo, SMB2_OPLOCK_LEVEL_NONE);
+- opinfo_conn_put(opinfo);
++ opinfo_put(opinfo);
+ }
+ }
+ up_read(&p_ci->m_lock);
+@@ -1167,13 +1150,10 @@ void smb_lazy_parent_lease_break_close(struct ksmbd_file *fp)
+ if (!atomic_inc_not_zero(&opinfo->refcount))
+ continue;
+
+- atomic_inc(&opinfo->conn->r_count);
+- if (ksmbd_conn_releasing(opinfo->conn)) {
+- atomic_dec(&opinfo->conn->r_count);
++ if (ksmbd_conn_releasing(opinfo->conn))
+ continue;
+- }
+ oplock_break(opinfo, SMB2_OPLOCK_LEVEL_NONE);
+- opinfo_conn_put(opinfo);
++ opinfo_put(opinfo);
+ }
+ }
+ up_read(&p_ci->m_lock);
+@@ -1252,7 +1232,7 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid,
+ prev_opinfo = opinfo_get_list(ci);
+ if (!prev_opinfo ||
+ (prev_opinfo->level == SMB2_OPLOCK_LEVEL_NONE && lctx)) {
+- opinfo_conn_put(prev_opinfo);
++ opinfo_put(prev_opinfo);
+ goto set_lev;
+ }
+ prev_op_has_lease = prev_opinfo->is_lease;
+@@ -1262,19 +1242,19 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid,
+ if (share_ret < 0 &&
+ prev_opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
+ err = share_ret;
+- opinfo_conn_put(prev_opinfo);
++ opinfo_put(prev_opinfo);
+ goto err_out;
+ }
+
+ if (prev_opinfo->level != SMB2_OPLOCK_LEVEL_BATCH &&
+ prev_opinfo->level != SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
+- opinfo_conn_put(prev_opinfo);
++ opinfo_put(prev_opinfo);
+ goto op_break_not_needed;
+ }
+
+ list_add(&work->interim_entry, &prev_opinfo->interim_list);
+ err = oplock_break(prev_opinfo, SMB2_OPLOCK_LEVEL_II);
+- opinfo_conn_put(prev_opinfo);
++ opinfo_put(prev_opinfo);
+ if (err == -ENOENT)
+ goto set_lev;
+ /* Check all oplock was freed by close */
+@@ -1337,14 +1317,14 @@ static void smb_break_all_write_oplock(struct ksmbd_work *work,
+ return;
+ if (brk_opinfo->level != SMB2_OPLOCK_LEVEL_BATCH &&
+ brk_opinfo->level != SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
+- opinfo_conn_put(brk_opinfo);
++ opinfo_put(brk_opinfo);
+ return;
+ }
+
+ brk_opinfo->open_trunc = is_trunc;
+ list_add(&work->interim_entry, &brk_opinfo->interim_list);
+ oplock_break(brk_opinfo, SMB2_OPLOCK_LEVEL_II);
+- opinfo_conn_put(brk_opinfo);
++ opinfo_put(brk_opinfo);
+ }
+
+ /**
+@@ -1376,11 +1356,8 @@ void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp,
+ if (!atomic_inc_not_zero(&brk_op->refcount))
+ continue;
+
+- atomic_inc(&brk_op->conn->r_count);
+- if (ksmbd_conn_releasing(brk_op->conn)) {
+- atomic_dec(&brk_op->conn->r_count);
++ if (ksmbd_conn_releasing(brk_op->conn))
+ continue;
+- }
+
+ rcu_read_unlock();
+ if (brk_op->is_lease && (brk_op->o_lease->state &
+@@ -1411,7 +1388,7 @@ void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp,
+ brk_op->open_trunc = is_trunc;
+ oplock_break(brk_op, SMB2_OPLOCK_LEVEL_NONE);
+ next:
+- opinfo_conn_put(brk_op);
++ opinfo_put(brk_op);
+ rcu_read_lock();
+ }
+ rcu_read_unlock();
+diff --git a/fs/smb/server/vfs_cache.c b/fs/smb/server/vfs_cache.c
+index 8b2e37c8716ed..271a23abc82fd 100644
+--- a/fs/smb/server/vfs_cache.c
++++ b/fs/smb/server/vfs_cache.c
+@@ -710,6 +710,8 @@ static bool session_fd_check(struct ksmbd_tree_connect *tcon,
+ list_for_each_entry_rcu(op, &ci->m_op_list, op_entry) {
+ if (op->conn != conn)
+ continue;
++ if (op->conn && atomic_dec_and_test(&op->conn->refcnt))
++ kfree(op->conn);
+ op->conn = NULL;
+ }
+ up_write(&ci->m_lock);
+@@ -807,6 +809,7 @@ int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp)
+ if (op->conn)
+ continue;
+ op->conn = fp->conn;
++ atomic_inc(&op->conn->refcnt);
+ }
+ up_write(&ci->m_lock);
+
+--
+2.43.0
+
--- /dev/null
+From 690a4340619cd10677a3173e5ded384a4f68e11f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 21 Aug 2024 16:58:57 +0100
+Subject: net: atlantic: Avoid warning about potential string truncation
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Simon Horman <horms@kernel.org>
+
+[ Upstream commit 5874e0c9f25661c2faefe4809907166defae3d7f ]
+
+W=1 builds with GCC 14.2.0 warn that:
+
+.../aq_ethtool.c:278:59: warning: ‘%d’ directive output may be truncated writing between 1 and 11 bytes into a region of size 6 [-Wformat-truncation=]
+ 278 | snprintf(tc_string, 8, "TC%d ", tc);
+ | ^~
+.../aq_ethtool.c:278:56: note: directive argument in the range [-2147483641, 254]
+ 278 | snprintf(tc_string, 8, "TC%d ", tc);
+ | ^~~~~~~
+.../aq_ethtool.c:278:33: note: ‘snprintf’ output between 5 and 15 bytes into a destination of size 8
+ 278 | snprintf(tc_string, 8, "TC%d ", tc);
+ | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+tc is always in the range 0 - cfg->tcs. And as cfg->tcs is a u8,
+the range is 0 - 255. Further, on inspecting the code, it seems
+that cfg->tcs will never be more than AQ_CFG_TCS_MAX (8), so
+the range is actually 0 - 8.
+
+So, it seems that the condition that GCC flags will not occur.
+But, nonetheless, it would be nice if it didn't emit the warning.
+
+It seems that this can be achieved by changing the format specifier
+from %d to %u, in which case I believe GCC recognises an upper bound
+on the range of tc of 0 - 255. After some experimentation I think
+this is due to the combination of the use of %u and the type of
+cfg->tcs (u8).
+
+Empirically, updating the type of the tc variable to unsigned int
+has the same effect.
+
+As both of these changes seem to make sense in relation to what the code
+is actually doing - iterating over unsigned values - do both.
+
+Compile tested only.
+
+Signed-off-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20240821-atlantic-str-v1-1-fa2cfe38ca00@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
+index a2606ee3b0a56..cfc413caf93f4 100644
+--- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
++++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
+@@ -266,7 +266,7 @@ static void aq_ethtool_get_strings(struct net_device *ndev,
+ const int rx_stat_cnt = ARRAY_SIZE(aq_ethtool_queue_rx_stat_names);
+ const int tx_stat_cnt = ARRAY_SIZE(aq_ethtool_queue_tx_stat_names);
+ char tc_string[8];
+- int tc;
++ unsigned int tc;
+
+ memset(tc_string, 0, sizeof(tc_string));
+ memcpy(p, aq_ethtool_stat_names,
+@@ -275,7 +275,7 @@ static void aq_ethtool_get_strings(struct net_device *ndev,
+
+ for (tc = 0; tc < cfg->tcs; tc++) {
+ if (cfg->is_qos)
+- snprintf(tc_string, 8, "TC%d ", tc);
++ snprintf(tc_string, 8, "TC%u ", tc);
+
+ for (i = 0; i < cfg->vecs; i++) {
+ for (si = 0; si < rx_stat_cnt; si++) {
+--
+2.43.0
+
--- /dev/null
+From ee4187d12cc0991b73a17366e959525730774394 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 27 Aug 2024 16:44:19 +0200
+Subject: net: hisilicon: hip04: fix OF node leak in probe()
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+[ Upstream commit 17555297dbd5bccc93a01516117547e26a61caf1 ]
+
+Driver is leaking OF node reference from
+of_parse_phandle_with_fixed_args() in probe().
+
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20240827144421.52852-2-krzysztof.kozlowski@linaro.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/hisilicon/hip04_eth.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/net/ethernet/hisilicon/hip04_eth.c b/drivers/net/ethernet/hisilicon/hip04_eth.c
+index b91e7a06b97f7..beb815e5289b1 100644
+--- a/drivers/net/ethernet/hisilicon/hip04_eth.c
++++ b/drivers/net/ethernet/hisilicon/hip04_eth.c
+@@ -947,6 +947,7 @@ static int hip04_mac_probe(struct platform_device *pdev)
+ priv->tx_coalesce_timer.function = tx_done;
+
+ priv->map = syscon_node_to_regmap(arg.np);
++ of_node_put(arg.np);
+ if (IS_ERR(priv->map)) {
+ dev_warn(d, "no syscon hisilicon,hip04-ppe\n");
+ ret = PTR_ERR(priv->map);
+--
+2.43.0
+
--- /dev/null
+From b53f2aacf3d7ff0d4e1b8e09ffc26b1cdaf3d368 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 27 Aug 2024 16:44:20 +0200
+Subject: net: hisilicon: hns_dsaf_mac: fix OF node leak in hns_mac_get_info()
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+[ Upstream commit 5680cf8d34e1552df987e2f4bb1bff0b2a8c8b11 ]
+
+Driver is leaking OF node reference from
+of_parse_phandle_with_fixed_args() in hns_mac_get_info().
+
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20240827144421.52852-3-krzysztof.kozlowski@linaro.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
+index f75668c479351..616a2768e5048 100644
+--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
++++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
+@@ -933,6 +933,7 @@ static int hns_mac_get_info(struct hns_mac_cb *mac_cb)
+ mac_cb->cpld_ctrl = NULL;
+ } else {
+ syscon = syscon_node_to_regmap(cpld_args.np);
++ of_node_put(cpld_args.np);
+ if (IS_ERR_OR_NULL(syscon)) {
+ dev_dbg(mac_cb->dev, "no cpld-syscon found!\n");
+ mac_cb->cpld_ctrl = NULL;
+--
+2.43.0
+
--- /dev/null
+From 05a07a093fe98539a4c3d3a8f1e225d21edd0828 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 27 Aug 2024 16:44:21 +0200
+Subject: net: hisilicon: hns_mdio: fix OF node leak in probe()
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+[ Upstream commit e62beddc45f487b9969821fad3a0913d9bc18a2f ]
+
+Driver is leaking OF node reference from
+of_parse_phandle_with_fixed_args() in probe().
+
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20240827144421.52852-4-krzysztof.kozlowski@linaro.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/hisilicon/hns_mdio.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/net/ethernet/hisilicon/hns_mdio.c b/drivers/net/ethernet/hisilicon/hns_mdio.c
+index ed73707176c1a..8a047145f0c50 100644
+--- a/drivers/net/ethernet/hisilicon/hns_mdio.c
++++ b/drivers/net/ethernet/hisilicon/hns_mdio.c
+@@ -575,6 +575,7 @@ static int hns_mdio_probe(struct platform_device *pdev)
+ MDIO_SC_RESET_ST;
+ }
+ }
++ of_node_put(reg_args.np);
+ } else {
+ dev_warn(&pdev->dev, "find syscon ret = %#x\n", ret);
+ mdio_dev->subctrl_vbase = NULL;
+--
+2.43.0
+
--- /dev/null
+From bad78f6f233459730f45bcaf1be2d069e5e1c2c0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 6 Aug 2024 12:28:24 +0100
+Subject: net: mvpp2: Increase size of queue_name buffer
+
+From: Simon Horman <horms@kernel.org>
+
+[ Upstream commit 91d516d4de48532d967a77967834e00c8c53dfe6 ]
+
+Increase size of queue_name buffer from 30 to 31 to accommodate
+the largest string written to it. This avoids truncation in
+the possibly unlikely case where the string is name is the
+maximum size.
+
+Flagged by gcc-14:
+
+ .../mvpp2_main.c: In function 'mvpp2_probe':
+ .../mvpp2_main.c:7636:32: warning: 'snprintf' output may be truncated before the last format character [-Wformat-truncation=]
+ 7636 | "stats-wq-%s%s", netdev_name(priv->port_list[0]->dev),
+ | ^
+ .../mvpp2_main.c:7635:9: note: 'snprintf' output between 10 and 31 bytes into a destination of size 30
+ 7635 | snprintf(priv->queue_name, sizeof(priv->queue_name),
+ | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ 7636 | "stats-wq-%s%s", netdev_name(priv->port_list[0]->dev),
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ 7637 | priv->port_count > 1 ? "+" : "");
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Introduced by commit 118d6298f6f0 ("net: mvpp2: add ethtool GOP statistics").
+I am not flagging this as a bug as I am not aware that it is one.
+
+Compile tested only.
+
+Signed-off-by: Simon Horman <horms@kernel.org>
+Reviewed-by: Marcin Wojtas <marcin.s.wojtas@gmail.com>
+Link: https://patch.msgid.link/20240806-mvpp2-namelen-v1-1-6dc773653f2f@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/marvell/mvpp2/mvpp2.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h
+index e809f91c08fb9..9e02e4367bec8 100644
+--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h
++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h
+@@ -1088,7 +1088,7 @@ struct mvpp2 {
+ unsigned int max_port_rxqs;
+
+ /* Workqueue to gather hardware statistics */
+- char queue_name[30];
++ char queue_name[31];
+ struct workqueue_struct *stats_queue;
+
+ /* Debugfs root entry */
+--
+2.43.0
+
--- /dev/null
+From f5e987a9d35d39db9147ec03e22188a550dae54b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 4 Sep 2024 15:34:30 +0000
+Subject: net: napi: Prevent overflow of napi_defer_hard_irqs
+
+From: Joe Damato <jdamato@fastly.com>
+
+[ Upstream commit 08062af0a52107a243f7608fd972edb54ca5b7f8 ]
+
+In commit 6f8b12d661d0 ("net: napi: add hard irqs deferral feature")
+napi_defer_irqs was added to net_device and napi_defer_irqs_count was
+added to napi_struct, both as type int.
+
+This value never goes below zero, so there is not reason for it to be a
+signed int. Change the type for both from int to u32, and add an
+overflow check to sysfs to limit the value to S32_MAX.
+
+The limit of S32_MAX was chosen because the practical limit before this
+patch was S32_MAX (anything larger was an overflow) and thus there are
+no behavioral changes introduced. If the extra bit is needed in the
+future, the limit can be raised.
+
+Before this patch:
+
+$ sudo bash -c 'echo 2147483649 > /sys/class/net/eth4/napi_defer_hard_irqs'
+$ cat /sys/class/net/eth4/napi_defer_hard_irqs
+-2147483647
+
+After this patch:
+
+$ sudo bash -c 'echo 2147483649 > /sys/class/net/eth4/napi_defer_hard_irqs'
+bash: line 0: echo: write error: Numerical result out of range
+
+Similarly, /sys/class/net/XXXXX/tx_queue_len is defined as unsigned:
+
+include/linux/netdevice.h: unsigned int tx_queue_len;
+
+And has an overflow check:
+
+dev_change_tx_queue_len(..., unsigned long new_len):
+
+ if (new_len != (unsigned int)new_len)
+ return -ERANGE;
+
+Suggested-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Joe Damato <jdamato@fastly.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20240904153431.307932-1-jdamato@fastly.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ Documentation/networking/net_cachelines/net_device.rst | 2 +-
+ include/linux/netdevice.h | 4 ++--
+ net/core/net-sysfs.c | 6 +++++-
+ 3 files changed, 8 insertions(+), 4 deletions(-)
+
+diff --git a/Documentation/networking/net_cachelines/net_device.rst b/Documentation/networking/net_cachelines/net_device.rst
+index 70c4fb9d4e5ce..d68f37f5b1f82 100644
+--- a/Documentation/networking/net_cachelines/net_device.rst
++++ b/Documentation/networking/net_cachelines/net_device.rst
+@@ -98,7 +98,7 @@ unsigned_int num_rx_queues
+ unsigned_int real_num_rx_queues - read_mostly get_rps_cpu
+ struct_bpf_prog* xdp_prog - read_mostly netif_elide_gro()
+ unsigned_long gro_flush_timeout - read_mostly napi_complete_done
+-int napi_defer_hard_irqs - read_mostly napi_complete_done
++u32 napi_defer_hard_irqs - read_mostly napi_complete_done
+ unsigned_int gro_max_size - read_mostly skb_gro_receive
+ unsigned_int gro_ipv4_max_size - read_mostly skb_gro_receive
+ rx_handler_func_t* rx_handler read_mostly - __netif_receive_skb_core
+diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
+index 238aaed5d7236..bf3eba0d9bdca 100644
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -354,7 +354,7 @@ struct napi_struct {
+
+ unsigned long state;
+ int weight;
+- int defer_hard_irqs_count;
++ u32 defer_hard_irqs_count;
+ unsigned long gro_bitmask;
+ int (*poll)(struct napi_struct *, int);
+ #ifdef CONFIG_NETPOLL
+@@ -2089,7 +2089,7 @@ struct net_device {
+ unsigned int real_num_rx_queues;
+ struct netdev_rx_queue *_rx;
+ unsigned long gro_flush_timeout;
+- int napi_defer_hard_irqs;
++ u32 napi_defer_hard_irqs;
+ unsigned int gro_max_size;
+ unsigned int gro_ipv4_max_size;
+ rx_handler_func_t __rcu *rx_handler;
+diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
+index 15ad775ddd3c1..dc0c622d453e1 100644
+--- a/net/core/net-sysfs.c
++++ b/net/core/net-sysfs.c
+@@ -32,6 +32,7 @@
+ #ifdef CONFIG_SYSFS
+ static const char fmt_hex[] = "%#x\n";
+ static const char fmt_dec[] = "%d\n";
++static const char fmt_uint[] = "%u\n";
+ static const char fmt_ulong[] = "%lu\n";
+ static const char fmt_u64[] = "%llu\n";
+
+@@ -425,6 +426,9 @@ NETDEVICE_SHOW_RW(gro_flush_timeout, fmt_ulong);
+
+ static int change_napi_defer_hard_irqs(struct net_device *dev, unsigned long val)
+ {
++ if (val > S32_MAX)
++ return -ERANGE;
++
+ WRITE_ONCE(dev->napi_defer_hard_irqs, val);
+ return 0;
+ }
+@@ -438,7 +442,7 @@ static ssize_t napi_defer_hard_irqs_store(struct device *dev,
+
+ return netdev_store(dev, attr, buf, len, change_napi_defer_hard_irqs);
+ }
+-NETDEVICE_SHOW_RW(napi_defer_hard_irqs, fmt_dec);
++NETDEVICE_SHOW_RW(napi_defer_hard_irqs, fmt_uint);
+
+ static ssize_t ifalias_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t len)
+--
+2.43.0
+
--- /dev/null
+From 6d3f7646fb0c6b67b8d1ebe7121b6076786b4fa7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Sep 2024 19:15:36 +0200
+Subject: net: phy: Check for read errors in SIOCGMIIREG
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
+
+[ Upstream commit 569bf6d481b0b823c3c9c3b8be77908fd7caf66b ]
+
+When reading registers from the PHY using the SIOCGMIIREG IOCTL any
+errors returned from either mdiobus_read() or mdiobus_c45_read() are
+ignored, and parts of the returned error is passed as the register value
+back to user-space.
+
+For example, if mdiobus_c45_read() is used with a bus that do not
+implement the read_c45() callback -EOPNOTSUPP is returned. This is
+however directly stored in mii_data->val_out and returned as the
+registers content. As val_out is a u16 the error code is truncated and
+returned as a plausible register value.
+
+Fix this by first checking the return value for errors before returning
+it as the register content.
+
+Before this patch,
+
+ # phytool read eth0/0:1/0
+ 0xffa1
+
+After this change,
+
+ $ phytool read eth0/0:1/0
+ error: phy_read (-95)
+
+Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
+Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Reviewed-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
+Tested-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
+Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
+Link: https://patch.msgid.link/20240903171536.628930-1-niklas.soderlund+renesas@ragnatech.se
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/phy/phy.c | 17 +++++++++++------
+ 1 file changed, 11 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
+index c4236564c1cd0..8495b111a524a 100644
+--- a/drivers/net/phy/phy.c
++++ b/drivers/net/phy/phy.c
+@@ -342,14 +342,19 @@ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd)
+ if (mdio_phy_id_is_c45(mii_data->phy_id)) {
+ prtad = mdio_phy_id_prtad(mii_data->phy_id);
+ devad = mdio_phy_id_devad(mii_data->phy_id);
+- mii_data->val_out = mdiobus_c45_read(
+- phydev->mdio.bus, prtad, devad,
+- mii_data->reg_num);
++ ret = mdiobus_c45_read(phydev->mdio.bus, prtad, devad,
++ mii_data->reg_num);
++
+ } else {
+- mii_data->val_out = mdiobus_read(
+- phydev->mdio.bus, mii_data->phy_id,
+- mii_data->reg_num);
++ ret = mdiobus_read(phydev->mdio.bus, mii_data->phy_id,
++ mii_data->reg_num);
+ }
++
++ if (ret < 0)
++ return ret;
++
++ mii_data->val_out = ret;
++
+ return 0;
+
+ case SIOCSMIIREG:
+--
+2.43.0
+
--- /dev/null
+From 241f520117cc1054317fb7f39951afd9ff80d529 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 4 Sep 2024 14:54:01 +0300
+Subject: net: sched: consistently use rcu_replace_pointer() in taprio_change()
+
+From: Dmitry Antipov <dmantipov@yandex.ru>
+
+[ Upstream commit d5c4546062fd6f5dbce575c7ea52ad66d1968678 ]
+
+According to Vinicius (and carefully looking through the whole
+https://syzkaller.appspot.com/bug?extid=b65e0af58423fc8a73aa
+once again), txtime branch of 'taprio_change()' is not going to
+race against 'advance_sched()'. But using 'rcu_replace_pointer()'
+in the former may be a good idea as well.
+
+Suggested-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
+Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru>
+Acked-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/sch_taprio.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c
+index b284a06b5a75f..847e1cc6052ec 100644
+--- a/net/sched/sch_taprio.c
++++ b/net/sched/sch_taprio.c
+@@ -1952,7 +1952,9 @@ static int taprio_change(struct Qdisc *sch, struct nlattr *opt,
+ goto unlock;
+ }
+
+- rcu_assign_pointer(q->admin_sched, new_admin);
++ /* Not going to race against advance_sched(), but still */
++ admin = rcu_replace_pointer(q->admin_sched, new_admin,
++ lockdep_rtnl_is_held());
+ if (admin)
+ call_rcu(&admin->rcu, taprio_free_sched_cb);
+ } else {
+--
+2.43.0
+
--- /dev/null
+From 73a10146d82586fde1f41a92839d4046927dfb62 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 23 Aug 2024 03:11:09 +0900
+Subject: net/xen-netback: prevent UAF in xenvif_flush_hash()
+
+From: Jeongjun Park <aha310510@gmail.com>
+
+[ Upstream commit 0fa5e94a1811d68fbffa0725efe6d4ca62c03d12 ]
+
+During the list_for_each_entry_rcu iteration call of xenvif_flush_hash,
+kfree_rcu does not exist inside the rcu read critical section, so if
+kfree_rcu is called when the rcu grace period ends during the iteration,
+UAF occurs when accessing head->next after the entry becomes free.
+
+Therefore, to solve this, you need to change it to list_for_each_entry_safe.
+
+Signed-off-by: Jeongjun Park <aha310510@gmail.com>
+Link: https://patch.msgid.link/20240822181109.2577354-1-aha310510@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/xen-netback/hash.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/xen-netback/hash.c b/drivers/net/xen-netback/hash.c
+index ff96f22648efd..45ddce35f6d2c 100644
+--- a/drivers/net/xen-netback/hash.c
++++ b/drivers/net/xen-netback/hash.c
+@@ -95,7 +95,7 @@ static u32 xenvif_new_hash(struct xenvif *vif, const u8 *data,
+
+ static void xenvif_flush_hash(struct xenvif *vif)
+ {
+- struct xenvif_hash_cache_entry *entry;
++ struct xenvif_hash_cache_entry *entry, *n;
+ unsigned long flags;
+
+ if (xenvif_hash_cache_size == 0)
+@@ -103,8 +103,7 @@ static void xenvif_flush_hash(struct xenvif *vif)
+
+ spin_lock_irqsave(&vif->hash.cache.lock, flags);
+
+- list_for_each_entry_rcu(entry, &vif->hash.cache.list, link,
+- lockdep_is_held(&vif->hash.cache.lock)) {
++ list_for_each_entry_safe(entry, n, &vif->hash.cache.list, link) {
+ list_del_rcu(&entry->link);
+ vif->hash.cache.count--;
+ kfree_rcu(entry, rcu);
+--
+2.43.0
+
--- /dev/null
+From 8efe88df199c285fa1fb7c25ffdd492eb657d474 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 31 Aug 2024 12:17:04 +0000
+Subject: netdev-genl: Set extack and fix error on napi-get
+
+From: Joe Damato <jdamato@fastly.com>
+
+[ Upstream commit 4e3a024b437ec0aee82550cc66a0f4e1a7a88a67 ]
+
+In commit 27f91aaf49b3 ("netdev-genl: Add netlink framework functions
+for napi"), when an invalid NAPI ID is specified the return value
+-EINVAL is used and no extack is set.
+
+Change the return value to -ENOENT and set the extack.
+
+Before this commit:
+
+$ ./tools/net/ynl/cli.py --spec Documentation/netlink/specs/netdev.yaml \
+ --do napi-get --json='{"id": 451}'
+Netlink error: Invalid argument
+nl_len = 36 (20) nl_flags = 0x100 nl_type = 2
+ error: -22
+
+After this commit:
+
+$ ./tools/net/ynl/cli.py --spec Documentation/netlink/specs/netdev.yaml \
+ --do napi-get --json='{"id": 451}'
+Netlink error: No such file or directory
+nl_len = 44 (28) nl_flags = 0x300 nl_type = 2
+ error: -2
+ extack: {'bad-attr': '.id'}
+
+Suggested-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Joe Damato <jdamato@fastly.com>
+Link: https://patch.msgid.link/20240831121707.17562-1-jdamato@fastly.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/core/netdev-genl.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/net/core/netdev-genl.c b/net/core/netdev-genl.c
+index 05f9515d2c05c..a17d7eaeb0019 100644
+--- a/net/core/netdev-genl.c
++++ b/net/core/netdev-genl.c
+@@ -216,10 +216,12 @@ int netdev_nl_napi_get_doit(struct sk_buff *skb, struct genl_info *info)
+ rtnl_lock();
+
+ napi = napi_by_id(napi_id);
+- if (napi)
++ if (napi) {
+ err = netdev_nl_napi_fill_one(rsp, napi, info);
+- else
+- err = -EINVAL;
++ } else {
++ NL_SET_BAD_ATTR(info->extack, info->attrs[NETDEV_A_NAPI_ID]);
++ err = -ENOENT;
++ }
+
+ rtnl_unlock();
+
+--
+2.43.0
+
--- /dev/null
+From 7443e050d5fa286109f59516636837d386852d99 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 29 Jul 2024 12:23:11 +0100
+Subject: netfs: Cancel dirty folios that have no storage destination
+
+From: David Howells <dhowells@redhat.com>
+
+[ Upstream commit 8f246b7c0a1be0882374f2ff831a61f0dbe77678 ]
+
+Kafs wants to be able to cache the contents of directories (and symlinks),
+but whilst these are downloaded from the server with the FS.FetchData RPC
+op and similar, the same as for regular files, they can't be updated by
+FS.StoreData, but rather have special operations (FS.MakeDir, etc.).
+
+Now, rather than redownloading a directory's content after each change made
+to that directory, kafs modifies the local blob. This blob can be saved
+out to the cache, and since it's using netfslib, kafs just marks the folios
+dirty and lets ->writepages() on the directory take care of it, as for an
+regular file.
+
+This is fine as long as there's a cache as although the upload stream is
+disabled, there's a cache stream to drive the procedure. But if the cache
+goes away in the meantime, suddenly there's no way do any writes and the
+code gets confused, complains "R=%x: No submit" to dmesg and leaves the
+dirty folio hanging.
+
+Fix this by just cancelling the store of the folio if neither stream is
+active. (If there's no cache at the time of dirtying, we should just not
+mark the folio dirty).
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+cc: Jeff Layton <jlayton@kernel.org>
+cc: netfs@lists.linux.dev
+cc: linux-fsdevel@vger.kernel.org
+Link: https://lore.kernel.org/r/20240814203850.2240469-23-dhowells@redhat.com/ # v2
+Signed-off-by: Christian Brauner <brauner@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/netfs/write_issue.c | 6 +++++-
+ include/trace/events/netfs.h | 1 +
+ 2 files changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/fs/netfs/write_issue.c b/fs/netfs/write_issue.c
+index 32bc88bee5d18..3c7eb43a2ec69 100644
+--- a/fs/netfs/write_issue.c
++++ b/fs/netfs/write_issue.c
+@@ -408,13 +408,17 @@ static int netfs_write_folio(struct netfs_io_request *wreq,
+ folio_unlock(folio);
+
+ if (fgroup == NETFS_FOLIO_COPY_TO_CACHE) {
+- if (!fscache_resources_valid(&wreq->cache_resources)) {
++ if (!cache->avail) {
+ trace_netfs_folio(folio, netfs_folio_trace_cancel_copy);
+ netfs_issue_write(wreq, upload);
+ netfs_folio_written_back(folio);
+ return 0;
+ }
+ trace_netfs_folio(folio, netfs_folio_trace_store_copy);
++ } else if (!upload->avail && !cache->avail) {
++ trace_netfs_folio(folio, netfs_folio_trace_cancel_store);
++ netfs_folio_written_back(folio);
++ return 0;
+ } else if (!upload->construct) {
+ trace_netfs_folio(folio, netfs_folio_trace_store);
+ } else {
+diff --git a/include/trace/events/netfs.h b/include/trace/events/netfs.h
+index 24ec3434d32ee..102696abe8c9e 100644
+--- a/include/trace/events/netfs.h
++++ b/include/trace/events/netfs.h
+@@ -140,6 +140,7 @@
+ EM(netfs_streaming_cont_filled_page, "mod-streamw-f+") \
+ /* The rest are for writeback */ \
+ EM(netfs_folio_trace_cancel_copy, "cancel-copy") \
++ EM(netfs_folio_trace_cancel_store, "cancel-store") \
+ EM(netfs_folio_trace_clear, "clear") \
+ EM(netfs_folio_trace_clear_cc, "clear-cc") \
+ EM(netfs_folio_trace_clear_g, "clear-g") \
+--
+2.43.0
+
--- /dev/null
+From cc32c0f92768aae1dc672953165f1d8c661df419 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 22 Aug 2024 04:10:47 -0700
+Subject: netpoll: Ensure clean state on setup failures
+
+From: Breno Leitao <leitao@debian.org>
+
+[ Upstream commit ae5a0456e0b4cfd7e61619e55251ffdf1bc7adfb ]
+
+Modify netpoll_setup() and __netpoll_setup() to ensure that the netpoll
+structure (np) is left in a clean state if setup fails for any reason.
+This prevents carrying over misconfigured fields in case of partial
+setup success.
+
+Key changes:
+- np->dev is now set only after successful setup, ensuring it's always
+ NULL if netpoll is not configured or if netpoll_setup() fails.
+- np->local_ip is zeroed if netpoll setup doesn't complete successfully.
+- Added DEBUG_NET_WARN_ON_ONCE() checks to catch unexpected states.
+- Reordered some operations in __netpoll_setup() for better logical flow.
+
+These changes improve the reliability of netpoll configuration, since it
+assures that the structure is fully initialized or totally unset.
+
+Suggested-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Breno Leitao <leitao@debian.org>
+Link: https://patch.msgid.link/20240822111051.179850-2-leitao@debian.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/core/netpoll.c | 15 ++++++++++-----
+ 1 file changed, 10 insertions(+), 5 deletions(-)
+
+diff --git a/net/core/netpoll.c b/net/core/netpoll.c
+index 55bcacf67df3b..e082139004093 100644
+--- a/net/core/netpoll.c
++++ b/net/core/netpoll.c
+@@ -626,12 +626,9 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev)
+ const struct net_device_ops *ops;
+ int err;
+
+- np->dev = ndev;
+- strscpy(np->dev_name, ndev->name, IFNAMSIZ);
+-
+ if (ndev->priv_flags & IFF_DISABLE_NETPOLL) {
+ np_err(np, "%s doesn't support polling, aborting\n",
+- np->dev_name);
++ ndev->name);
+ err = -ENOTSUPP;
+ goto out;
+ }
+@@ -649,7 +646,7 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev)
+
+ refcount_set(&npinfo->refcnt, 1);
+
+- ops = np->dev->netdev_ops;
++ ops = ndev->netdev_ops;
+ if (ops->ndo_netpoll_setup) {
+ err = ops->ndo_netpoll_setup(ndev, npinfo);
+ if (err)
+@@ -660,6 +657,8 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev)
+ refcount_inc(&npinfo->refcnt);
+ }
+
++ np->dev = ndev;
++ strscpy(np->dev_name, ndev->name, IFNAMSIZ);
+ npinfo->netpoll = np;
+
+ /* last thing to do is link it to the net device structure */
+@@ -677,6 +676,7 @@ EXPORT_SYMBOL_GPL(__netpoll_setup);
+ int netpoll_setup(struct netpoll *np)
+ {
+ struct net_device *ndev = NULL;
++ bool ip_overwritten = false;
+ struct in_device *in_dev;
+ int err;
+
+@@ -741,6 +741,7 @@ int netpoll_setup(struct netpoll *np)
+ }
+
+ np->local_ip.ip = ifa->ifa_local;
++ ip_overwritten = true;
+ np_info(np, "local IP %pI4\n", &np->local_ip.ip);
+ } else {
+ #if IS_ENABLED(CONFIG_IPV6)
+@@ -757,6 +758,7 @@ int netpoll_setup(struct netpoll *np)
+ !!(ipv6_addr_type(&np->remote_ip.in6) & IPV6_ADDR_LINKLOCAL))
+ continue;
+ np->local_ip.in6 = ifp->addr;
++ ip_overwritten = true;
+ err = 0;
+ break;
+ }
+@@ -787,6 +789,9 @@ int netpoll_setup(struct netpoll *np)
+ return 0;
+
+ put:
++ DEBUG_NET_WARN_ON_ONCE(np->dev);
++ if (ip_overwritten)
++ memset(&np->local_ip, 0, sizeof(np->local_ip));
+ netdev_put(ndev, &np->dev_tracker);
+ unlock:
+ rtnl_unlock();
+--
+2.43.0
+
--- /dev/null
+From 6ce22b4ecebbfcb604c360865aba9eb1dac6919c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 11 Sep 2024 17:44:45 +0800
+Subject: nfp: Use IRQF_NO_AUTOEN flag in request_irq()
+
+From: Jinjie Ruan <ruanjinjie@huawei.com>
+
+[ Upstream commit daaba19d357f0900b303a530ced96c78086267ea ]
+
+disable_irq() after request_irq() still has a time gap in which
+interrupts can come. request_irq() with IRQF_NO_AUTOEN flag will
+disable IRQ auto-enable when request IRQ.
+
+Reviewed-by: Louis Peens <louis.peens@corigine.com>
+Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
+Link: https://patch.msgid.link/20240911094445.1922476-4-ruanjinjie@huawei.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
+index 182ba0a8b095b..6e0929af0f725 100644
+--- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
++++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
+@@ -821,14 +821,13 @@ nfp_net_prepare_vector(struct nfp_net *nn, struct nfp_net_r_vector *r_vec,
+
+ snprintf(r_vec->name, sizeof(r_vec->name),
+ "%s-rxtx-%d", nfp_net_name(nn), idx);
+- err = request_irq(r_vec->irq_vector, r_vec->handler, 0, r_vec->name,
+- r_vec);
++ err = request_irq(r_vec->irq_vector, r_vec->handler, IRQF_NO_AUTOEN,
++ r_vec->name, r_vec);
+ if (err) {
+ nfp_net_napi_del(&nn->dp, r_vec);
+ nn_err(nn, "Error requesting IRQ %d\n", r_vec->irq_vector);
+ return err;
+ }
+- disable_irq(r_vec->irq_vector);
+
+ irq_set_affinity_hint(r_vec->irq_vector, &r_vec->affinity_mask);
+
+--
+2.43.0
+
--- /dev/null
+From e4cb0b82c255d54cf95eebc201f58f3cf282606c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 22 Jul 2024 14:02:18 +0200
+Subject: nvme-keyring: restrict match length for version '1' identifiers
+
+From: Hannes Reinecke <hare@kernel.org>
+
+[ Upstream commit 79559c75332458985ab8a21f11b08bf7c9b833b0 ]
+
+TP8018 introduced a new TLS PSK identifier version (version 1), which appended
+a PSK hash value to the existing identifier (cf NVMe TCP specification v1.1,
+section 3.6.1.3 'TLS PSK and PSK Identity Derivation').
+An original (version 0) identifier has the form:
+
+NVMe0<type><hmac> <hostnqn> <subsysnqn>
+
+and a version 1 identifier has the form:
+
+NVMe1<type><hmac> <hostnqn> <subsysnqn> <hash>
+
+This patch modifies the lookup algorthm to compare only the first part
+of the identifier (excluding the hash value) to handle both version 0 and
+version 1 identifiers.
+And the spec declares 'version 0' identifiers obsolete, so the lookup
+algorithm is modified to prever v1 identifiers.
+
+Signed-off-by: Hannes Reinecke <hare@kernel.org>
+Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Keith Busch <kbusch@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/nvme/common/keyring.c | 36 +++++++++++++++++++++++++----------
+ 1 file changed, 26 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/nvme/common/keyring.c b/drivers/nvme/common/keyring.c
+index 6f7e7a8fa5ae4..05e89307c8aa3 100644
+--- a/drivers/nvme/common/keyring.c
++++ b/drivers/nvme/common/keyring.c
+@@ -36,14 +36,12 @@ static bool nvme_tls_psk_match(const struct key *key,
+ pr_debug("%s: no key description\n", __func__);
+ return false;
+ }
+- match_len = strlen(key->description);
+- pr_debug("%s: id %s len %zd\n", __func__, key->description, match_len);
+-
+ if (!match_data->raw_data) {
+ pr_debug("%s: no match data\n", __func__);
+ return false;
+ }
+ match_id = match_data->raw_data;
++ match_len = strlen(match_id);
+ pr_debug("%s: match '%s' '%s' len %zd\n",
+ __func__, match_id, key->description, match_len);
+ return !memcmp(key->description, match_id, match_len);
+@@ -71,7 +69,7 @@ static struct key_type nvme_tls_psk_key_type = {
+
+ static struct key *nvme_tls_psk_lookup(struct key *keyring,
+ const char *hostnqn, const char *subnqn,
+- int hmac, bool generated)
++ u8 hmac, u8 psk_ver, bool generated)
+ {
+ char *identity;
+ size_t identity_len = (NVMF_NQN_SIZE) * 2 + 11;
+@@ -82,8 +80,8 @@ static struct key *nvme_tls_psk_lookup(struct key *keyring,
+ if (!identity)
+ return ERR_PTR(-ENOMEM);
+
+- snprintf(identity, identity_len, "NVMe0%c%02d %s %s",
+- generated ? 'G' : 'R', hmac, hostnqn, subnqn);
++ snprintf(identity, identity_len, "NVMe%u%c%02u %s %s",
++ psk_ver, generated ? 'G' : 'R', hmac, hostnqn, subnqn);
+
+ if (!keyring)
+ keyring = nvme_keyring;
+@@ -107,21 +105,38 @@ static struct key *nvme_tls_psk_lookup(struct key *keyring,
+ /*
+ * NVMe PSK priority list
+ *
+- * 'Retained' PSKs (ie 'generated == false')
+- * should be preferred to 'generated' PSKs,
+- * and SHA-384 should be preferred to SHA-256.
++ * 'Retained' PSKs (ie 'generated == false') should be preferred to 'generated'
++ * PSKs, PSKs with hash (psk_ver 1) should be preferred to PSKs without hash
++ * (psk_ver 0), and SHA-384 should be preferred to SHA-256.
+ */
+ static struct nvme_tls_psk_priority_list {
+ bool generated;
++ u8 psk_ver;
+ enum nvme_tcp_tls_cipher cipher;
+ } nvme_tls_psk_prio[] = {
+ { .generated = false,
++ .psk_ver = 1,
++ .cipher = NVME_TCP_TLS_CIPHER_SHA384, },
++ { .generated = false,
++ .psk_ver = 1,
++ .cipher = NVME_TCP_TLS_CIPHER_SHA256, },
++ { .generated = false,
++ .psk_ver = 0,
+ .cipher = NVME_TCP_TLS_CIPHER_SHA384, },
+ { .generated = false,
++ .psk_ver = 0,
++ .cipher = NVME_TCP_TLS_CIPHER_SHA256, },
++ { .generated = true,
++ .psk_ver = 1,
++ .cipher = NVME_TCP_TLS_CIPHER_SHA384, },
++ { .generated = true,
++ .psk_ver = 1,
+ .cipher = NVME_TCP_TLS_CIPHER_SHA256, },
+ { .generated = true,
++ .psk_ver = 0,
+ .cipher = NVME_TCP_TLS_CIPHER_SHA384, },
+ { .generated = true,
++ .psk_ver = 0,
+ .cipher = NVME_TCP_TLS_CIPHER_SHA256, },
+ };
+
+@@ -137,10 +152,11 @@ key_serial_t nvme_tls_psk_default(struct key *keyring,
+
+ for (prio = 0; prio < ARRAY_SIZE(nvme_tls_psk_prio); prio++) {
+ bool generated = nvme_tls_psk_prio[prio].generated;
++ u8 ver = nvme_tls_psk_prio[prio].psk_ver;
+ enum nvme_tcp_tls_cipher cipher = nvme_tls_psk_prio[prio].cipher;
+
+ tls_key = nvme_tls_psk_lookup(keyring, hostnqn, subnqn,
+- cipher, generated);
++ cipher, ver, generated);
+ if (!IS_ERR(tls_key)) {
+ tls_key_id = tls_key->serial;
+ key_put(tls_key);
+--
+2.43.0
+
--- /dev/null
+From 2f4c1f49f5699a783b73d03d94f0c4c473890e68 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 22 Jul 2024 14:02:20 +0200
+Subject: nvme-tcp: check for invalidated or revoked key
+
+From: Hannes Reinecke <hare@kernel.org>
+
+[ Upstream commit 5bc46b49c828a6dfaab80b71ecb63fe76a1096d2 ]
+
+key_lookup() will always return a key, even if that key is revoked
+or invalidated. So check for invalid keys before continuing.
+
+Signed-off-by: Hannes Reinecke <hare@kernel.org>
+Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Keith Busch <kbusch@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/nvme/common/keyring.c | 22 ++++++++++++++++++++++
+ drivers/nvme/host/Kconfig | 1 +
+ drivers/nvme/host/fabrics.c | 2 +-
+ drivers/nvme/host/tcp.c | 2 +-
+ include/linux/nvme-keyring.h | 6 +++++-
+ 5 files changed, 30 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/nvme/common/keyring.c b/drivers/nvme/common/keyring.c
+index 05e89307c8aa3..ed5167f942d89 100644
+--- a/drivers/nvme/common/keyring.c
++++ b/drivers/nvme/common/keyring.c
+@@ -20,6 +20,28 @@ key_serial_t nvme_keyring_id(void)
+ }
+ EXPORT_SYMBOL_GPL(nvme_keyring_id);
+
++static bool nvme_tls_psk_revoked(struct key *psk)
++{
++ return test_bit(KEY_FLAG_REVOKED, &psk->flags) ||
++ test_bit(KEY_FLAG_INVALIDATED, &psk->flags);
++}
++
++struct key *nvme_tls_key_lookup(key_serial_t key_id)
++{
++ struct key *key = key_lookup(key_id);
++
++ if (IS_ERR(key)) {
++ pr_err("key id %08x not found\n", key_id);
++ return key;
++ }
++ if (nvme_tls_psk_revoked(key)) {
++ pr_err("key id %08x revoked\n", key_id);
++ return ERR_PTR(-EKEYREVOKED);
++ }
++ return key;
++}
++EXPORT_SYMBOL_GPL(nvme_tls_key_lookup);
++
+ static void nvme_tls_psk_describe(const struct key *key, struct seq_file *m)
+ {
+ seq_puts(m, key->description);
+diff --git a/drivers/nvme/host/Kconfig b/drivers/nvme/host/Kconfig
+index b309c8be720f4..854eb26ac3db9 100644
+--- a/drivers/nvme/host/Kconfig
++++ b/drivers/nvme/host/Kconfig
+@@ -110,6 +110,7 @@ config NVME_HOST_AUTH
+ bool "NVMe over Fabrics In-Band Authentication in host side"
+ depends on NVME_CORE
+ select NVME_AUTH
++ select NVME_KEYRING if NVME_TCP_TLS
+ help
+ This provides support for NVMe over Fabrics In-Band Authentication in
+ host side.
+diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c
+index b5a4b5fd573e0..3e3db6a6524e0 100644
+--- a/drivers/nvme/host/fabrics.c
++++ b/drivers/nvme/host/fabrics.c
+@@ -650,7 +650,7 @@ static struct key *nvmf_parse_key(int key_id)
+ return ERR_PTR(-EINVAL);
+ }
+
+- key = key_lookup(key_id);
++ key = nvme_tls_key_lookup(key_id);
+ if (IS_ERR(key))
+ pr_err("key id %08x not found\n", key_id);
+ else
+diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
+index f551609691807..8c79af3ed1f23 100644
+--- a/drivers/nvme/host/tcp.c
++++ b/drivers/nvme/host/tcp.c
+@@ -1596,7 +1596,7 @@ static void nvme_tcp_tls_done(void *data, int status, key_serial_t pskid)
+ goto out_complete;
+ }
+
+- tls_key = key_lookup(pskid);
++ tls_key = nvme_tls_key_lookup(pskid);
+ if (IS_ERR(tls_key)) {
+ dev_warn(ctrl->ctrl.device, "queue %d: Invalid key %x\n",
+ qid, pskid);
+diff --git a/include/linux/nvme-keyring.h b/include/linux/nvme-keyring.h
+index e10333d78dbbe..19d2b256180fd 100644
+--- a/include/linux/nvme-keyring.h
++++ b/include/linux/nvme-keyring.h
+@@ -12,7 +12,7 @@ key_serial_t nvme_tls_psk_default(struct key *keyring,
+ const char *hostnqn, const char *subnqn);
+
+ key_serial_t nvme_keyring_id(void);
+-
++struct key *nvme_tls_key_lookup(key_serial_t key_id);
+ #else
+
+ static inline key_serial_t nvme_tls_psk_default(struct key *keyring,
+@@ -24,5 +24,9 @@ static inline key_serial_t nvme_keyring_id(void)
+ {
+ return 0;
+ }
++static inline struct key *nvme_tls_key_lookup(key_serial_t key_id)
++{
++ return ERR_PTR(-ENOTSUPP);
++}
+ #endif /* !CONFIG_NVME_KEYRING */
+ #endif /* _NVME_KEYRING_H */
+--
+2.43.0
+
--- /dev/null
+From 3b741c3360d973144c6de7f0a0240dc237c6c5fc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 22 Jul 2024 14:02:19 +0200
+Subject: nvme-tcp: sanitize TLS key handling
+
+From: Hannes Reinecke <hare@kernel.org>
+
+[ Upstream commit 363895767fbfa05891b0b4d9e06ebde7a10c6a07 ]
+
+There is a difference between TLS configured (ie the user has
+provisioned/requested a key) and TLS enabled (ie the connection
+is encrypted with TLS). This becomes important for secure concatenation,
+where the initial authentication is run on an unencrypted connection
+(ie with TLS configured, but not enabled), and then the queue is reset to
+run over TLS (ie TLS configured _and_ enabled).
+So to differentiate between those two states store the generated
+key in opts->tls_key (as we're using the same TLS key for all queues),
+the key serial of the resulting TLS handshake in ctrl->tls_pskid
+(to signal that TLS on the admin queue is enabled), and a simple
+flag for the queues to indicated that TLS has been enabled.
+
+Signed-off-by: Hannes Reinecke <hare@kernel.org>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Keith Busch <kbusch@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/nvme/host/core.c | 1 -
+ drivers/nvme/host/nvme.h | 2 +-
+ drivers/nvme/host/sysfs.c | 4 +--
+ drivers/nvme/host/tcp.c | 53 +++++++++++++++++++++++++++++----------
+ 4 files changed, 43 insertions(+), 17 deletions(-)
+
+diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
+index 5569cf4183b2a..415ede9886c12 100644
+--- a/drivers/nvme/host/core.c
++++ b/drivers/nvme/host/core.c
+@@ -4587,7 +4587,6 @@ static void nvme_free_ctrl(struct device *dev)
+
+ if (!subsys || ctrl->instance != subsys->instance)
+ ida_free(&nvme_instance_ida, ctrl->instance);
+- key_put(ctrl->tls_key);
+ nvme_free_cels(ctrl);
+ nvme_mpath_uninit(ctrl);
+ cleanup_srcu_struct(&ctrl->srcu);
+diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
+index ff1769172778b..cde1cb906dbf2 100644
+--- a/drivers/nvme/host/nvme.h
++++ b/drivers/nvme/host/nvme.h
+@@ -375,7 +375,7 @@ struct nvme_ctrl {
+ struct nvme_dhchap_key *ctrl_key;
+ u16 transaction;
+ #endif
+- struct key *tls_key;
++ key_serial_t tls_pskid;
+
+ /* Power saving configuration */
+ u64 ps_max_latency_us;
+diff --git a/drivers/nvme/host/sysfs.c b/drivers/nvme/host/sysfs.c
+index 3c55f7edd1819..5b1dee8a66ef8 100644
+--- a/drivers/nvme/host/sysfs.c
++++ b/drivers/nvme/host/sysfs.c
+@@ -671,9 +671,9 @@ static ssize_t tls_key_show(struct device *dev,
+ {
+ struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
+
+- if (!ctrl->tls_key)
++ if (!ctrl->tls_pskid)
+ return 0;
+- return sysfs_emit(buf, "%08x", key_serial(ctrl->tls_key));
++ return sysfs_emit(buf, "%08x", ctrl->tls_pskid);
+ }
+ static DEVICE_ATTR_RO(tls_key);
+ #endif
+diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
+index 8b5e4327fe83b..f551609691807 100644
+--- a/drivers/nvme/host/tcp.c
++++ b/drivers/nvme/host/tcp.c
+@@ -165,6 +165,7 @@ struct nvme_tcp_queue {
+
+ bool hdr_digest;
+ bool data_digest;
++ bool tls_enabled;
+ struct ahash_request *rcv_hash;
+ struct ahash_request *snd_hash;
+ __le32 exp_ddgst;
+@@ -213,7 +214,21 @@ static inline int nvme_tcp_queue_id(struct nvme_tcp_queue *queue)
+ return queue - queue->ctrl->queues;
+ }
+
+-static inline bool nvme_tcp_tls(struct nvme_ctrl *ctrl)
++/*
++ * Check if the queue is TLS encrypted
++ */
++static inline bool nvme_tcp_queue_tls(struct nvme_tcp_queue *queue)
++{
++ if (!IS_ENABLED(CONFIG_NVME_TCP_TLS))
++ return 0;
++
++ return queue->tls_enabled;
++}
++
++/*
++ * Check if TLS is configured for the controller.
++ */
++static inline bool nvme_tcp_tls_configured(struct nvme_ctrl *ctrl)
+ {
+ if (!IS_ENABLED(CONFIG_NVME_TCP_TLS))
+ return 0;
+@@ -368,7 +383,7 @@ static inline bool nvme_tcp_queue_has_pending(struct nvme_tcp_queue *queue)
+
+ static inline bool nvme_tcp_queue_more(struct nvme_tcp_queue *queue)
+ {
+- return !nvme_tcp_tls(&queue->ctrl->ctrl) &&
++ return !nvme_tcp_queue_tls(queue) &&
+ nvme_tcp_queue_has_pending(queue);
+ }
+
+@@ -1427,7 +1442,7 @@ static int nvme_tcp_init_connection(struct nvme_tcp_queue *queue)
+ memset(&msg, 0, sizeof(msg));
+ iov.iov_base = icresp;
+ iov.iov_len = sizeof(*icresp);
+- if (nvme_tcp_tls(&queue->ctrl->ctrl)) {
++ if (nvme_tcp_queue_tls(queue)) {
+ msg.msg_control = cbuf;
+ msg.msg_controllen = sizeof(cbuf);
+ }
+@@ -1439,7 +1454,7 @@ static int nvme_tcp_init_connection(struct nvme_tcp_queue *queue)
+ goto free_icresp;
+ }
+ ret = -ENOTCONN;
+- if (nvme_tcp_tls(&queue->ctrl->ctrl)) {
++ if (nvme_tcp_queue_tls(queue)) {
+ ctype = tls_get_record_type(queue->sock->sk,
+ (struct cmsghdr *)cbuf);
+ if (ctype != TLS_RECORD_TYPE_DATA) {
+@@ -1587,7 +1602,10 @@ static void nvme_tcp_tls_done(void *data, int status, key_serial_t pskid)
+ qid, pskid);
+ queue->tls_err = -ENOKEY;
+ } else {
+- ctrl->ctrl.tls_key = tls_key;
++ queue->tls_enabled = true;
++ if (qid == 0)
++ ctrl->ctrl.tls_pskid = key_serial(tls_key);
++ key_put(tls_key);
+ queue->tls_err = 0;
+ }
+
+@@ -1768,7 +1786,7 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl, int qid,
+ }
+
+ /* If PSKs are configured try to start TLS */
+- if (IS_ENABLED(CONFIG_NVME_TCP_TLS) && pskid) {
++ if (nvme_tcp_tls_configured(nctrl) && pskid) {
+ ret = nvme_tcp_start_tls(nctrl, queue, pskid);
+ if (ret)
+ goto err_init_connect;
+@@ -1829,6 +1847,8 @@ static void nvme_tcp_stop_queue(struct nvme_ctrl *nctrl, int qid)
+ mutex_lock(&queue->queue_lock);
+ if (test_and_clear_bit(NVME_TCP_Q_LIVE, &queue->flags))
+ __nvme_tcp_stop_queue(queue);
++ /* Stopping the queue will disable TLS */
++ queue->tls_enabled = false;
+ mutex_unlock(&queue->queue_lock);
+ }
+
+@@ -1925,16 +1945,17 @@ static int nvme_tcp_alloc_admin_queue(struct nvme_ctrl *ctrl)
+ int ret;
+ key_serial_t pskid = 0;
+
+- if (nvme_tcp_tls(ctrl)) {
++ if (nvme_tcp_tls_configured(ctrl)) {
+ if (ctrl->opts->tls_key)
+ pskid = key_serial(ctrl->opts->tls_key);
+- else
++ else {
+ pskid = nvme_tls_psk_default(ctrl->opts->keyring,
+ ctrl->opts->host->nqn,
+ ctrl->opts->subsysnqn);
+- if (!pskid) {
+- dev_err(ctrl->device, "no valid PSK found\n");
+- return -ENOKEY;
++ if (!pskid) {
++ dev_err(ctrl->device, "no valid PSK found\n");
++ return -ENOKEY;
++ }
+ }
+ }
+
+@@ -1957,13 +1978,14 @@ static int __nvme_tcp_alloc_io_queues(struct nvme_ctrl *ctrl)
+ {
+ int i, ret;
+
+- if (nvme_tcp_tls(ctrl) && !ctrl->tls_key) {
++ if (nvme_tcp_tls_configured(ctrl) && !ctrl->tls_pskid) {
+ dev_err(ctrl->device, "no PSK negotiated\n");
+ return -ENOKEY;
+ }
++
+ for (i = 1; i < ctrl->queue_count; i++) {
+ ret = nvme_tcp_alloc_queue(ctrl, i,
+- key_serial(ctrl->tls_key));
++ ctrl->tls_pskid);
+ if (ret)
+ goto out_free_queues;
+ }
+@@ -2144,6 +2166,11 @@ static void nvme_tcp_teardown_admin_queue(struct nvme_ctrl *ctrl,
+ if (remove)
+ nvme_unquiesce_admin_queue(ctrl);
+ nvme_tcp_destroy_admin_queue(ctrl, remove);
++ if (ctrl->tls_pskid) {
++ dev_dbg(ctrl->device, "Wipe negotiated TLS_PSK %08x\n",
++ ctrl->tls_pskid);
++ ctrl->tls_pskid = 0;
++ }
+ }
+
+ static void nvme_tcp_teardown_io_queues(struct nvme_ctrl *ctrl,
+--
+2.43.0
+
--- /dev/null
+From dc34b39511bf9d69041a12cb90ea16c63f221b0d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 20 Aug 2024 14:16:53 +0200
+Subject: of/irq: Refer to actual buffer size in of_irq_parse_one()
+
+From: Geert Uytterhoeven <geert+renesas@glider.be>
+
+[ Upstream commit 39ab331ab5d377a18fbf5a0e0b228205edfcc7f4 ]
+
+Replace two open-coded calculations of the buffer size by invocations of
+sizeof() on the buffer itself, to make sure the code will always use the
+actual buffer size.
+
+Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
+Link: https://lore.kernel.org/r/817c0b9626fd30790fc488c472a3398324cfcc0c.1724156125.git.geert+renesas@glider.be
+Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/of/irq.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/of/irq.c b/drivers/of/irq.c
+index 8fd63100ba8f0..d67b69cb84bfe 100644
+--- a/drivers/of/irq.c
++++ b/drivers/of/irq.c
+@@ -357,8 +357,8 @@ int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_ar
+ addr = of_get_property(device, "reg", &addr_len);
+
+ /* Prevent out-of-bounds read in case of longer interrupt parent address size */
+- if (addr_len > (3 * sizeof(__be32)))
+- addr_len = 3 * sizeof(__be32);
++ if (addr_len > sizeof(addr_buf))
++ addr_len = sizeof(addr_buf);
+ if (addr)
+ memcpy(addr_buf, addr, addr_len);
+
+--
+2.43.0
+
--- /dev/null
+From b4b715725669e2f5059f875f877465a0f8239aa0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 29 Aug 2024 17:51:08 +0200
+Subject: ovl: fsync after metadata copy-up
+
+From: Amir Goldstein <amir73il@gmail.com>
+
+[ Upstream commit 7d6899fb69d25e1bc6f4700b7c1d92e6b608593d ]
+
+For upper filesystems which do not use strict ordering of persisting
+metadata changes (e.g. ubifs), when overlayfs file is modified for
+the first time, copy up will create a copy of the lower file and
+its parent directories in the upper layer. Permission lost of the
+new upper parent directory was observed during power-cut stress test.
+
+Fix by moving the fsync call to after metadata copy to make sure that the
+metadata copied up directory and files persists to disk before renaming
+from tmp to final destination.
+
+With metacopy enabled, this change will hurt performance of workloads
+such as chown -R, so we keep the legacy behavior of fsync only on copyup
+of data.
+
+Link: https://lore.kernel.org/linux-unionfs/CAOQ4uxj-pOvmw1-uXR3qVdqtLjSkwcR9nVKcNU_vC10Zyf2miQ@mail.gmail.com/
+Reported-and-tested-by: Fei Lv <feilv@asrmicro.com>
+Signed-off-by: Amir Goldstein <amir73il@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/overlayfs/copy_up.c | 43 ++++++++++++++++++++++++++++++++++++++----
+ 1 file changed, 39 insertions(+), 4 deletions(-)
+
+diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
+index a5ef2005a2cc5..051a802893a18 100644
+--- a/fs/overlayfs/copy_up.c
++++ b/fs/overlayfs/copy_up.c
+@@ -243,8 +243,24 @@ static int ovl_verify_area(loff_t pos, loff_t pos2, loff_t len, loff_t totlen)
+ return 0;
+ }
+
++static int ovl_sync_file(struct path *path)
++{
++ struct file *new_file;
++ int err;
++
++ new_file = ovl_path_open(path, O_LARGEFILE | O_RDONLY);
++ if (IS_ERR(new_file))
++ return PTR_ERR(new_file);
++
++ err = vfs_fsync(new_file, 0);
++ fput(new_file);
++
++ return err;
++}
++
+ static int ovl_copy_up_file(struct ovl_fs *ofs, struct dentry *dentry,
+- struct file *new_file, loff_t len)
++ struct file *new_file, loff_t len,
++ bool datasync)
+ {
+ struct path datapath;
+ struct file *old_file;
+@@ -342,7 +358,8 @@ static int ovl_copy_up_file(struct ovl_fs *ofs, struct dentry *dentry,
+
+ len -= bytes;
+ }
+- if (!error && ovl_should_sync(ofs))
++ /* call fsync once, either now or later along with metadata */
++ if (!error && ovl_should_sync(ofs) && datasync)
+ error = vfs_fsync(new_file, 0);
+ out_fput:
+ fput(old_file);
+@@ -574,6 +591,7 @@ struct ovl_copy_up_ctx {
+ bool indexed;
+ bool metacopy;
+ bool metacopy_digest;
++ bool metadata_fsync;
+ };
+
+ static int ovl_link_up(struct ovl_copy_up_ctx *c)
+@@ -634,7 +652,8 @@ static int ovl_copy_up_data(struct ovl_copy_up_ctx *c, const struct path *temp)
+ if (IS_ERR(new_file))
+ return PTR_ERR(new_file);
+
+- err = ovl_copy_up_file(ofs, c->dentry, new_file, c->stat.size);
++ err = ovl_copy_up_file(ofs, c->dentry, new_file, c->stat.size,
++ !c->metadata_fsync);
+ fput(new_file);
+
+ return err;
+@@ -701,6 +720,10 @@ static int ovl_copy_up_metadata(struct ovl_copy_up_ctx *c, struct dentry *temp)
+ err = ovl_set_attr(ofs, temp, &c->stat);
+ inode_unlock(temp->d_inode);
+
++ /* fsync metadata before moving it into upper dir */
++ if (!err && ovl_should_sync(ofs) && c->metadata_fsync)
++ err = ovl_sync_file(&upperpath);
++
+ return err;
+ }
+
+@@ -860,7 +883,8 @@ static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c)
+
+ temp = tmpfile->f_path.dentry;
+ if (!c->metacopy && c->stat.size) {
+- err = ovl_copy_up_file(ofs, c->dentry, tmpfile, c->stat.size);
++ err = ovl_copy_up_file(ofs, c->dentry, tmpfile, c->stat.size,
++ !c->metadata_fsync);
+ if (err)
+ goto out_fput;
+ }
+@@ -1135,6 +1159,17 @@ static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
+ !kgid_has_mapping(current_user_ns(), ctx.stat.gid))
+ return -EOVERFLOW;
+
++ /*
++ * With metacopy disabled, we fsync after final metadata copyup, for
++ * both regular files and directories to get atomic copyup semantics
++ * on filesystems that do not use strict metadata ordering (e.g. ubifs).
++ *
++ * With metacopy enabled we want to avoid fsync on all meta copyup
++ * that will hurt performance of workloads such as chown -R, so we
++ * only fsync on data copyup as legacy behavior.
++ */
++ ctx.metadata_fsync = !OVL_FS(dentry->d_sb)->config.metacopy &&
++ (S_ISREG(ctx.stat.mode) || S_ISDIR(ctx.stat.mode));
+ ctx.metacopy = ovl_need_meta_copy_up(dentry, ctx.stat.mode, flags);
+
+ if (parent) {
+--
+2.43.0
+
--- /dev/null
+From 9708913b983d7d207e6e650cb94aafdb2e269b7a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 7 Aug 2024 13:29:27 +0200
+Subject: perf: Fix event_function_call() locking
+
+From: Peter Zijlstra <peterz@infradead.org>
+
+[ Upstream commit 558abc7e3f895049faa46b08656be4c60dc6e9fd ]
+
+All the event_function/@func call context already uses perf_ctx_lock()
+except for the !ctx->is_active case. Make it all consistent.
+
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Reviewed-by: Kan Liang <kan.liang@linux.intel.com>
+Reviewed-by: Namhyung Kim <namhyung@kernel.org>
+Link: https://lore.kernel.org/r/20240807115550.138301094@infradead.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/events/core.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/kernel/events/core.c b/kernel/events/core.c
+index 081d9692ce747..e18a07de9920a 100644
+--- a/kernel/events/core.c
++++ b/kernel/events/core.c
+@@ -263,6 +263,7 @@ static int event_function(void *info)
+ static void event_function_call(struct perf_event *event, event_f func, void *data)
+ {
+ struct perf_event_context *ctx = event->ctx;
++ struct perf_cpu_context *cpuctx = this_cpu_ptr(&perf_cpu_context);
+ struct task_struct *task = READ_ONCE(ctx->task); /* verified in event_function */
+ struct event_function_struct efs = {
+ .event = event,
+@@ -291,22 +292,22 @@ static void event_function_call(struct perf_event *event, event_f func, void *da
+ if (!task_function_call(task, event_function, &efs))
+ return;
+
+- raw_spin_lock_irq(&ctx->lock);
++ perf_ctx_lock(cpuctx, ctx);
+ /*
+ * Reload the task pointer, it might have been changed by
+ * a concurrent perf_event_context_sched_out().
+ */
+ task = ctx->task;
+ if (task == TASK_TOMBSTONE) {
+- raw_spin_unlock_irq(&ctx->lock);
++ perf_ctx_unlock(cpuctx, ctx);
+ return;
+ }
+ if (ctx->is_active) {
+- raw_spin_unlock_irq(&ctx->lock);
++ perf_ctx_unlock(cpuctx, ctx);
+ goto again;
+ }
+ func(event, NULL, ctx, data);
+- raw_spin_unlock_irq(&ctx->lock);
++ perf_ctx_unlock(cpuctx, ctx);
+ }
+
+ /*
+--
+2.43.0
+
--- /dev/null
+From a8b6632c02c45eb65a8fa2aab392b485c373c415 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 29 Jul 2024 10:52:23 -0700
+Subject: perf,x86: avoid missing caller address in stack traces captured in
+ uprobe
+
+From: Andrii Nakryiko <andrii@kernel.org>
+
+[ Upstream commit cfa7f3d2c526c224a6271cc78a4a27a0de06f4f0 ]
+
+When tracing user functions with uprobe functionality, it's common to
+install the probe (e.g., a BPF program) at the first instruction of the
+function. This is often going to be `push %rbp` instruction in function
+preamble, which means that within that function frame pointer hasn't
+been established yet. This leads to consistently missing an actual
+caller of the traced function, because perf_callchain_user() only
+records current IP (capturing traced function) and then following frame
+pointer chain (which would be caller's frame, containing the address of
+caller's caller).
+
+So when we have target_1 -> target_2 -> target_3 call chain and we are
+tracing an entry to target_3, captured stack trace will report
+target_1 -> target_3 call chain, which is wrong and confusing.
+
+This patch proposes a x86-64-specific heuristic to detect `push %rbp`
+(`push %ebp` on 32-bit architecture) instruction being traced. Given
+entire kernel implementation of user space stack trace capturing works
+under assumption that user space code was compiled with frame pointer
+register (%rbp/%ebp) preservation, it seems pretty reasonable to use
+this instruction as a strong indicator that this is the entry to the
+function. In that case, return address is still pointed to by %rsp/%esp,
+so we fetch it and add to stack trace before proceeding to unwind the
+rest using frame pointer-based logic.
+
+We also check for `endbr64` (for 64-bit modes) as another common pattern
+for function entry, as suggested by Josh Poimboeuf. Even if we get this
+wrong sometimes for uprobes attached not at the function entry, it's OK
+because stack trace will still be overall meaningful, just with one
+extra bogus entry. If we don't detect this, we end up with guaranteed to
+be missing caller function entry in the stack trace, which is worse
+overall.
+
+Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Link: https://lkml.kernel.org/r/20240729175223.23914-1-andrii@kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/events/core.c | 63 +++++++++++++++++++++++++++++++++++++++++
+ include/linux/uprobes.h | 2 ++
+ kernel/events/uprobes.c | 2 ++
+ 3 files changed, 67 insertions(+)
+
+diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
+index 83d12dd3f831a..d77a97056844b 100644
+--- a/arch/x86/events/core.c
++++ b/arch/x86/events/core.c
+@@ -41,6 +41,8 @@
+ #include <asm/desc.h>
+ #include <asm/ldt.h>
+ #include <asm/unwind.h>
++#include <asm/uprobes.h>
++#include <asm/ibt.h>
+
+ #include "perf_event.h"
+
+@@ -2814,6 +2816,46 @@ static unsigned long get_segment_base(unsigned int segment)
+ return get_desc_base(desc);
+ }
+
++#ifdef CONFIG_UPROBES
++/*
++ * Heuristic-based check if uprobe is installed at the function entry.
++ *
++ * Under assumption of user code being compiled with frame pointers,
++ * `push %rbp/%ebp` is a good indicator that we indeed are.
++ *
++ * Similarly, `endbr64` (assuming 64-bit mode) is also a common pattern.
++ * If we get this wrong, captured stack trace might have one extra bogus
++ * entry, but the rest of stack trace will still be meaningful.
++ */
++static bool is_uprobe_at_func_entry(struct pt_regs *regs)
++{
++ struct arch_uprobe *auprobe;
++
++ if (!current->utask)
++ return false;
++
++ auprobe = current->utask->auprobe;
++ if (!auprobe)
++ return false;
++
++ /* push %rbp/%ebp */
++ if (auprobe->insn[0] == 0x55)
++ return true;
++
++ /* endbr64 (64-bit only) */
++ if (user_64bit_mode(regs) && is_endbr(*(u32 *)auprobe->insn))
++ return true;
++
++ return false;
++}
++
++#else
++static bool is_uprobe_at_func_entry(struct pt_regs *regs)
++{
++ return false;
++}
++#endif /* CONFIG_UPROBES */
++
+ #ifdef CONFIG_IA32_EMULATION
+
+ #include <linux/compat.h>
+@@ -2825,6 +2867,7 @@ perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry_ctx *ent
+ unsigned long ss_base, cs_base;
+ struct stack_frame_ia32 frame;
+ const struct stack_frame_ia32 __user *fp;
++ u32 ret_addr;
+
+ if (user_64bit_mode(regs))
+ return 0;
+@@ -2834,6 +2877,12 @@ perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry_ctx *ent
+
+ fp = compat_ptr(ss_base + regs->bp);
+ pagefault_disable();
++
++ /* see perf_callchain_user() below for why we do this */
++ if (is_uprobe_at_func_entry(regs) &&
++ !get_user(ret_addr, (const u32 __user *)regs->sp))
++ perf_callchain_store(entry, ret_addr);
++
+ while (entry->nr < entry->max_stack) {
+ if (!valid_user_frame(fp, sizeof(frame)))
+ break;
+@@ -2862,6 +2911,7 @@ perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs
+ {
+ struct stack_frame frame;
+ const struct stack_frame __user *fp;
++ unsigned long ret_addr;
+
+ if (perf_guest_state()) {
+ /* TODO: We don't support guest os callchain now */
+@@ -2885,6 +2935,19 @@ perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs
+ return;
+
+ pagefault_disable();
++
++ /*
++ * If we are called from uprobe handler, and we are indeed at the very
++ * entry to user function (which is normally a `push %rbp` instruction,
++ * under assumption of application being compiled with frame pointers),
++ * we should read return address from *regs->sp before proceeding
++ * to follow frame pointers, otherwise we'll skip immediate caller
++ * as %rbp is not yet setup.
++ */
++ if (is_uprobe_at_func_entry(regs) &&
++ !get_user(ret_addr, (const unsigned long __user *)regs->sp))
++ perf_callchain_store(entry, ret_addr);
++
+ while (entry->nr < entry->max_stack) {
+ if (!valid_user_frame(fp, sizeof(frame)))
+ break;
+diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h
+index f46e0ca0169c7..d91e32aff5a13 100644
+--- a/include/linux/uprobes.h
++++ b/include/linux/uprobes.h
+@@ -76,6 +76,8 @@ struct uprobe_task {
+ struct uprobe *active_uprobe;
+ unsigned long xol_vaddr;
+
++ struct arch_uprobe *auprobe;
++
+ struct return_instance *return_instances;
+ unsigned int depth;
+ };
+diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
+index 47cdec3e1df11..28c678c8daef3 100644
+--- a/kernel/events/uprobes.c
++++ b/kernel/events/uprobes.c
+@@ -2071,6 +2071,7 @@ static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs)
+ bool need_prep = false; /* prepare return uprobe, when needed */
+
+ down_read(&uprobe->register_rwsem);
++ current->utask->auprobe = &uprobe->arch;
+ for (uc = uprobe->consumers; uc; uc = uc->next) {
+ int rc = 0;
+
+@@ -2085,6 +2086,7 @@ static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs)
+
+ remove &= rc;
+ }
++ current->utask->auprobe = NULL;
+
+ if (need_prep && !remove)
+ prepare_uretprobe(uprobe, regs); /* put bp at return */
+--
+2.43.0
+
--- /dev/null
+From 2a40f56da1acfca4e814859606bae5f2a23c3cff Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 12 Sep 2024 15:05:32 -0400
+Subject: platform/mellanox: mlxbf-pmc: fix lockdep warning
+
+From: Luiz Capitulino <luizcap@redhat.com>
+
+[ Upstream commit 305790dd91057a3f7497c9d128614a4f8486b62b ]
+
+It seems the mlxbf-pmc driver is missing initializing sysfs attributes
+which causes the warning below when CONFIG_LOCKDEP and
+CONFIG_DEBUG_LOCK_ALLOC are enabled. This commit fixes it.
+
+[ 155.380843] BUG: key ffff470f45dfa6d8 has not been registered!
+[ 155.386749] ------------[ cut here ]------------
+[ 155.391361] DEBUG_LOCKS_WARN_ON(1)
+[ 155.391381] WARNING: CPU: 4 PID: 1828 at kernel/locking/lockdep.c:4894 lockdep_init_map_type+0x1d0/0x288
+[ 155.404254] Modules linked in: mlxbf_pmc(+) xfs libcrc32c mmc_block mlx5_core crct10dif_ce mlxfw ghash_ce virtio_net tls net_failover sha2
+_ce failover psample sha256_arm64 dw_mmc_bluefield pci_hyperv_intf sha1_ce dw_mmc_pltfm sbsa_gwdt dw_mmc micrel mmc_core nfit i2c_mlxbf pwr_m
+lxbf gpio_generic libnvdimm mlxbf_tmfifo mlxbf_gige dm_mirror dm_region_hash dm_log dm_mod
+[ 155.436786] CPU: 4 UID: 0 PID: 1828 Comm: modprobe Kdump: loaded Not tainted 6.11.0-rc7-rep1+ #1
+[ 155.445562] Hardware name: https://www.mellanox.com BlueField SoC/BlueField SoC, BIOS 4.8.0.13249 Aug 7 2024
+[ 155.455463] pstate: 60000005 (nZCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
+[ 155.462413] pc : lockdep_init_map_type+0x1d0/0x288
+[ 155.467196] lr : lockdep_init_map_type+0x1d0/0x288
+[ 155.471976] sp : ffff80008a1734e0
+[ 155.475279] x29: ffff80008a1734e0 x28: ffff470f45df0240 x27: 00000000ffffee4b
+[ 155.482406] x26: 00000000000011b4 x25: 0000000000000000 x24: 0000000000000000
+[ 155.489532] x23: ffff470f45dfa6d8 x22: 0000000000000000 x21: ffffd54ef6bea000
+[ 155.496659] x20: ffff470f45dfa6d8 x19: ffff470f49cdc638 x18: ffffffffffffffff
+[ 155.503784] x17: 2f30303a31444642 x16: ffffd54ef48a65e8 x15: ffff80010a172fe7
+[ 155.510911] x14: 0000000000000000 x13: 284e4f5f4e524157 x12: 5f534b434f4c5f47
+[ 155.518037] x11: 0000000000000001 x10: 0000000000000001 x9 : ffffd54ef3f48a14
+[ 155.525163] x8 : 00000000000bffe8 x7 : c0000000ffff7fff x6 : 00000000002bffa8
+[ 155.532289] x5 : ffff4712bdcb6088 x4 : 0000000000000000 x3 : 0000000000000027
+[ 155.539416] x2 : 0000000000000000 x1 : 0000000000000000 x0 : ffff470f43e5be00
+[ 155.546542] Call trace:
+[ 155.548976] lockdep_init_map_type+0x1d0/0x288
+[ 155.553410] __kernfs_create_file+0x80/0x138
+[ 155.557673] sysfs_add_file_mode_ns+0x94/0x150
+[ 155.562106] create_files+0xb0/0x248
+[ 155.565672] internal_create_group+0x10c/0x328
+[ 155.570105] internal_create_groups.part.0+0x50/0xc8
+[ 155.575060] sysfs_create_groups+0x20/0x38
+[ 155.579146] device_add_attrs+0x1b8/0x228
+[ 155.583146] device_add+0x2a4/0x690
+[ 155.586625] device_register+0x24/0x38
+[ 155.590362] __hwmon_device_register+0x1e0/0x3c8
+[ 155.594969] devm_hwmon_device_register_with_groups+0x78/0xe0
+[ 155.600703] mlxbf_pmc_probe+0x224/0x3a0 [mlxbf_pmc]
+[ 155.605669] platform_probe+0x6c/0xe0
+[ 155.609320] really_probe+0xc4/0x398
+[ 155.612887] __driver_probe_device+0x80/0x168
+[ 155.617233] driver_probe_device+0x44/0x120
+[ 155.621405] __driver_attach+0xf4/0x200
+[ 155.625230] bus_for_each_dev+0x7c/0xe8
+[ 155.629055] driver_attach+0x28/0x38
+[ 155.632619] bus_add_driver+0x110/0x238
+[ 155.636445] driver_register+0x64/0x128
+[ 155.640270] __platform_driver_register+0x2c/0x40
+[ 155.644965] pmc_driver_init+0x24/0xff8 [mlxbf_pmc]
+[ 155.649833] do_one_initcall+0x70/0x3d0
+[ 155.653660] do_init_module+0x64/0x220
+[ 155.657400] load_module+0x628/0x6a8
+[ 155.660964] init_module_from_file+0x8c/0xd8
+[ 155.665222] idempotent_init_module+0x194/0x290
+[ 155.669742] __arm64_sys_finit_module+0x6c/0xd8
+[ 155.674261] invoke_syscall.constprop.0+0x74/0xd0
+[ 155.678957] do_el0_svc+0xb4/0xd0
+[ 155.682262] el0_svc+0x5c/0x248
+[ 155.685394] el0t_64_sync_handler+0x134/0x150
+[ 155.689739] el0t_64_sync+0x17c/0x180
+[ 155.693390] irq event stamp: 6407
+[ 155.696693] hardirqs last enabled at (6407): [<ffffd54ef3f48564>] console_unlock+0x154/0x1b8
+[ 155.705207] hardirqs last disabled at (6406): [<ffffd54ef3f485ac>] console_unlock+0x19c/0x1b8
+[ 155.713719] softirqs last enabled at (6404): [<ffffd54ef3e9740c>] handle_softirqs+0x4f4/0x518
+[ 155.722320] softirqs last disabled at (6395): [<ffffd54ef3df0160>] __do_softirq+0x18/0x20
+[ 155.730484] ---[ end trace 0000000000000000 ]---
+
+Signed-off-by: Luiz Capitulino <luizcap@redhat.com>
+Link: https://lore.kernel.org/r/20240912190532.377097-1-luizcap@redhat.com
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/platform/mellanox/mlxbf-pmc.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/drivers/platform/mellanox/mlxbf-pmc.c b/drivers/platform/mellanox/mlxbf-pmc.c
+index 4ed9c7fd2b62a..9d18dfca6a673 100644
+--- a/drivers/platform/mellanox/mlxbf-pmc.c
++++ b/drivers/platform/mellanox/mlxbf-pmc.c
+@@ -1774,6 +1774,7 @@ static int mlxbf_pmc_init_perftype_counter(struct device *dev, unsigned int blk_
+
+ /* "event_list" sysfs to list events supported by the block */
+ attr = &pmc->block[blk_num].attr_event_list;
++ sysfs_attr_init(&attr->dev_attr.attr);
+ attr->dev_attr.attr.mode = 0444;
+ attr->dev_attr.show = mlxbf_pmc_event_list_show;
+ attr->nr = blk_num;
+@@ -1787,6 +1788,7 @@ static int mlxbf_pmc_init_perftype_counter(struct device *dev, unsigned int blk_
+ if (strstr(pmc->block_name[blk_num], "l3cache") ||
+ ((pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE))) {
+ attr = &pmc->block[blk_num].attr_enable;
++ sysfs_attr_init(&attr->dev_attr.attr);
+ attr->dev_attr.attr.mode = 0644;
+ attr->dev_attr.show = mlxbf_pmc_enable_show;
+ attr->dev_attr.store = mlxbf_pmc_enable_store;
+@@ -1814,6 +1816,7 @@ static int mlxbf_pmc_init_perftype_counter(struct device *dev, unsigned int blk_
+ /* "eventX" and "counterX" sysfs to program and read counter values */
+ for (j = 0; j < pmc->block[blk_num].counters; ++j) {
+ attr = &pmc->block[blk_num].attr_counter[j];
++ sysfs_attr_init(&attr->dev_attr.attr);
+ attr->dev_attr.attr.mode = 0644;
+ attr->dev_attr.show = mlxbf_pmc_counter_show;
+ attr->dev_attr.store = mlxbf_pmc_counter_store;
+@@ -1826,6 +1829,7 @@ static int mlxbf_pmc_init_perftype_counter(struct device *dev, unsigned int blk_
+ attr = NULL;
+
+ attr = &pmc->block[blk_num].attr_event[j];
++ sysfs_attr_init(&attr->dev_attr.attr);
+ attr->dev_attr.attr.mode = 0644;
+ attr->dev_attr.show = mlxbf_pmc_event_show;
+ attr->dev_attr.store = mlxbf_pmc_event_store;
+@@ -1861,6 +1865,7 @@ static int mlxbf_pmc_init_perftype_reg(struct device *dev, unsigned int blk_num)
+ while (count > 0) {
+ --count;
+ attr = &pmc->block[blk_num].attr_event[count];
++ sysfs_attr_init(&attr->dev_attr.attr);
+ attr->dev_attr.attr.mode = 0644;
+ attr->dev_attr.show = mlxbf_pmc_counter_show;
+ attr->dev_attr.store = mlxbf_pmc_counter_store;
+--
+2.43.0
+
--- /dev/null
+From c8fd75c09199bd4c69bbde30f934768d445246e2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 12 Sep 2024 15:36:01 +0800
+Subject: platform/x86/amd: pmf: Add quirk for TUF Gaming A14
+
+From: aln8 <aln8un@gmail.com>
+
+[ Upstream commit 06369503d644068abd9e90918c6611274d94c126 ]
+
+The ASUS TUF Gaming A14 has the same issue as the ROG Zephyrus G14
+where it advertises SPS support but doesn't use it.
+
+Signed-off-by: aln8 <aln8un@gmail.com>
+Acked-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
+Link: https://lore.kernel.org/r/20240912073601.65656-1-aln8un@gmail.com
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/platform/x86/amd/pmf/pmf-quirks.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/drivers/platform/x86/amd/pmf/pmf-quirks.c b/drivers/platform/x86/amd/pmf/pmf-quirks.c
+index 48870ca52b413..7cde5733b9cac 100644
+--- a/drivers/platform/x86/amd/pmf/pmf-quirks.c
++++ b/drivers/platform/x86/amd/pmf/pmf-quirks.c
+@@ -37,6 +37,14 @@ static const struct dmi_system_id fwbug_list[] = {
+ },
+ .driver_data = &quirk_no_sps_bug,
+ },
++ {
++ .ident = "ASUS TUF Gaming A14",
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
++ DMI_MATCH(DMI_PRODUCT_NAME, "FA401W"),
++ },
++ .driver_data = &quirk_no_sps_bug,
++ },
+ {}
+ };
+
+--
+2.43.0
+
--- /dev/null
+From 0999daecd7f1100e089cdaf19bd2bb0bfdf3ccb1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 22 Aug 2024 17:38:57 +0200
+Subject: platform/x86: lenovo-ymc: Ignore the 0x0 state
+
+From: Gergo Koteles <soyer@irl.hu>
+
+[ Upstream commit d9dca215708d32e7f88ac0591fbb187cbf368adb ]
+
+While booting, Lenovo 14ARB7 reports 'lenovo-ymc: Unknown key 0 pressed'
+warning. This is caused by lenovo_ymc_probe() calling lenovo_ymc_notify()
+at probe time to get the initial tablet-mode-switch state and the key-code
+lenovo_ymc_notify() reads from the firmware is not initialized at probe
+time yet on the Lenovo 14ARB7.
+
+The hardware/firmware does an ACPI notify on the WMI device itself when
+it initializes the tablet-mode-switch state later on.
+
+Add 0x0 YMC state to the sparse keymap to silence the warning.
+
+Signed-off-by: Gergo Koteles <soyer@irl.hu>
+Link: https://lore.kernel.org/r/08ab73bb74c4ad448409f2ce707b1148874a05ce.1724340562.git.soyer@irl.hu
+[hdegoede@redhat.com: Reword commit message]
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/platform/x86/lenovo-ymc.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/platform/x86/lenovo-ymc.c b/drivers/platform/x86/lenovo-ymc.c
+index e0bbd6a14a89c..bd9f95404c7cb 100644
+--- a/drivers/platform/x86/lenovo-ymc.c
++++ b/drivers/platform/x86/lenovo-ymc.c
+@@ -43,6 +43,8 @@ struct lenovo_ymc_private {
+ };
+
+ static const struct key_entry lenovo_ymc_keymap[] = {
++ /* Ignore the uninitialized state */
++ { KE_IGNORE, 0x00 },
+ /* Laptop */
+ { KE_SW, 0x01, { .sw = { SW_TABLET_MODE, 0 } } },
+ /* Tablet */
+--
+2.43.0
+
--- /dev/null
+From bb5eb37aafeb6b0a1813b8f138f8c40d826c7727 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 11 Sep 2024 21:12:40 +0200
+Subject: platform/x86: touchscreen_dmi: add nanote-next quirk
+
+From: Ckath <ckath@yandex.ru>
+
+[ Upstream commit c11619af35bae5884029bd14170c3e4b55ddf6f3 ]
+
+Add touschscreen info for the nanote next (UMPC-03-SR).
+
+After checking with multiple owners the DMI info really is this generic.
+
+Signed-off-by: Ckath <ckath@yandex.ru>
+Link: https://lore.kernel.org/r/e8dda83a-10ae-42cf-a061-5d29be0d193a@yandex.ru
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/platform/x86/touchscreen_dmi.c | 26 ++++++++++++++++++++++++++
+ 1 file changed, 26 insertions(+)
+
+diff --git a/drivers/platform/x86/touchscreen_dmi.c b/drivers/platform/x86/touchscreen_dmi.c
+index f74af0a689f20..0a39f68c641d1 100644
+--- a/drivers/platform/x86/touchscreen_dmi.c
++++ b/drivers/platform/x86/touchscreen_dmi.c
+@@ -840,6 +840,21 @@ static const struct ts_dmi_data rwc_nanote_p8_data = {
+ .properties = rwc_nanote_p8_props,
+ };
+
++static const struct property_entry rwc_nanote_next_props[] = {
++ PROPERTY_ENTRY_U32("touchscreen-min-x", 5),
++ PROPERTY_ENTRY_U32("touchscreen-min-y", 5),
++ PROPERTY_ENTRY_U32("touchscreen-size-x", 1785),
++ PROPERTY_ENTRY_U32("touchscreen-size-y", 1145),
++ PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
++ PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-rwc-nanote-next.fw"),
++ { }
++};
++
++static const struct ts_dmi_data rwc_nanote_next_data = {
++ .acpi_name = "MSSL1680:00",
++ .properties = rwc_nanote_next_props,
++};
++
+ static const struct property_entry schneider_sct101ctm_props[] = {
+ PROPERTY_ENTRY_U32("touchscreen-size-x", 1715),
+ PROPERTY_ENTRY_U32("touchscreen-size-y", 1140),
+@@ -1589,6 +1604,17 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
+ DMI_MATCH(DMI_PRODUCT_SKU, "0001")
+ },
+ },
++ {
++ /* RWC NANOTE NEXT */
++ .driver_data = (void *)&rwc_nanote_next_data,
++ .matches = {
++ DMI_MATCH(DMI_PRODUCT_NAME, "To be filled by O.E.M."),
++ DMI_MATCH(DMI_BOARD_NAME, "To be filled by O.E.M."),
++ DMI_MATCH(DMI_BOARD_VENDOR, "To be filled by O.E.M."),
++ /* Above matches are too generic, add bios-version match */
++ DMI_MATCH(DMI_BIOS_VERSION, "S8A70R100-V005"),
++ },
++ },
+ {
+ /* Schneider SCT101CTM */
+ .driver_data = (void *)&schneider_sct101ctm_data,
+--
+2.43.0
+
--- /dev/null
+From e8087bfbd9900fcfed60efa0efbb250858c5dd67 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 16 Sep 2024 11:02:55 +0200
+Subject: platform/x86: x86-android-tablets: Adjust Xiaomi Pad 2 bottom bezel
+ touch buttons LED
+
+From: Hans de Goede <hdegoede@redhat.com>
+
+[ Upstream commit df40a23cc34c200cfde559eda7ca540f3ae7bd9e ]
+
+The "input-events" LED trigger used to turn on the backlight LEDs had to
+be rewritten to use led_trigger_register_simple() + led_trigger_event()
+to fix a serious locking issue.
+
+This means it no longer supports using blink_brightness to set a per LED
+brightness for the trigger and it no longer sets LED_CORE_SUSPENDRESUME.
+
+Adjust the MiPad 2 bottom bezel touch buttons LED class device to match:
+
+1. Make LED_FULL the maximum brightness to fix the LED brightness
+ being very low when on.
+2. Set flags = LED_CORE_SUSPENDRESUME.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Link: https://lore.kernel.org/r/20240916090255.35548-1-hdegoede@redhat.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/platform/x86/x86-android-tablets/other.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/platform/x86/x86-android-tablets/other.c b/drivers/platform/x86/x86-android-tablets/other.c
+index eb0e55c69dfed..2549c348c8825 100644
+--- a/drivers/platform/x86/x86-android-tablets/other.c
++++ b/drivers/platform/x86/x86-android-tablets/other.c
+@@ -670,7 +670,7 @@ static const struct software_node *ktd2026_node_group[] = {
+ * is controlled by the "pwm_soc_lpss_2" PWM output.
+ */
+ #define XIAOMI_MIPAD2_LED_PERIOD_NS 19200
+-#define XIAOMI_MIPAD2_LED_DEFAULT_DUTY 6000 /* From Android kernel */
++#define XIAOMI_MIPAD2_LED_MAX_DUTY_NS 6000 /* From Android kernel */
+
+ static struct pwm_device *xiaomi_mipad2_led_pwm;
+
+@@ -679,7 +679,7 @@ static int xiaomi_mipad2_brightness_set(struct led_classdev *led_cdev,
+ {
+ struct pwm_state state = {
+ .period = XIAOMI_MIPAD2_LED_PERIOD_NS,
+- .duty_cycle = val,
++ .duty_cycle = XIAOMI_MIPAD2_LED_MAX_DUTY_NS * val / LED_FULL,
+ /* Always set PWM enabled to avoid the pin floating */
+ .enabled = true,
+ };
+@@ -701,11 +701,11 @@ static int __init xiaomi_mipad2_init(struct device *dev)
+ return -ENOMEM;
+
+ led_cdev->name = "mipad2:white:touch-buttons-backlight";
+- led_cdev->max_brightness = XIAOMI_MIPAD2_LED_PERIOD_NS;
+- /* "input-events" trigger uses blink_brightness */
+- led_cdev->blink_brightness = XIAOMI_MIPAD2_LED_DEFAULT_DUTY;
++ led_cdev->max_brightness = LED_FULL;
+ led_cdev->default_trigger = "input-events";
+ led_cdev->brightness_set_blocking = xiaomi_mipad2_brightness_set;
++ /* Turn LED off during suspend */
++ led_cdev->flags = LED_CORE_SUSPENDRESUME;
+
+ ret = devm_led_classdev_register(dev, led_cdev);
+ if (ret)
+--
+2.43.0
+
--- /dev/null
+From 98f8d5886c9ab96dab11b5ea593d58f59f70e3b6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 May 2024 16:25:52 +0200
+Subject: pmdomain: core: Don't hold the genpd-lock when calling
+ dev_pm_domain_set()
+
+From: Ulf Hansson <ulf.hansson@linaro.org>
+
+[ Upstream commit b87eee38605c396f0e1fa435939960e5c6cd41d6 ]
+
+There is no need to hold the genpd-lock, while assigning the
+dev->pm_domain. In fact, it becomes a problem on a PREEMPT_RT based
+configuration as the genpd-lock may be a raw spinlock, while the lock
+acquired through the call to dev_pm_domain_set() is a regular spinlock.
+
+To fix the problem, let's simply move the calls to dev_pm_domain_set()
+outside the genpd-lock.
+
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+Tested-by: Raghavendra Kakarla <quic_rkakarla@quicinc.com> # qcm6490 with PREEMPT_RT set
+Acked-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Link: https://lore.kernel.org/r/20240527142557.321610-3-ulf.hansson@linaro.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pmdomain/core.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/pmdomain/core.c b/drivers/pmdomain/core.c
+index 0ab6008e863e8..4134a8344d2da 100644
+--- a/drivers/pmdomain/core.c
++++ b/drivers/pmdomain/core.c
+@@ -1694,7 +1694,6 @@ static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
+ genpd_lock(genpd);
+
+ genpd_set_cpumask(genpd, gpd_data->cpu);
+- dev_pm_domain_set(dev, &genpd->domain);
+
+ genpd->device_count++;
+ if (gd)
+@@ -1703,6 +1702,7 @@ static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
+ list_add_tail(&gpd_data->base.list_node, &genpd->dev_list);
+
+ genpd_unlock(genpd);
++ dev_pm_domain_set(dev, &genpd->domain);
+ out:
+ if (ret)
+ genpd_free_dev_data(dev, gpd_data);
+@@ -1759,12 +1759,13 @@ static int genpd_remove_device(struct generic_pm_domain *genpd,
+ genpd->gd->max_off_time_changed = true;
+
+ genpd_clear_cpumask(genpd, gpd_data->cpu);
+- dev_pm_domain_set(dev, NULL);
+
+ list_del_init(&pdd->list_node);
+
+ genpd_unlock(genpd);
+
++ dev_pm_domain_set(dev, NULL);
++
+ if (genpd->detach_dev)
+ genpd->detach_dev(genpd, dev);
+
+--
+2.43.0
+
--- /dev/null
+From 8389003eca426ab13f51e908c3034ec0e4a56de2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 10 Jun 2024 09:28:36 -0500
+Subject: power: reset: brcmstb: Do not go into infinite loop if reset fails
+
+From: Andrew Davis <afd@ti.com>
+
+[ Upstream commit cf8c39b00e982fa506b16f9d76657838c09150cb ]
+
+There may be other backup reset methods available, do not halt
+here so that other reset methods can be tried.
+
+Signed-off-by: Andrew Davis <afd@ti.com>
+Reviewed-by: Dhruva Gole <d-gole@ti.com>
+Acked-by: Florian Fainelli <florian.fainelli@broadcom.com>
+Link: https://lore.kernel.org/r/20240610142836.168603-5-afd@ti.com
+Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/power/reset/brcmstb-reboot.c | 3 ---
+ 1 file changed, 3 deletions(-)
+
+diff --git a/drivers/power/reset/brcmstb-reboot.c b/drivers/power/reset/brcmstb-reboot.c
+index 0f2944dc93551..a04713f191a11 100644
+--- a/drivers/power/reset/brcmstb-reboot.c
++++ b/drivers/power/reset/brcmstb-reboot.c
+@@ -62,9 +62,6 @@ static int brcmstb_restart_handler(struct notifier_block *this,
+ return NOTIFY_DONE;
+ }
+
+- while (1)
+- ;
+-
+ return NOTIFY_DONE;
+ }
+
+--
+2.43.0
+
--- /dev/null
+From 2ee66c001378c865bf341a1eda4eea5b6580d93e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 21 Aug 2024 19:50:26 -0700
+Subject: powerpc/pseries: Use correct data types from pseries_hp_errorlog
+ struct
+
+From: Haren Myneni <haren@linux.ibm.com>
+
+[ Upstream commit b76e0d4215b6b622127ebcceaa7f603313ceaec4 ]
+
+_be32 type is defined for some elements in pseries_hp_errorlog
+struct but also used them u32 after be32_to_cpu() conversion.
+
+Example: In handle_dlpar_errorlog()
+hp_elog->_drc_u.drc_index = be32_to_cpu(hp_elog->_drc_u.drc_index);
+
+And later assigned to u32 type
+dlpar_cpu() - u32 drc_index = hp_elog->_drc_u.drc_index;
+
+This incorrect usage is giving the following warnings and the
+patch resolve these warnings with the correct assignment.
+
+arch/powerpc/platforms/pseries/dlpar.c:398:53: sparse: sparse:
+incorrect type in argument 1 (different base types) @@
+expected unsigned int [usertype] drc_index @@
+got restricted __be32 [usertype] drc_index @@
+...
+arch/powerpc/platforms/pseries/dlpar.c:418:43: sparse: sparse:
+incorrect type in assignment (different base types) @@
+expected restricted __be32 [usertype] drc_count @@
+got unsigned int [usertype] @@
+
+Reported-by: kernel test robot <lkp@intel.com>
+Closes: https://lore.kernel.org/oe-kbuild-all/202408182142.wuIKqYae-lkp@intel.com/
+Closes: https://lore.kernel.org/oe-kbuild-all/202408182302.o7QRO45S-lkp@intel.com/
+Signed-off-by: Haren Myneni <haren@linux.ibm.com>
+
+v3:
+- Fix warnings from using incorrect data types in pseries_hp_errorlog
+ struct
+v2:
+- Remove pr_info() and TODO comments
+- Update more information in the commit logs
+
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+Link: https://msgid.link/20240822025028.938332-1-haren@linux.ibm.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/powerpc/platforms/pseries/dlpar.c | 17 -----------------
+ arch/powerpc/platforms/pseries/hotplug-cpu.c | 2 +-
+ arch/powerpc/platforms/pseries/hotplug-memory.c | 16 ++++++++--------
+ arch/powerpc/platforms/pseries/pmem.c | 2 +-
+ 4 files changed, 10 insertions(+), 27 deletions(-)
+
+diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c
+index 47f8eabd1bee3..9873b916b2370 100644
+--- a/arch/powerpc/platforms/pseries/dlpar.c
++++ b/arch/powerpc/platforms/pseries/dlpar.c
+@@ -334,23 +334,6 @@ int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_elog)
+ {
+ int rc;
+
+- /* pseries error logs are in BE format, convert to cpu type */
+- switch (hp_elog->id_type) {
+- case PSERIES_HP_ELOG_ID_DRC_COUNT:
+- hp_elog->_drc_u.drc_count =
+- be32_to_cpu(hp_elog->_drc_u.drc_count);
+- break;
+- case PSERIES_HP_ELOG_ID_DRC_INDEX:
+- hp_elog->_drc_u.drc_index =
+- be32_to_cpu(hp_elog->_drc_u.drc_index);
+- break;
+- case PSERIES_HP_ELOG_ID_DRC_IC:
+- hp_elog->_drc_u.ic.count =
+- be32_to_cpu(hp_elog->_drc_u.ic.count);
+- hp_elog->_drc_u.ic.index =
+- be32_to_cpu(hp_elog->_drc_u.ic.index);
+- }
+-
+ switch (hp_elog->resource) {
+ case PSERIES_HP_ELOG_RESOURCE_MEM:
+ rc = dlpar_memory(hp_elog);
+diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
+index e62835a12d73f..6838a0fcda296 100644
+--- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
++++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
+@@ -757,7 +757,7 @@ int dlpar_cpu(struct pseries_hp_errorlog *hp_elog)
+ u32 drc_index;
+ int rc;
+
+- drc_index = hp_elog->_drc_u.drc_index;
++ drc_index = be32_to_cpu(hp_elog->_drc_u.drc_index);
+
+ lock_device_hotplug();
+
+diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c
+index 3fe3ddb30c04b..38dc4f7c9296b 100644
+--- a/arch/powerpc/platforms/pseries/hotplug-memory.c
++++ b/arch/powerpc/platforms/pseries/hotplug-memory.c
+@@ -817,16 +817,16 @@ int dlpar_memory(struct pseries_hp_errorlog *hp_elog)
+ case PSERIES_HP_ELOG_ACTION_ADD:
+ switch (hp_elog->id_type) {
+ case PSERIES_HP_ELOG_ID_DRC_COUNT:
+- count = hp_elog->_drc_u.drc_count;
++ count = be32_to_cpu(hp_elog->_drc_u.drc_count);
+ rc = dlpar_memory_add_by_count(count);
+ break;
+ case PSERIES_HP_ELOG_ID_DRC_INDEX:
+- drc_index = hp_elog->_drc_u.drc_index;
++ drc_index = be32_to_cpu(hp_elog->_drc_u.drc_index);
+ rc = dlpar_memory_add_by_index(drc_index);
+ break;
+ case PSERIES_HP_ELOG_ID_DRC_IC:
+- count = hp_elog->_drc_u.ic.count;
+- drc_index = hp_elog->_drc_u.ic.index;
++ count = be32_to_cpu(hp_elog->_drc_u.ic.count);
++ drc_index = be32_to_cpu(hp_elog->_drc_u.ic.index);
+ rc = dlpar_memory_add_by_ic(count, drc_index);
+ break;
+ default:
+@@ -838,16 +838,16 @@ int dlpar_memory(struct pseries_hp_errorlog *hp_elog)
+ case PSERIES_HP_ELOG_ACTION_REMOVE:
+ switch (hp_elog->id_type) {
+ case PSERIES_HP_ELOG_ID_DRC_COUNT:
+- count = hp_elog->_drc_u.drc_count;
++ count = be32_to_cpu(hp_elog->_drc_u.drc_count);
+ rc = dlpar_memory_remove_by_count(count);
+ break;
+ case PSERIES_HP_ELOG_ID_DRC_INDEX:
+- drc_index = hp_elog->_drc_u.drc_index;
++ drc_index = be32_to_cpu(hp_elog->_drc_u.drc_index);
+ rc = dlpar_memory_remove_by_index(drc_index);
+ break;
+ case PSERIES_HP_ELOG_ID_DRC_IC:
+- count = hp_elog->_drc_u.ic.count;
+- drc_index = hp_elog->_drc_u.ic.index;
++ count = be32_to_cpu(hp_elog->_drc_u.ic.count);
++ drc_index = be32_to_cpu(hp_elog->_drc_u.ic.index);
+ rc = dlpar_memory_remove_by_ic(count, drc_index);
+ break;
+ default:
+diff --git a/arch/powerpc/platforms/pseries/pmem.c b/arch/powerpc/platforms/pseries/pmem.c
+index 3c290b9ed01b3..0f1d45f32e4a4 100644
+--- a/arch/powerpc/platforms/pseries/pmem.c
++++ b/arch/powerpc/platforms/pseries/pmem.c
+@@ -121,7 +121,7 @@ int dlpar_hp_pmem(struct pseries_hp_errorlog *hp_elog)
+ return -EINVAL;
+ }
+
+- drc_index = hp_elog->_drc_u.drc_index;
++ drc_index = be32_to_cpu(hp_elog->_drc_u.drc_index);
+
+ lock_device_hotplug();
+
+--
+2.43.0
+
--- /dev/null
+From ec7e21060791ea3fe19dcf7480f5f2669ba287c5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 2 Aug 2024 11:02:25 +0300
+Subject: proc: add config & param to block forcing mem writes
+
+From: Adrian Ratiu <adrian.ratiu@collabora.com>
+
+[ Upstream commit 41e8149c8892ed1962bd15350b3c3e6e90cba7f4 ]
+
+This adds a Kconfig option and boot param to allow removing
+the FOLL_FORCE flag from /proc/pid/mem write calls because
+it can be abused.
+
+The traditional forcing behavior is kept as default because
+it can break GDB and some other use cases.
+
+Previously we tried a more sophisticated approach allowing
+distributions to fine-tune /proc/pid/mem behavior, however
+that got NAK-ed by Linus [1], who prefers this simpler
+approach with semantics also easier to understand for users.
+
+Link: https://lore.kernel.org/lkml/CAHk-=wiGWLChxYmUA5HrT5aopZrB7_2VTa0NLZcxORgkUe5tEQ@mail.gmail.com/ [1]
+Cc: Doug Anderson <dianders@chromium.org>
+Cc: Jeff Xu <jeffxu@google.com>
+Cc: Jann Horn <jannh@google.com>
+Cc: Kees Cook <kees@kernel.org>
+Cc: Ard Biesheuvel <ardb@kernel.org>
+Cc: Christian Brauner <brauner@kernel.org>
+Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com>
+Link: https://lore.kernel.org/r/20240802080225.89408-1-adrian.ratiu@collabora.com
+Signed-off-by: Christian Brauner <brauner@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../admin-guide/kernel-parameters.txt | 10 +++
+ fs/proc/base.c | 61 ++++++++++++++++++-
+ security/Kconfig | 32 ++++++++++
+ 3 files changed, 102 insertions(+), 1 deletion(-)
+
+diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
+index c82446cef8e21..2c8e062eb2ce5 100644
+--- a/Documentation/admin-guide/kernel-parameters.txt
++++ b/Documentation/admin-guide/kernel-parameters.txt
+@@ -4791,6 +4791,16 @@
+ printk.time= Show timing data prefixed to each printk message line
+ Format: <bool> (1/Y/y=enable, 0/N/n=disable)
+
++ proc_mem.force_override= [KNL]
++ Format: {always | ptrace | never}
++ Traditionally /proc/pid/mem allows memory permissions to be
++ overridden without restrictions. This option may be set to
++ restrict that. Can be one of:
++ - 'always': traditional behavior always allows mem overrides.
++ - 'ptrace': only allow mem overrides for active ptracers.
++ - 'never': never allow mem overrides.
++ If not specified, default is the CONFIG_PROC_MEM_* choice.
++
+ processor.max_cstate= [HW,ACPI]
+ Limit processor to maximum C-state
+ max_cstate=9 overrides any DMI blacklist limit.
+diff --git a/fs/proc/base.c b/fs/proc/base.c
+index 72a1acd03675c..f389c69767fa5 100644
+--- a/fs/proc/base.c
++++ b/fs/proc/base.c
+@@ -85,6 +85,7 @@
+ #include <linux/elf.h>
+ #include <linux/pid_namespace.h>
+ #include <linux/user_namespace.h>
++#include <linux/fs_parser.h>
+ #include <linux/fs_struct.h>
+ #include <linux/slab.h>
+ #include <linux/sched/autogroup.h>
+@@ -117,6 +118,40 @@
+ static u8 nlink_tid __ro_after_init;
+ static u8 nlink_tgid __ro_after_init;
+
++enum proc_mem_force {
++ PROC_MEM_FORCE_ALWAYS,
++ PROC_MEM_FORCE_PTRACE,
++ PROC_MEM_FORCE_NEVER
++};
++
++static enum proc_mem_force proc_mem_force_override __ro_after_init =
++ IS_ENABLED(CONFIG_PROC_MEM_NO_FORCE) ? PROC_MEM_FORCE_NEVER :
++ IS_ENABLED(CONFIG_PROC_MEM_FORCE_PTRACE) ? PROC_MEM_FORCE_PTRACE :
++ PROC_MEM_FORCE_ALWAYS;
++
++static const struct constant_table proc_mem_force_table[] __initconst = {
++ { "always", PROC_MEM_FORCE_ALWAYS },
++ { "ptrace", PROC_MEM_FORCE_PTRACE },
++ { "never", PROC_MEM_FORCE_NEVER },
++ { }
++};
++
++static int __init early_proc_mem_force_override(char *buf)
++{
++ if (!buf)
++ return -EINVAL;
++
++ /*
++ * lookup_constant() defaults to proc_mem_force_override to preseve
++ * the initial Kconfig choice in case an invalid param gets passed.
++ */
++ proc_mem_force_override = lookup_constant(proc_mem_force_table,
++ buf, proc_mem_force_override);
++
++ return 0;
++}
++early_param("proc_mem.force_override", early_proc_mem_force_override);
++
+ struct pid_entry {
+ const char *name;
+ unsigned int len;
+@@ -835,6 +870,28 @@ static int mem_open(struct inode *inode, struct file *file)
+ return ret;
+ }
+
++static bool proc_mem_foll_force(struct file *file, struct mm_struct *mm)
++{
++ struct task_struct *task;
++ bool ptrace_active = false;
++
++ switch (proc_mem_force_override) {
++ case PROC_MEM_FORCE_NEVER:
++ return false;
++ case PROC_MEM_FORCE_PTRACE:
++ task = get_proc_task(file_inode(file));
++ if (task) {
++ ptrace_active = READ_ONCE(task->ptrace) &&
++ READ_ONCE(task->mm) == mm &&
++ READ_ONCE(task->parent) == current;
++ put_task_struct(task);
++ }
++ return ptrace_active;
++ default:
++ return true;
++ }
++}
++
+ static ssize_t mem_rw(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos, int write)
+ {
+@@ -855,7 +912,9 @@ static ssize_t mem_rw(struct file *file, char __user *buf,
+ if (!mmget_not_zero(mm))
+ goto free;
+
+- flags = FOLL_FORCE | (write ? FOLL_WRITE : 0);
++ flags = write ? FOLL_WRITE : 0;
++ if (proc_mem_foll_force(file, mm))
++ flags |= FOLL_FORCE;
+
+ while (count > 0) {
+ size_t this_len = min_t(size_t, count, PAGE_SIZE);
+diff --git a/security/Kconfig b/security/Kconfig
+index 412e76f1575d0..a93c1a9b7c283 100644
+--- a/security/Kconfig
++++ b/security/Kconfig
+@@ -19,6 +19,38 @@ config SECURITY_DMESG_RESTRICT
+
+ If you are unsure how to answer this question, answer N.
+
++choice
++ prompt "Allow /proc/pid/mem access override"
++ default PROC_MEM_ALWAYS_FORCE
++ help
++ Traditionally /proc/pid/mem allows users to override memory
++ permissions for users like ptrace, assuming they have ptrace
++ capability.
++
++ This allows people to limit that - either never override, or
++ require actual active ptrace attachment.
++
++ Defaults to the traditional behavior (for now)
++
++config PROC_MEM_ALWAYS_FORCE
++ bool "Traditional /proc/pid/mem behavior"
++ help
++ This allows /proc/pid/mem accesses to override memory mapping
++ permissions if you have ptrace access rights.
++
++config PROC_MEM_FORCE_PTRACE
++ bool "Require active ptrace() use for access override"
++ help
++ This allows /proc/pid/mem accesses to override memory mapping
++ permissions for active ptracers like gdb.
++
++config PROC_MEM_NO_FORCE
++ bool "Never"
++ help
++ Never override memory mapping permissions
++
++endchoice
++
+ config SECURITY
+ bool "Enable different security models"
+ depends on SYSFS
+--
+2.43.0
+
--- /dev/null
+From b378184a28d14ec00c295e7e5037478cb37354e7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 10 Jul 2024 12:45:42 +0800
+Subject: rcu-tasks: Fix access non-existent percpu rtpcp variable in
+ rcu_tasks_need_gpcb()
+
+From: Zqiang <qiang.zhang1211@gmail.com>
+
+[ Upstream commit fd70e9f1d85f5323096ad313ba73f5fe3d15ea41 ]
+
+For kernels built with CONFIG_FORCE_NR_CPUS=y, the nr_cpu_ids is
+defined as NR_CPUS instead of the number of possible cpus, this
+will cause the following system panic:
+
+smpboot: Allowing 4 CPUs, 0 hotplug CPUs
+...
+setup_percpu: NR_CPUS:512 nr_cpumask_bits:512 nr_cpu_ids:512 nr_node_ids:1
+...
+BUG: unable to handle page fault for address: ffffffff9911c8c8
+Oops: 0000 [#1] PREEMPT SMP PTI
+CPU: 0 PID: 15 Comm: rcu_tasks_trace Tainted: G W
+6.6.21 #1 5dc7acf91a5e8e9ac9dcfc35bee0245691283ea6
+RIP: 0010:rcu_tasks_need_gpcb+0x25d/0x2c0
+RSP: 0018:ffffa371c00a3e60 EFLAGS: 00010082
+CR2: ffffffff9911c8c8 CR3: 000000040fa20005 CR4: 00000000001706f0
+Call Trace:
+<TASK>
+? __die+0x23/0x80
+? page_fault_oops+0xa4/0x180
+? exc_page_fault+0x152/0x180
+? asm_exc_page_fault+0x26/0x40
+? rcu_tasks_need_gpcb+0x25d/0x2c0
+? __pfx_rcu_tasks_kthread+0x40/0x40
+rcu_tasks_one_gp+0x69/0x180
+rcu_tasks_kthread+0x94/0xc0
+kthread+0xe8/0x140
+? __pfx_kthread+0x40/0x40
+ret_from_fork+0x34/0x80
+? __pfx_kthread+0x40/0x40
+ret_from_fork_asm+0x1b/0x80
+</TASK>
+
+Considering that there may be holes in the CPU numbers, use the
+maximum possible cpu number, instead of nr_cpu_ids, for configuring
+enqueue and dequeue limits.
+
+[ neeraj.upadhyay: Fix htmldocs build error reported by Stephen Rothwell ]
+
+Closes: https://lore.kernel.org/linux-input/CALMA0xaTSMN+p4xUXkzrtR5r6k7hgoswcaXx7baR_z9r5jjskw@mail.gmail.com/T/#u
+Reported-by: Zhixu Liu <zhixu.liu@gmail.com>
+Signed-off-by: Zqiang <qiang.zhang1211@gmail.com>
+Signed-off-by: Neeraj Upadhyay <neeraj.upadhyay@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/rcu/tasks.h | 82 ++++++++++++++++++++++++++++++----------------
+ 1 file changed, 53 insertions(+), 29 deletions(-)
+
+diff --git a/kernel/rcu/tasks.h b/kernel/rcu/tasks.h
+index ba3440a45b6dd..bc8429ada7a51 100644
+--- a/kernel/rcu/tasks.h
++++ b/kernel/rcu/tasks.h
+@@ -34,6 +34,7 @@ typedef void (*postgp_func_t)(struct rcu_tasks *rtp);
+ * @rtp_blkd_tasks: List of tasks blocked as readers.
+ * @rtp_exit_list: List of tasks in the latter portion of do_exit().
+ * @cpu: CPU number corresponding to this entry.
++ * @index: Index of this CPU in rtpcp_array of the rcu_tasks structure.
+ * @rtpp: Pointer to the rcu_tasks structure.
+ */
+ struct rcu_tasks_percpu {
+@@ -49,6 +50,7 @@ struct rcu_tasks_percpu {
+ struct list_head rtp_blkd_tasks;
+ struct list_head rtp_exit_list;
+ int cpu;
++ int index;
+ struct rcu_tasks *rtpp;
+ };
+
+@@ -76,6 +78,7 @@ struct rcu_tasks_percpu {
+ * @call_func: This flavor's call_rcu()-equivalent function.
+ * @wait_state: Task state for synchronous grace-period waits (default TASK_UNINTERRUPTIBLE).
+ * @rtpcpu: This flavor's rcu_tasks_percpu structure.
++ * @rtpcp_array: Array of pointers to rcu_tasks_percpu structure of CPUs in cpu_possible_mask.
+ * @percpu_enqueue_shift: Shift down CPU ID this much when enqueuing callbacks.
+ * @percpu_enqueue_lim: Number of per-CPU callback queues in use for enqueuing.
+ * @percpu_dequeue_lim: Number of per-CPU callback queues in use for dequeuing.
+@@ -110,6 +113,7 @@ struct rcu_tasks {
+ call_rcu_func_t call_func;
+ unsigned int wait_state;
+ struct rcu_tasks_percpu __percpu *rtpcpu;
++ struct rcu_tasks_percpu **rtpcp_array;
+ int percpu_enqueue_shift;
+ int percpu_enqueue_lim;
+ int percpu_dequeue_lim;
+@@ -182,6 +186,8 @@ module_param(rcu_task_collapse_lim, int, 0444);
+ static int rcu_task_lazy_lim __read_mostly = 32;
+ module_param(rcu_task_lazy_lim, int, 0444);
+
++static int rcu_task_cpu_ids;
++
+ /* RCU tasks grace-period state for debugging. */
+ #define RTGS_INIT 0
+ #define RTGS_WAIT_WAIT_CBS 1
+@@ -245,6 +251,8 @@ static void cblist_init_generic(struct rcu_tasks *rtp)
+ int cpu;
+ int lim;
+ int shift;
++ int maxcpu;
++ int index = 0;
+
+ if (rcu_task_enqueue_lim < 0) {
+ rcu_task_enqueue_lim = 1;
+@@ -254,14 +262,9 @@ static void cblist_init_generic(struct rcu_tasks *rtp)
+ }
+ lim = rcu_task_enqueue_lim;
+
+- if (lim > nr_cpu_ids)
+- lim = nr_cpu_ids;
+- shift = ilog2(nr_cpu_ids / lim);
+- if (((nr_cpu_ids - 1) >> shift) >= lim)
+- shift++;
+- WRITE_ONCE(rtp->percpu_enqueue_shift, shift);
+- WRITE_ONCE(rtp->percpu_dequeue_lim, lim);
+- smp_store_release(&rtp->percpu_enqueue_lim, lim);
++ rtp->rtpcp_array = kcalloc(num_possible_cpus(), sizeof(struct rcu_tasks_percpu *), GFP_KERNEL);
++ BUG_ON(!rtp->rtpcp_array);
++
+ for_each_possible_cpu(cpu) {
+ struct rcu_tasks_percpu *rtpcp = per_cpu_ptr(rtp->rtpcpu, cpu);
+
+@@ -273,14 +276,29 @@ static void cblist_init_generic(struct rcu_tasks *rtp)
+ INIT_WORK(&rtpcp->rtp_work, rcu_tasks_invoke_cbs_wq);
+ rtpcp->cpu = cpu;
+ rtpcp->rtpp = rtp;
++ rtpcp->index = index;
++ rtp->rtpcp_array[index] = rtpcp;
++ index++;
+ if (!rtpcp->rtp_blkd_tasks.next)
+ INIT_LIST_HEAD(&rtpcp->rtp_blkd_tasks);
+ if (!rtpcp->rtp_exit_list.next)
+ INIT_LIST_HEAD(&rtpcp->rtp_exit_list);
++ maxcpu = cpu;
+ }
+
+- pr_info("%s: Setting shift to %d and lim to %d rcu_task_cb_adjust=%d.\n", rtp->name,
+- data_race(rtp->percpu_enqueue_shift), data_race(rtp->percpu_enqueue_lim), rcu_task_cb_adjust);
++ rcu_task_cpu_ids = maxcpu + 1;
++ if (lim > rcu_task_cpu_ids)
++ lim = rcu_task_cpu_ids;
++ shift = ilog2(rcu_task_cpu_ids / lim);
++ if (((rcu_task_cpu_ids - 1) >> shift) >= lim)
++ shift++;
++ WRITE_ONCE(rtp->percpu_enqueue_shift, shift);
++ WRITE_ONCE(rtp->percpu_dequeue_lim, lim);
++ smp_store_release(&rtp->percpu_enqueue_lim, lim);
++
++ pr_info("%s: Setting shift to %d and lim to %d rcu_task_cb_adjust=%d rcu_task_cpu_ids=%d.\n",
++ rtp->name, data_race(rtp->percpu_enqueue_shift), data_race(rtp->percpu_enqueue_lim),
++ rcu_task_cb_adjust, rcu_task_cpu_ids);
+ }
+
+ // Compute wakeup time for lazy callback timer.
+@@ -348,7 +366,7 @@ static void call_rcu_tasks_generic(struct rcu_head *rhp, rcu_callback_t func,
+ rtpcp->rtp_n_lock_retries = 0;
+ }
+ if (rcu_task_cb_adjust && ++rtpcp->rtp_n_lock_retries > rcu_task_contend_lim &&
+- READ_ONCE(rtp->percpu_enqueue_lim) != nr_cpu_ids)
++ READ_ONCE(rtp->percpu_enqueue_lim) != rcu_task_cpu_ids)
+ needadjust = true; // Defer adjustment to avoid deadlock.
+ }
+ // Queuing callbacks before initialization not yet supported.
+@@ -368,10 +386,10 @@ static void call_rcu_tasks_generic(struct rcu_head *rhp, rcu_callback_t func,
+ raw_spin_unlock_irqrestore_rcu_node(rtpcp, flags);
+ if (unlikely(needadjust)) {
+ raw_spin_lock_irqsave(&rtp->cbs_gbl_lock, flags);
+- if (rtp->percpu_enqueue_lim != nr_cpu_ids) {
++ if (rtp->percpu_enqueue_lim != rcu_task_cpu_ids) {
+ WRITE_ONCE(rtp->percpu_enqueue_shift, 0);
+- WRITE_ONCE(rtp->percpu_dequeue_lim, nr_cpu_ids);
+- smp_store_release(&rtp->percpu_enqueue_lim, nr_cpu_ids);
++ WRITE_ONCE(rtp->percpu_dequeue_lim, rcu_task_cpu_ids);
++ smp_store_release(&rtp->percpu_enqueue_lim, rcu_task_cpu_ids);
+ pr_info("Switching %s to per-CPU callback queuing.\n", rtp->name);
+ }
+ raw_spin_unlock_irqrestore(&rtp->cbs_gbl_lock, flags);
+@@ -444,6 +462,8 @@ static int rcu_tasks_need_gpcb(struct rcu_tasks *rtp)
+
+ dequeue_limit = smp_load_acquire(&rtp->percpu_dequeue_lim);
+ for (cpu = 0; cpu < dequeue_limit; cpu++) {
++ if (!cpu_possible(cpu))
++ continue;
+ struct rcu_tasks_percpu *rtpcp = per_cpu_ptr(rtp->rtpcpu, cpu);
+
+ /* Advance and accelerate any new callbacks. */
+@@ -481,7 +501,7 @@ static int rcu_tasks_need_gpcb(struct rcu_tasks *rtp)
+ if (rcu_task_cb_adjust && ncbs <= rcu_task_collapse_lim) {
+ raw_spin_lock_irqsave(&rtp->cbs_gbl_lock, flags);
+ if (rtp->percpu_enqueue_lim > 1) {
+- WRITE_ONCE(rtp->percpu_enqueue_shift, order_base_2(nr_cpu_ids));
++ WRITE_ONCE(rtp->percpu_enqueue_shift, order_base_2(rcu_task_cpu_ids));
+ smp_store_release(&rtp->percpu_enqueue_lim, 1);
+ rtp->percpu_dequeue_gpseq = get_state_synchronize_rcu();
+ gpdone = false;
+@@ -496,7 +516,9 @@ static int rcu_tasks_need_gpcb(struct rcu_tasks *rtp)
+ pr_info("Completing switch %s to CPU-0 callback queuing.\n", rtp->name);
+ }
+ if (rtp->percpu_dequeue_lim == 1) {
+- for (cpu = rtp->percpu_dequeue_lim; cpu < nr_cpu_ids; cpu++) {
++ for (cpu = rtp->percpu_dequeue_lim; cpu < rcu_task_cpu_ids; cpu++) {
++ if (!cpu_possible(cpu))
++ continue;
+ struct rcu_tasks_percpu *rtpcp = per_cpu_ptr(rtp->rtpcpu, cpu);
+
+ WARN_ON_ONCE(rcu_segcblist_n_cbs(&rtpcp->cblist));
+@@ -511,30 +533,32 @@ static int rcu_tasks_need_gpcb(struct rcu_tasks *rtp)
+ // Advance callbacks and invoke any that are ready.
+ static void rcu_tasks_invoke_cbs(struct rcu_tasks *rtp, struct rcu_tasks_percpu *rtpcp)
+ {
+- int cpu;
+- int cpunext;
+ int cpuwq;
+ unsigned long flags;
+ int len;
++ int index;
+ struct rcu_head *rhp;
+ struct rcu_cblist rcl = RCU_CBLIST_INITIALIZER(rcl);
+ struct rcu_tasks_percpu *rtpcp_next;
+
+- cpu = rtpcp->cpu;
+- cpunext = cpu * 2 + 1;
+- if (cpunext < smp_load_acquire(&rtp->percpu_dequeue_lim)) {
+- rtpcp_next = per_cpu_ptr(rtp->rtpcpu, cpunext);
+- cpuwq = rcu_cpu_beenfullyonline(cpunext) ? cpunext : WORK_CPU_UNBOUND;
+- queue_work_on(cpuwq, system_wq, &rtpcp_next->rtp_work);
+- cpunext++;
+- if (cpunext < smp_load_acquire(&rtp->percpu_dequeue_lim)) {
+- rtpcp_next = per_cpu_ptr(rtp->rtpcpu, cpunext);
+- cpuwq = rcu_cpu_beenfullyonline(cpunext) ? cpunext : WORK_CPU_UNBOUND;
++ index = rtpcp->index * 2 + 1;
++ if (index < num_possible_cpus()) {
++ rtpcp_next = rtp->rtpcp_array[index];
++ if (rtpcp_next->cpu < smp_load_acquire(&rtp->percpu_dequeue_lim)) {
++ cpuwq = rcu_cpu_beenfullyonline(rtpcp_next->cpu) ? rtpcp_next->cpu : WORK_CPU_UNBOUND;
+ queue_work_on(cpuwq, system_wq, &rtpcp_next->rtp_work);
++ index++;
++ if (index < num_possible_cpus()) {
++ rtpcp_next = rtp->rtpcp_array[index];
++ if (rtpcp_next->cpu < smp_load_acquire(&rtp->percpu_dequeue_lim)) {
++ cpuwq = rcu_cpu_beenfullyonline(rtpcp_next->cpu) ? rtpcp_next->cpu : WORK_CPU_UNBOUND;
++ queue_work_on(cpuwq, system_wq, &rtpcp_next->rtp_work);
++ }
++ }
+ }
+ }
+
+- if (rcu_segcblist_empty(&rtpcp->cblist) || !cpu_possible(cpu))
++ if (rcu_segcblist_empty(&rtpcp->cblist))
+ return;
+ raw_spin_lock_irqsave_rcu_node(rtpcp, flags);
+ rcu_segcblist_advance(&rtpcp->cblist, rcu_seq_current(&rtp->tasks_gp_seq));
+--
+2.43.0
+
--- /dev/null
+From 2ab445bbd31de18a7c7497872a84b18f3c597ad0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 1 Aug 2024 17:43:03 -0700
+Subject: rcuscale: Provide clear error when async specified without primitives
+
+From: Paul E. McKenney <paulmck@kernel.org>
+
+[ Upstream commit 11377947b5861fa59bf77c827e1dd7c081842cc9 ]
+
+Currently, if the rcuscale module's async module parameter is specified
+for RCU implementations that do not have async primitives such as RCU
+Tasks Rude (which now lacks a call_rcu_tasks_rude() function), there
+will be a series of splats due to calls to a NULL pointer. This commit
+therefore warns of this situation, but switches to non-async testing.
+
+Signed-off-by: "Paul E. McKenney" <paulmck@kernel.org>
+Signed-off-by: Neeraj Upadhyay <neeraj.upadhyay@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/rcu/rcuscale.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/kernel/rcu/rcuscale.c b/kernel/rcu/rcuscale.c
+index 8db4fedaaa1eb..a5806baa1a2a8 100644
+--- a/kernel/rcu/rcuscale.c
++++ b/kernel/rcu/rcuscale.c
+@@ -498,7 +498,7 @@ rcu_scale_writer(void *arg)
+ schedule_timeout_idle(torture_random(&tr) % writer_holdoff_jiffies + 1);
+ wdp = &wdpp[i];
+ *wdp = ktime_get_mono_fast_ns();
+- if (gp_async) {
++ if (gp_async && !WARN_ON_ONCE(!cur_ops->async)) {
+ retry:
+ if (!rhp)
+ rhp = kmalloc(sizeof(*rhp), GFP_KERNEL);
+@@ -554,7 +554,7 @@ rcu_scale_writer(void *arg)
+ i++;
+ rcu_scale_wait_shutdown();
+ } while (!torture_must_stop());
+- if (gp_async) {
++ if (gp_async && cur_ops->async) {
+ cur_ops->gp_barrier();
+ }
+ writer_n_durations[me] = i_max + 1;
+--
+2.43.0
+
--- /dev/null
+From b31f13e7acfa95b95e17e607dd658ada07ced947 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 11 Jul 2024 14:57:37 -0700
+Subject: scsi: aacraid: Rearrange order of struct aac_srb_unit
+
+From: Kees Cook <kees@kernel.org>
+
+[ Upstream commit 6e5860b0ad4934baee8c7a202c02033b2631bb44 ]
+
+struct aac_srb_unit contains struct aac_srb, which contains struct sgmap,
+which ends in a (currently) "fake" (1-element) flexible array. Converting
+this to a flexible array is needed so that runtime bounds checking won't
+think the array is fixed size (i.e. under CONFIG_FORTIFY_SOURCE=y and/or
+CONFIG_UBSAN_BOUNDS=y), as other parts of aacraid use struct sgmap as a
+flexible array.
+
+It is not legal to have a flexible array in the middle of a structure, so
+it either needs to be split up or rearranged so that it is at the end of
+the structure. Luckily, struct aac_srb_unit, which is exclusively
+consumed/updated by aac_send_safw_bmic_cmd(), does not depend on member
+ordering.
+
+The values set in the on-stack struct aac_srb_unit instance "srbu" by the
+only two callers, aac_issue_safw_bmic_identify() and
+aac_get_safw_ciss_luns(), do not contain anything in srbu.srb.sgmap.sg, and
+they both implicitly initialize srbu.srb.sgmap.count to 0 during
+memset(). For example:
+
+ memset(&srbu, 0, sizeof(struct aac_srb_unit));
+
+ srbcmd = &srbu.srb;
+ srbcmd->flags = cpu_to_le32(SRB_DataIn);
+ srbcmd->cdb[0] = CISS_REPORT_PHYSICAL_LUNS;
+ srbcmd->cdb[1] = 2; /* extended reporting */
+ srbcmd->cdb[8] = (u8)(datasize >> 8);
+ srbcmd->cdb[9] = (u8)(datasize);
+
+ rcode = aac_send_safw_bmic_cmd(dev, &srbu, phys_luns, datasize);
+
+During aac_send_safw_bmic_cmd(), a separate srb is mapped into DMA, and has
+srbu.srb copied into it:
+
+ srb = fib_data(fibptr);
+ memcpy(srb, &srbu->srb, sizeof(struct aac_srb));
+
+Only then is srb.sgmap.count written and srb->sg populated:
+
+ srb->count = cpu_to_le32(xfer_len);
+
+ sg64 = (struct sgmap64 *)&srb->sg;
+ sg64->count = cpu_to_le32(1);
+ sg64->sg[0].addr[1] = cpu_to_le32(upper_32_bits(addr));
+ sg64->sg[0].addr[0] = cpu_to_le32(lower_32_bits(addr));
+ sg64->sg[0].count = cpu_to_le32(xfer_len);
+
+But this is happening in the DMA memory, not in srbu.srb. An attempt to
+copy the changes back to srbu does happen:
+
+ /*
+ * Copy the updated data for other dumping or other usage if
+ * needed
+ */
+ memcpy(&srbu->srb, srb, sizeof(struct aac_srb));
+
+But this was never correct: the sg64 (3 u32s) overlap of srb.sg (2 u32s)
+always meant that srbu.srb would have held truncated information and any
+attempt to walk srbu.srb.sg.sg based on the value of srbu.srb.sg.count
+would result in attempting to parse past the end of srbu.srb.sg.sg[0] into
+srbu.srb_reply.
+
+After getting a reply from hardware, the reply is copied into
+srbu.srb_reply:
+
+ srb_reply = (struct aac_srb_reply *)fib_data(fibptr);
+ memcpy(&srbu->srb_reply, srb_reply, sizeof(struct aac_srb_reply));
+
+This has always been fixed-size, so there's no issue here. It is worth
+noting that the two callers _never check_ srbu contents -- neither
+srbu.srb nor srbu.srb_reply is examined. (They depend on the mapped
+xfer_buf instead.)
+
+Therefore, the ordering of members in struct aac_srb_unit does not matter,
+and the flexible array member can moved to the end.
+
+(Additionally, the two memcpy()s that update srbu could be entirely
+removed as they are never consumed, but I left that as-is.)
+
+Signed-off-by: Kees Cook <kees@kernel.org>
+Link: https://lore.kernel.org/r/20240711215739.208776-1-kees@kernel.org
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/aacraid/aacraid.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
+index 7d5a155073c62..9b66fa29fb05c 100644
+--- a/drivers/scsi/aacraid/aacraid.h
++++ b/drivers/scsi/aacraid/aacraid.h
+@@ -2029,8 +2029,8 @@ struct aac_srb_reply
+ };
+
+ struct aac_srb_unit {
+- struct aac_srb srb;
+ struct aac_srb_reply srb_reply;
++ struct aac_srb srb;
+ };
+
+ /*
+--
+2.43.0
+
--- /dev/null
+From 3dbd3631480ab7895b97913ce3c6af0b195977a9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 26 Jul 2024 16:15:09 -0700
+Subject: scsi: lpfc: Fix unsolicited FLOGI kref imbalance when in direct
+ attached topology
+
+From: Justin Tee <justin.tee@broadcom.com>
+
+[ Upstream commit b5c18c9dd138733c16893613345af44deadcf05e ]
+
+In direct attached topology, certain target vendors that are quick to issue
+FLOGI followed by a cable pull for more than dev_loss_tmo may result in a
+kref imbalance for the remote port ndlp object.
+
+Add an nlp_get when the defer_flogi_acc flag is set. This is expected to
+balance the nlp_put in the defer_flogi_acc clause in the
+lpfc_issue_els_flogi() routine. Because we need to retain the ndlp ptr,
+reorganize all of the defer_flogi_acc information into one
+lpfc_defer_flogi_acc struct.
+
+Signed-off-by: Justin Tee <justin.tee@broadcom.com>
+Link: https://lore.kernel.org/r/20240726231512.92867-6-justintee8345@gmail.com
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/lpfc/lpfc.h | 12 ++++++---
+ drivers/scsi/lpfc/lpfc_els.c | 46 +++++++++++++++++++-------------
+ drivers/scsi/lpfc/lpfc_hbadisc.c | 11 ++++++--
+ 3 files changed, 46 insertions(+), 23 deletions(-)
+
+diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
+index 7c147d6ea8a8f..e5a9c5a323f8b 100644
+--- a/drivers/scsi/lpfc/lpfc.h
++++ b/drivers/scsi/lpfc/lpfc.h
+@@ -306,6 +306,14 @@ struct lpfc_stats {
+
+ struct lpfc_hba;
+
++/* Data structure to keep withheld FLOGI_ACC information */
++struct lpfc_defer_flogi_acc {
++ bool flag;
++ u16 rx_id;
++ u16 ox_id;
++ struct lpfc_nodelist *ndlp;
++
++};
+
+ #define LPFC_VMID_TIMER 300 /* timer interval in seconds */
+
+@@ -1430,9 +1438,7 @@ struct lpfc_hba {
+ uint16_t vlan_id;
+ struct list_head fcf_conn_rec_list;
+
+- bool defer_flogi_acc_flag;
+- uint16_t defer_flogi_acc_rx_id;
+- uint16_t defer_flogi_acc_ox_id;
++ struct lpfc_defer_flogi_acc defer_flogi_acc;
+
+ spinlock_t ct_ev_lock; /* synchronize access to ct_ev_waiters */
+ struct list_head ct_ev_waiters;
+diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
+index 445cb6c2e80f5..9084976aa77e1 100644
+--- a/drivers/scsi/lpfc/lpfc_els.c
++++ b/drivers/scsi/lpfc/lpfc_els.c
+@@ -1390,7 +1390,7 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ phba->link_flag &= ~LS_EXTERNAL_LOOPBACK;
+
+ /* Check for a deferred FLOGI ACC condition */
+- if (phba->defer_flogi_acc_flag) {
++ if (phba->defer_flogi_acc.flag) {
+ /* lookup ndlp for received FLOGI */
+ ndlp = lpfc_findnode_did(vport, 0);
+ if (!ndlp)
+@@ -1404,34 +1404,38 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ if (phba->sli_rev == LPFC_SLI_REV4) {
+ bf_set(wqe_ctxt_tag,
+ &defer_flogi_acc.wqe.xmit_els_rsp.wqe_com,
+- phba->defer_flogi_acc_rx_id);
++ phba->defer_flogi_acc.rx_id);
+ bf_set(wqe_rcvoxid,
+ &defer_flogi_acc.wqe.xmit_els_rsp.wqe_com,
+- phba->defer_flogi_acc_ox_id);
++ phba->defer_flogi_acc.ox_id);
+ } else {
+ icmd = &defer_flogi_acc.iocb;
+- icmd->ulpContext = phba->defer_flogi_acc_rx_id;
++ icmd->ulpContext = phba->defer_flogi_acc.rx_id;
+ icmd->unsli3.rcvsli3.ox_id =
+- phba->defer_flogi_acc_ox_id;
++ phba->defer_flogi_acc.ox_id;
+ }
+
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "3354 Xmit deferred FLOGI ACC: rx_id: x%x,"
+ " ox_id: x%x, hba_flag x%lx\n",
+- phba->defer_flogi_acc_rx_id,
+- phba->defer_flogi_acc_ox_id, phba->hba_flag);
++ phba->defer_flogi_acc.rx_id,
++ phba->defer_flogi_acc.ox_id, phba->hba_flag);
+
+ /* Send deferred FLOGI ACC */
+ lpfc_els_rsp_acc(vport, ELS_CMD_FLOGI, &defer_flogi_acc,
+ ndlp, NULL);
+
+- phba->defer_flogi_acc_flag = false;
+- vport->fc_myDID = did;
++ phba->defer_flogi_acc.flag = false;
+
+- /* Decrement ndlp reference count to indicate the node can be
+- * released when other references are removed.
++ /* Decrement the held ndlp that was incremented when the
++ * deferred flogi acc flag was set.
+ */
+- lpfc_nlp_put(ndlp);
++ if (phba->defer_flogi_acc.ndlp) {
++ lpfc_nlp_put(phba->defer_flogi_acc.ndlp);
++ phba->defer_flogi_acc.ndlp = NULL;
++ }
++
++ vport->fc_myDID = did;
+ }
+
+ return 0;
+@@ -8454,9 +8458,9 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+
+ /* Defer ACC response until AFTER we issue a FLOGI */
+ if (!test_bit(HBA_FLOGI_ISSUED, &phba->hba_flag)) {
+- phba->defer_flogi_acc_rx_id = bf_get(wqe_ctxt_tag,
++ phba->defer_flogi_acc.rx_id = bf_get(wqe_ctxt_tag,
+ &wqe->xmit_els_rsp.wqe_com);
+- phba->defer_flogi_acc_ox_id = bf_get(wqe_rcvoxid,
++ phba->defer_flogi_acc.ox_id = bf_get(wqe_rcvoxid,
+ &wqe->xmit_els_rsp.wqe_com);
+
+ vport->fc_myDID = did;
+@@ -8464,11 +8468,17 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "3344 Deferring FLOGI ACC: rx_id: x%x,"
+ " ox_id: x%x, hba_flag x%lx\n",
+- phba->defer_flogi_acc_rx_id,
+- phba->defer_flogi_acc_ox_id, phba->hba_flag);
++ phba->defer_flogi_acc.rx_id,
++ phba->defer_flogi_acc.ox_id, phba->hba_flag);
+
+- phba->defer_flogi_acc_flag = true;
++ phba->defer_flogi_acc.flag = true;
+
++ /* This nlp_get is paired with nlp_puts that reset the
++ * defer_flogi_acc.flag back to false. We need to retain
++ * a kref on the ndlp until the deferred FLOGI ACC is
++ * processed or cancelled.
++ */
++ phba->defer_flogi_acc.ndlp = lpfc_nlp_get(ndlp);
+ return 0;
+ }
+
+@@ -10504,7 +10514,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+
+ lpfc_els_rcv_flogi(vport, elsiocb, ndlp);
+ /* retain node if our response is deferred */
+- if (phba->defer_flogi_acc_flag)
++ if (phba->defer_flogi_acc.flag)
+ break;
+ if (newnode)
+ lpfc_disc_state_machine(vport, ndlp, NULL,
+diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
+index e74a676b6e153..e553fab869de9 100644
+--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
++++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
+@@ -1247,7 +1247,14 @@ lpfc_linkdown(struct lpfc_hba *phba)
+ lpfc_scsi_dev_block(phba);
+ offline = pci_channel_offline(phba->pcidev);
+
+- phba->defer_flogi_acc_flag = false;
++ /* Decrement the held ndlp if there is a deferred flogi acc */
++ if (phba->defer_flogi_acc.flag) {
++ if (phba->defer_flogi_acc.ndlp) {
++ lpfc_nlp_put(phba->defer_flogi_acc.ndlp);
++ phba->defer_flogi_acc.ndlp = NULL;
++ }
++ }
++ phba->defer_flogi_acc.flag = false;
+
+ /* Clear external loopback plug detected flag */
+ phba->link_flag &= ~LS_EXTERNAL_LOOPBACK;
+@@ -1369,7 +1376,7 @@ lpfc_linkup_port(struct lpfc_vport *vport)
+ (vport != phba->pport))
+ return;
+
+- if (phba->defer_flogi_acc_flag) {
++ if (phba->defer_flogi_acc.flag) {
+ clear_bit(FC_ABORT_DISCOVERY, &vport->fc_flag);
+ clear_bit(FC_RSCN_MODE, &vport->fc_flag);
+ clear_bit(FC_NLP_MORE, &vport->fc_flag);
+--
+2.43.0
+
--- /dev/null
+From 9701af2014055cc8084b8787a1e083663b554e87 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 26 Jul 2024 16:15:10 -0700
+Subject: scsi: lpfc: Update PRLO handling in direct attached topology
+
+From: Justin Tee <justin.tee@broadcom.com>
+
+[ Upstream commit 1f0f7679ad8942f810b0f19ee9cf098c3502d66a ]
+
+A kref imbalance occurs when handling an unsolicited PRLO in direct
+attached topology.
+
+Rework PRLO rcv handling when in MAPPED state. Save the state that we were
+handling a PRLO by setting nlp_last_elscmd to ELS_CMD_PRLO. Then in the
+lpfc_cmpl_els_logo_acc() completion routine, manually restart discovery.
+By issuing the PLOGI, which nlp_gets, before nlp_put at the end of the
+lpfc_cmpl_els_logo_acc() routine, we are saving us from a final nlp_put.
+And, we are still allowing the unreg_rpi to happen.
+
+Signed-off-by: Justin Tee <justin.tee@broadcom.com>
+Link: https://lore.kernel.org/r/20240726231512.92867-7-justintee8345@gmail.com
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/lpfc/lpfc_els.c | 27 ++++++++++++++++-----------
+ drivers/scsi/lpfc/lpfc_nportdisc.c | 22 ++++++++++++++++++++--
+ 2 files changed, 36 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
+index 9084976aa77e1..9c8a6d2a29049 100644
+--- a/drivers/scsi/lpfc/lpfc_els.c
++++ b/drivers/scsi/lpfc/lpfc_els.c
+@@ -5244,9 +5244,10 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ /* ACC to LOGO completes to NPort <nlp_DID> */
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "0109 ACC to LOGO completes to NPort x%x refcnt %d "
+- "Data: x%x x%x x%x\n",
+- ndlp->nlp_DID, kref_read(&ndlp->kref), ndlp->nlp_flag,
+- ndlp->nlp_state, ndlp->nlp_rpi);
++ "last els x%x Data: x%x x%x x%x\n",
++ ndlp->nlp_DID, kref_read(&ndlp->kref),
++ ndlp->nlp_last_elscmd, ndlp->nlp_flag, ndlp->nlp_state,
++ ndlp->nlp_rpi);
+
+ /* This clause allows the LOGO ACC to complete and free resources
+ * for the Fabric Domain Controller. It does deliberately skip
+@@ -5258,18 +5259,22 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ goto out;
+
+ if (ndlp->nlp_state == NLP_STE_NPR_NODE) {
+- /* If PLOGI is being retried, PLOGI completion will cleanup the
+- * node. The NLP_NPR_2B_DISC flag needs to be retained to make
+- * progress on nodes discovered from last RSCN.
+- */
+- if ((ndlp->nlp_flag & NLP_DELAY_TMO) &&
+- (ndlp->nlp_last_elscmd == ELS_CMD_PLOGI))
+- goto out;
+-
+ if (ndlp->nlp_flag & NLP_RPI_REGISTERED)
+ lpfc_unreg_rpi(vport, ndlp);
+
++ /* If came from PRLO, then PRLO_ACC is done.
++ * Start rediscovery now.
++ */
++ if (ndlp->nlp_last_elscmd == ELS_CMD_PRLO) {
++ spin_lock_irq(&ndlp->lock);
++ ndlp->nlp_flag |= NLP_NPR_2B_DISC;
++ spin_unlock_irq(&ndlp->lock);
++ ndlp->nlp_prev_state = ndlp->nlp_state;
++ lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
++ lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
++ }
+ }
++
+ out:
+ /*
+ * The driver received a LOGO from the rport and has ACK'd it.
+diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
+index f6a53446e57f9..4574716c8764f 100644
+--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
++++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
+@@ -2652,8 +2652,26 @@ lpfc_rcv_prlo_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ /* flush the target */
+ lpfc_sli_abort_iocb(vport, ndlp->nlp_sid, 0, LPFC_CTX_TGT);
+
+- /* Treat like rcv logo */
+- lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_PRLO);
++ /* Send PRLO_ACC */
++ spin_lock_irq(&ndlp->lock);
++ ndlp->nlp_flag |= NLP_LOGO_ACC;
++ spin_unlock_irq(&ndlp->lock);
++ lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL);
++
++ /* Save ELS_CMD_PRLO as the last elscmd and then set to NPR.
++ * lpfc_cmpl_els_logo_acc is expected to restart discovery.
++ */
++ ndlp->nlp_last_elscmd = ELS_CMD_PRLO;
++ ndlp->nlp_prev_state = ndlp->nlp_state;
++
++ lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_ELS | LOG_DISCOVERY,
++ "3422 DID x%06x nflag x%x lastels x%x ref cnt %u\n",
++ ndlp->nlp_DID, ndlp->nlp_flag,
++ ndlp->nlp_last_elscmd,
++ kref_read(&ndlp->kref));
++
++ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
++
+ return ndlp->nlp_state;
+ }
+
+--
+2.43.0
+
--- /dev/null
+From 01812561c7b8585ca74274cf9759fcabcb49351f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 26 Jul 2024 16:15:07 -0700
+Subject: scsi: lpfc: Validate hdwq pointers before dereferencing in
+ reset/errata paths
+
+From: Justin Tee <justin.tee@broadcom.com>
+
+[ Upstream commit 2be1d4f11944cd6283cb97268b3e17c4424945ca ]
+
+When the HBA is undergoing a reset or is handling an errata event, NULL ptr
+dereference crashes may occur in routines such as
+lpfc_sli_flush_io_rings(), lpfc_dev_loss_tmo_callbk(), or
+lpfc_abort_handler().
+
+Add NULL ptr checks before dereferencing hdwq pointers that may have been
+freed due to operations colliding with a reset or errata event handler.
+
+Signed-off-by: Justin Tee <justin.tee@broadcom.com>
+Link: https://lore.kernel.org/r/20240726231512.92867-4-justintee8345@gmail.com
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/lpfc/lpfc_hbadisc.c | 3 ++-
+ drivers/scsi/lpfc/lpfc_scsi.c | 13 +++++++++++--
+ drivers/scsi/lpfc/lpfc_sli.c | 11 +++++++++++
+ 3 files changed, 24 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
+index 13b08c85440fe..e74a676b6e153 100644
+--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
++++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
+@@ -175,7 +175,8 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
+ ndlp->nlp_state, ndlp->fc4_xpt_flags);
+
+ /* Don't schedule a worker thread event if the vport is going down. */
+- if (test_bit(FC_UNLOADING, &vport->load_flag)) {
++ if (test_bit(FC_UNLOADING, &vport->load_flag) ||
++ !test_bit(HBA_SETUP, &phba->hba_flag)) {
+ spin_lock_irqsave(&ndlp->lock, iflags);
+ ndlp->rport = NULL;
+
+diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
+index 9f0b59672e191..0eaede8275dac 100644
+--- a/drivers/scsi/lpfc/lpfc_scsi.c
++++ b/drivers/scsi/lpfc/lpfc_scsi.c
+@@ -5555,11 +5555,20 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
+
+ iocb = &lpfc_cmd->cur_iocbq;
+ if (phba->sli_rev == LPFC_SLI_REV4) {
+- pring_s4 = phba->sli4_hba.hdwq[iocb->hba_wqidx].io_wq->pring;
+- if (!pring_s4) {
++ /* if the io_wq & pring are gone, the port was reset. */
++ if (!phba->sli4_hba.hdwq[iocb->hba_wqidx].io_wq ||
++ !phba->sli4_hba.hdwq[iocb->hba_wqidx].io_wq->pring) {
++ lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
++ "2877 SCSI Layer I/O Abort Request "
++ "IO CMPL Status x%x ID %d LUN %llu "
++ "HBA_SETUP %d\n", FAILED,
++ cmnd->device->id,
++ (u64)cmnd->device->lun,
++ test_bit(HBA_SETUP, &phba->hba_flag));
+ ret = FAILED;
+ goto out_unlock_hba;
+ }
++ pring_s4 = phba->sli4_hba.hdwq[iocb->hba_wqidx].io_wq->pring;
+ spin_lock(&pring_s4->ring_lock);
+ }
+ /* the command is in process of being cancelled */
+diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
+index 3e55d5edd60ab..c6fcaeeb52945 100644
+--- a/drivers/scsi/lpfc/lpfc_sli.c
++++ b/drivers/scsi/lpfc/lpfc_sli.c
+@@ -4687,6 +4687,17 @@ lpfc_sli_flush_io_rings(struct lpfc_hba *phba)
+ /* Look on all the FCP Rings for the iotag */
+ if (phba->sli_rev >= LPFC_SLI_REV4) {
+ for (i = 0; i < phba->cfg_hdw_queue; i++) {
++ if (!phba->sli4_hba.hdwq ||
++ !phba->sli4_hba.hdwq[i].io_wq) {
++ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
++ "7777 hdwq's deleted %lx "
++ "%lx %x %x\n",
++ phba->pport->load_flag,
++ phba->hba_flag,
++ phba->link_state,
++ phba->sli.sli_flag);
++ return;
++ }
+ pring = phba->sli4_hba.hdwq[i].io_wq->pring;
+
+ spin_lock_irq(&pring->ring_lock);
+--
+2.43.0
+
--- /dev/null
+From c961291e892285b949af10d6a243645cc08d45af Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 7 Aug 2024 13:36:28 +1000
+Subject: scsi: NCR5380: Initialize buffer for MSG IN and STATUS transfers
+
+From: Finn Thain <fthain@linux-m68k.org>
+
+[ Upstream commit 1c71065df2df693d208dd32758171c1dece66341 ]
+
+Following an incomplete transfer in MSG IN phase, the driver would not
+notice the problem and would make use of invalid data. Initialize 'tmp'
+appropriately and bail out if no message was received. For STATUS phase,
+preserve the existing status code unless a new value was transferred.
+
+Tested-by: Stan Johnson <userm57@yahoo.com>
+Signed-off-by: Finn Thain <fthain@linux-m68k.org>
+Link: https://lore.kernel.org/r/52e02a8812ae1a2d810d7f9f7fd800c3ccc320c4.1723001788.git.fthain@linux-m68k.org
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/NCR5380.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
+index 00e245173320c..4fcb73b727aa5 100644
+--- a/drivers/scsi/NCR5380.c
++++ b/drivers/scsi/NCR5380.c
+@@ -1807,8 +1807,11 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
+ return;
+ case PHASE_MSGIN:
+ len = 1;
++ tmp = 0xff;
+ data = &tmp;
+ NCR5380_transfer_pio(instance, &phase, &len, &data, 0);
++ if (tmp == 0xff)
++ break;
+ ncmd->message = tmp;
+
+ switch (tmp) {
+@@ -1996,6 +1999,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
+ break;
+ case PHASE_STATIN:
+ len = 1;
++ tmp = ncmd->status;
+ data = &tmp;
+ NCR5380_transfer_pio(instance, &phase, &len, &data, 0);
+ ncmd->status = tmp;
+--
+2.43.0
+
--- /dev/null
+From 587e358a76090f7e303c17db3e661ef9472b7e00 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 11 Jul 2024 14:47:00 -0500
+Subject: scsi: smartpqi: Add new controller PCI IDs
+
+From: David Strahan <David.Strahan@microchip.com>
+
+[ Upstream commit 0e21e73384d324f75ea16f3d622cfc433fa6209b ]
+
+All PCI ID entries in hex.
+
+Add new inagile PCI IDs:
+ VID / DID / SVID / SDID
+ ---- ---- ---- ----
+ SMART-HBA 8242-24i 9005 / 028f / 1ff9 / 0045
+ RAID 8236-16i 9005 / 028f / 1ff9 / 0046
+ RAID 8240-24i 9005 / 028f / 1ff9 / 0047
+ SMART-HBA 8238-16i 9005 / 028f / 1ff9 / 0048
+ PM8222-SHBA 9005 / 028f / 1ff9 / 004a
+ RAID PM8204-2GB 9005 / 028f / 1ff9 / 004b
+ RAID PM8204-4GB 9005 / 028f / 1ff9 / 004c
+ PM8222-HBA 9005 / 028f / 1ff9 / 004f
+ MT0804M6R 9005 / 028f / 1ff9 / 0051
+ MT0801M6E 9005 / 028f / 1ff9 / 0052
+ MT0808M6R 9005 / 028f / 1ff9 / 0053
+ MT0800M6H 9005 / 028f / 1ff9 / 0054
+ RS0800M5H24i 9005 / 028f / 1ff9 / 006b
+ RS0800M5E8i 9005 / 028f / 1ff9 / 006c
+ RS0800M5H8i 9005 / 028f / 1ff9 / 006d
+ RS0804M5R16i 9005 / 028f / 1ff9 / 006f
+ RS0800M5E24i 9005 / 028f / 1ff9 / 0070
+ RS0800M5H16i 9005 / 028f / 1ff9 / 0071
+ RS0800M5E16i 9005 / 028f / 1ff9 / 0072
+ RT0800M7E 9005 / 028f / 1ff9 / 0086
+ RT0800M7H 9005 / 028f / 1ff9 / 0087
+ RT0804M7R 9005 / 028f / 1ff9 / 0088
+ RT0808M7R 9005 / 028f / 1ff9 / 0089
+ RT1608M6R16i 9005 / 028f / 1ff9 / 00a1
+
+Add new h3c pci_id:
+ VID / DID / SVID / SDID
+ ---- ---- ---- ----
+ UN RAID P4408-Mr-2 9005 / 028f / 193d / 1110
+
+Add new powerleader pci ids:
+ VID / DID / SVID / SDID
+ ---- ---- ---- ----
+ PL SmartROC PM8204 9005 / 028f / 1f3a / 0104
+
+Reviewed-by: Scott Benesh <scott.benesh@microchip.com>
+Reviewed-by: Scott Teel <scott.teel@microchip.com>
+Reviewed-by: Mike McGowen <mike.mcgowen@microchip.com>
+Signed-off-by: David Strahan <David.Strahan@microchip.com>
+Signed-off-by: Don Brace <don.brace@microchip.com>
+Link: https://lore.kernel.org/r/20240711194704.982400-2-don.brace@microchip.com
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/smartpqi/smartpqi_init.c | 104 ++++++++++++++++++++++++++
+ 1 file changed, 104 insertions(+)
+
+diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c
+index c1524fb334eb5..02d16fddd3123 100644
+--- a/drivers/scsi/smartpqi/smartpqi_init.c
++++ b/drivers/scsi/smartpqi/smartpqi_init.c
+@@ -9456,6 +9456,10 @@ static const struct pci_device_id pqi_pci_id_table[] = {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ 0x193d, 0x110b)
+ },
++ {
++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++ 0x193d, 0x1110)
++ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ 0x193d, 0x8460)
+@@ -9572,6 +9576,14 @@ static const struct pci_device_id pqi_pci_id_table[] = {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ 0x1bd4, 0x0089)
+ },
++ {
++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++ 0x1ff9, 0x00a1)
++ },
++ {
++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++ 0x1f3a, 0x0104)
++ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ 0x19e5, 0xd227)
+@@ -10164,6 +10176,98 @@ static const struct pci_device_id pqi_pci_id_table[] = {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ 0x1137, 0x02fa)
+ },
++ {
++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++ 0x1ff9, 0x0045)
++ },
++ {
++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++ 0x1ff9, 0x0046)
++ },
++ {
++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++ 0x1ff9, 0x0047)
++ },
++ {
++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++ 0x1ff9, 0x0048)
++ },
++ {
++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++ 0x1ff9, 0x004a)
++ },
++ {
++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++ 0x1ff9, 0x004b)
++ },
++ {
++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++ 0x1ff9, 0x004c)
++ },
++ {
++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++ 0x1ff9, 0x004f)
++ },
++ {
++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++ 0x1ff9, 0x0051)
++ },
++ {
++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++ 0x1ff9, 0x0052)
++ },
++ {
++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++ 0x1ff9, 0x0053)
++ },
++ {
++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++ 0x1ff9, 0x0054)
++ },
++ {
++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++ 0x1ff9, 0x006b)
++ },
++ {
++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++ 0x1ff9, 0x006c)
++ },
++ {
++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++ 0x1ff9, 0x006d)
++ },
++ {
++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++ 0x1ff9, 0x006f)
++ },
++ {
++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++ 0x1ff9, 0x0070)
++ },
++ {
++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++ 0x1ff9, 0x0071)
++ },
++ {
++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++ 0x1ff9, 0x0072)
++ },
++ {
++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++ 0x1ff9, 0x0086)
++ },
++ {
++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++ 0x1ff9, 0x0087)
++ },
++ {
++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++ 0x1ff9, 0x0088)
++ },
++ {
++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++ 0x1ff9, 0x0089)
++ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ 0x1e93, 0x1000)
+--
+2.43.0
+
--- /dev/null
+From b295b8bfb64bd628dd21f6533735cc3a918cc716 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 27 Aug 2024 13:54:58 -0500
+Subject: scsi: smartpqi: add new controller PCI IDs
+
+From: David Strahan <David.Strahan@microchip.com>
+
+[ Upstream commit dbc39b84540f746cc814e69b21e53e6d3e12329a ]
+
+All PCI ID entries in Hex.
+
+Add new cisco pci ids:
+ VID / DID / SVID / SDID
+ ---- ---- ---- ----
+ 9005 028f 1137 02fe
+ 9005 028f 1137 02ff
+ 9005 028f 1137 0300
+
+Add new h3c pci ids:
+ VID / DID / SVID / SDID
+ ---- ---- ---- ----
+ 9005 028f 193d 0462
+ 9005 028f 193d 8462
+
+Add new ieit pci ids:
+ VID / DID / SVID / SDID
+ ---- ---- ---- ----
+ 9005 028f 1ff9 00a3
+
+Reviewed-by: Scott Benesh <scott.benesh@microchip.com>
+Reviewed-by: Mike McGowen <mike.mcgowen@microchip.com>
+Signed-off-by: David Strahan <David.Strahan@microchip.com>
+Signed-off-by: Don Brace <don.brace@microchip.com>
+Link: https://lore.kernel.org/r/20240827185501.692804-5-don.brace@microchip.com
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/smartpqi/smartpqi_init.c | 24 ++++++++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+
+diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c
+index a4719af88718e..4230714e5f3a1 100644
+--- a/drivers/scsi/smartpqi/smartpqi_init.c
++++ b/drivers/scsi/smartpqi/smartpqi_init.c
+@@ -9428,6 +9428,10 @@ static const struct pci_device_id pqi_pci_id_table[] = {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ 0x152d, 0x8a37)
+ },
++ {
++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++ 0x193d, 0x0462)
++ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ 0x193d, 0x1104)
+@@ -9468,6 +9472,10 @@ static const struct pci_device_id pqi_pci_id_table[] = {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ 0x193d, 0x8461)
+ },
++ {
++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++ 0x193d, 0x8462)
++ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ 0x193d, 0xc460)
+@@ -10176,6 +10184,18 @@ static const struct pci_device_id pqi_pci_id_table[] = {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ 0x1137, 0x02fa)
+ },
++ {
++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++ 0x1137, 0x02fe)
++ },
++ {
++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++ 0x1137, 0x02ff)
++ },
++ {
++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++ 0x1137, 0x0300)
++ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ 0x1ff9, 0x0045)
+@@ -10352,6 +10372,10 @@ static const struct pci_device_id pqi_pci_id_table[] = {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ 0x1f51, 0x1045)
+ },
++ {
++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++ 0x1ff9, 0x00a3)
++ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_ANY_ID, PCI_ANY_ID)
+--
+2.43.0
+
--- /dev/null
+From d78a23acacd8b11bfd391e990956a7b2826c9920 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 27 Aug 2024 13:54:56 -0500
+Subject: scsi: smartpqi: correct stream detection
+
+From: Mahesh Rajashekhara <mahesh.rajashekhara@microchip.com>
+
+[ Upstream commit 4c76114932d1d6fad2e72823e7898a3c960cf2a7 ]
+
+Correct stream detection by initializing the structure
+pqi_scsi_dev_raid_map_data to 0s.
+
+When the OS issues SCSI READ commands, the driver erroneously considers
+them as SCSI WRITES. If they are identified as sequential IOs, the driver
+then submits those requests via the RAID path instead of the AIO path.
+
+The 'is_write' flag might be set for SCSI READ commands also. The driver
+may interpret SCSI READ commands as SCSI WRITE commands, resulting in IOs
+being submitted through the RAID path.
+
+Note: This does not cause data corruption.
+
+Reviewed-by: Scott Benesh <scott.benesh@microchip.com>
+Reviewed-by: Scott Teel <scott.teel@microchip.com>
+Reviewed-by: Mike McGowen <mike.mcgowen@microchip.com>
+Signed-off-by: Mahesh Rajashekhara <mahesh.rajashekhara@microchip.com>
+Signed-off-by: Don Brace <don.brace@microchip.com>
+Link: https://lore.kernel.org/r/20240827185501.692804-3-don.brace@microchip.com
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/smartpqi/smartpqi_init.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c
+index 02d16fddd3123..a4719af88718e 100644
+--- a/drivers/scsi/smartpqi/smartpqi_init.c
++++ b/drivers/scsi/smartpqi/smartpqi_init.c
+@@ -5917,7 +5917,7 @@ static bool pqi_is_parity_write_stream(struct pqi_ctrl_info *ctrl_info,
+ int rc;
+ struct pqi_scsi_dev *device;
+ struct pqi_stream_data *pqi_stream_data;
+- struct pqi_scsi_dev_raid_map_data rmd;
++ struct pqi_scsi_dev_raid_map_data rmd = { 0 };
+
+ if (!ctrl_info->enable_stream_detection)
+ return false;
+--
+2.43.0
+
--- /dev/null
+From 9e04b8ef13ebdbc3cfa8f07a6f070c44a7797b08 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 7 Aug 2024 23:51:44 +0200
+Subject: selftests/nolibc: avoid passing NULL to printf("%s")
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Thomas Weißschuh <linux@weissschuh.net>
+
+[ Upstream commit f1a58f61d88642ae1e6e97e9d72d73bc70a93cb8 ]
+
+Clang on higher optimization levels detects that NULL is passed to
+printf("%s") and warns about it.
+While printf() from nolibc gracefully handles that NULL,
+it is undefined behavior as per POSIX, so the warning is reasonable.
+Avoid the warning by transforming NULL into a non-NULL placeholder.
+
+Reviewed-by: Shuah Khan <skhan@linuxfoundation.org>
+Acked-by: Willy Tarreau <w@1wt.eu>
+Link: https://lore.kernel.org/r/20240807-nolibc-llvm-v2-8-c20f2f5fc7c2@weissschuh.net
+Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/testing/selftests/nolibc/nolibc-test.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c
+index 994477ee87bef..4bd8360d54225 100644
+--- a/tools/testing/selftests/nolibc/nolibc-test.c
++++ b/tools/testing/selftests/nolibc/nolibc-test.c
+@@ -534,7 +534,7 @@ int expect_strzr(const char *expr, int llen)
+ {
+ int ret = 0;
+
+- llen += printf(" = <%s> ", expr);
++ llen += printf(" = <%s> ", expr ? expr : "(null)");
+ if (expr) {
+ ret = 1;
+ result(llen, FAIL);
+@@ -553,7 +553,7 @@ int expect_strnz(const char *expr, int llen)
+ {
+ int ret = 0;
+
+- llen += printf(" = <%s> ", expr);
++ llen += printf(" = <%s> ", expr ? expr : "(null)");
+ if (!expr) {
+ ret = 1;
+ result(llen, FAIL);
+--
+2.43.0
+
tools-rtla-fix-installation-from-out-of-tree-build.patch
alsa-gus-fix-some-error-handling-paths-related-to-ge.patch
alsa-hda-conexant-fix-conflicting-quirk-for-system76.patch
+wifi-ath9k-fix-possible-integer-overflow-in-ath9k_ge.patch
+wifi-rtw89-avoid-to-add-interface-to-list-twice-when.patch
+wifi-ath9k_htc-use-__skb_set_length-for-resetting-ur.patch
+crypto-x86-sha256-add-parentheses-around-macros-sing.patch
+crypto-octeontx-fix-authenc-setkey.patch
+crypto-octeontx2-fix-authenc-setkey.patch
+ice-adjust-over-allocation-of-memory-in-ice_sched_ad.patch
+wifi-iwlwifi-mvm-fix-a-race-in-scan-abort-flow.patch
+wifi-iwlwifi-mvm-drop-wrong-sta-selection-in-tx.patch
+wifi-cfg80211-set-correct-chandef-when-starting-cac.patch
+net-xen-netback-prevent-uaf-in-xenvif_flush_hash.patch
+net-hisilicon-hip04-fix-of-node-leak-in-probe.patch
+net-hisilicon-hns_dsaf_mac-fix-of-node-leak-in-hns_m.patch
+net-hisilicon-hns_mdio-fix-of-node-leak-in-probe.patch
+acpi-pad-fix-crash-in-exit_round_robin.patch
+acpica-fix-memory-leak-if-acpi_ps_get_next_namepath-.patch
+acpica-fix-memory-leak-if-acpi_ps_get_next_field-fai.patch
+fs-inode-prevent-dump_mapping-accessing-invalid-dent.patch
+e1000e-avoid-failing-the-system-during-pm_suspend.patch
+acpi-resource-skip-irq-override-on-asus-vivobook-go-.patch
+wifi-mt76-mt7915-disable-tx-worker-during-tx-ba-sess.patch
+net-sched-consistently-use-rcu_replace_pointer-in-ta.patch
+bluetooth-btusb-add-realtek-rtl8852c-support-id-0x04.patch
+bluetooth-btrtl-set-msft-ext-address-filter-quirk-fo.patch
+acpi-video-add-force_vendor-quirk-for-panasonic-toug.patch
+acpi-cppc-add-support-for-setting-epp-register-in-ff.patch
+blk_iocost-fix-more-out-of-bound-shifts.patch
+wifi-ath12k-fix-array-out-of-bound-access-in-soc-sta.patch
+wifi-ath11k-fix-array-out-of-bound-access-in-soc-sta.patch
+wifi-rtw88-select-want_dev_coredump.patch
+acpi-ec-do-not-release-locks-during-operation-region.patch
+acpica-check-null-return-of-acpi_allocate_zeroed-in-.patch
+tipc-guard-against-string-buffer-overrun.patch
+net-mvpp2-increase-size-of-queue_name-buffer.patch
+bnxt_en-extend-maximum-length-of-version-string-by-1.patch
+ipv4-check-in_dev-earlier-for-ioctl-siocsifaddr.patch
+wifi-rtw89-correct-base-ht-rate-mask-for-firmware.patch
+ipv4-mask-upper-dscp-bits-and-ecn-bits-in-netlink_fi.patch
+nvme-keyring-restrict-match-length-for-version-1-ide.patch
+nvme-tcp-sanitize-tls-key-handling.patch
+nvme-tcp-check-for-invalidated-or-revoked-key.patch
+net-atlantic-avoid-warning-about-potential-string-tr.patch
+crypto-simd-do-not-call-crypto_alloc_tfm-during-regi.patch
+netpoll-ensure-clean-state-on-setup-failures.patch
+tcp-avoid-reusing-fin_wait2-when-trying-to-find-port.patch
+wifi-iwlwifi-mvm-use-correct-key-iteration.patch
+wifi-iwlwifi-allow-only-cn-mcc-from-wrdd.patch
+wifi-iwlwifi-mvm-avoid-null-pointer-dereference.patch
+wifi-mac80211-fix-rcu-list-iterations.patch
+acpica-iasl-handle-empty-connection_node.patch
+proc-add-config-param-to-block-forcing-mem-writes.patch
+drivers-perf-arm_spe-use-perf_allow_kernel-for-permi.patch
+can-netlink-avoid-call-to-do_set_data_bittiming-call.patch
+netdev-genl-set-extack-and-fix-error-on-napi-get.patch
+block-fix-integer-overflow-in-blksecdiscard.patch
+arm64-trans_pgd-mark-ptes-entries-as-valid-to-avoid-.patch
+net-phy-check-for-read-errors-in-siocgmiireg.patch
+wifi-rtw89-avoid-reading-out-of-bounds-when-loading-.patch
+x86-bugs-add-missing-no_ssb-flag.patch
+x86-bugs-fix-handling-when-srso-mitigation-is-disabl.patch
+net-napi-prevent-overflow-of-napi_defer_hard_irqs.patch
+crypto-hisilicon-fix-missed-error-branch.patch
+wifi-mt76-mt7915-add-dummy-hw-offload-of-ieee-802.11.patch
+wifi-mt76-mt7915-hold-dev-mt76.mutex-while-disabling.patch
+wifi-mwifiex-fix-memcpy-field-spanning-write-warning.patch
+netfs-cancel-dirty-folios-that-have-no-storage-desti.patch
+nfp-use-irqf_no_autoen-flag-in-request_irq.patch
+alsa-usb-audio-add-input-value-sanity-checks-for-sta.patch
+x86-ioapic-handle-allocation-failures-gracefully.patch
+x86-apic-remove-logical-destination-mode-for-64-bit.patch
+alsa-usb-audio-support-multiple-control-interfaces.patch
+alsa-usb-audio-define-macros-for-quirk-table-entries.patch
+alsa-usb-audio-replace-complex-quirk-lines-with-macr.patch
+alsa-usb-audio-add-quirk-for-rme-digiface-usb.patch
+alsa-usb-audio-add-mixer-quirk-for-rme-digiface-usb.patch
+alsa-usb-audio-add-logitech-audio-profile-quirk.patch
+asoc-codecs-wsa883x-handle-reading-version-failure.patch
+alsa-control-take-power_ref-lock-primarily.patch
+tools-x86-kcpuid-protect-against-faulty-max-subleaf-.patch
+x86-pkeys-add-pkru-as-a-parameter-in-signal-handling.patch
+x86-pkeys-restore-altstack-access-in-sigreturn.patch
+x86-kexec-add-efi-config-table-identity-mapping-for-.patch
+x86-mm-ident_map-use-gbpages-only-where-full-gb-page.patch
+alsa-asihpi-fix-potential-oob-array-access.patch
+alsa-hdsp-break-infinite-midi-input-flush-loop.patch
+tools-nolibc-powerpc-limit-stack-protector-workaroun.patch
+selftests-nolibc-avoid-passing-null-to-printf-s.patch
+x86-syscall-avoid-memcpy-for-ia32-syscall_get_argume.patch
+asoc-intel-boards-always-check-the-result-of-acpi_de.patch
+rcu-tasks-fix-access-non-existent-percpu-rtpcp-varia.patch
+hwmon-nct6775-add-g15cf-to-asus-wmi-monitoring-list.patch
+fbdev-efifb-register-sysfs-groups-through-driver-cor.patch
+fbdev-pxafb-fix-possible-use-after-free-in-pxafb_tas.patch
+pmdomain-core-don-t-hold-the-genpd-lock-when-calling.patch
+coredump-standartize-and-fix-logging.patch
+rcuscale-provide-clear-error-when-async-specified-wi.patch
+power-reset-brcmstb-do-not-go-into-infinite-loop-if-.patch
+iommu-arm-smmu-v3-match-stall-behaviour-for-s2.patch
+iommu-vt-d-always-reserve-a-domain-id-for-identity-s.patch
+iommu-vt-d-fix-potential-lockup-if-qi_submit_sync-ca.patch
+iommu-vt-d-unconditionally-flush-device-tlb-for-pasi.patch
+iommu-arm-smmu-v3-do-not-use-devm-for-the-cd-table-a.patch
+cgroup-disallow-mounting-v1-hierarchies-without-cont.patch
+drm-stm-avoid-use-after-free-issues-with-crtc-and-pl.patch
+drm-amd-display-pass-non-null-to-dcn20_validate_appl.patch
+drm-amd-display-check-null-pointers-before-using-the.patch
+drm-amdgpu-disallow-multiple-bo_handles-chunks-in-on.patch
+drm-amdkfd-amdkfd_free_gtt_mem-clear-the-correct-poi.patch
+drm-amd-display-add-null-check-for-head_pipe-in-dcn2.patch
+drm-amd-display-add-null-check-for-head_pipe-in-dcn3.patch
+drm-amd-display-add-null-check-for-clk_mgr-and-clk_m.patch
+drm-amd-display-add-null-check-for-clk_mgr-in-dcn32_.patch
+drm-xe-hdcp-check-gsc-structure-validity.patch
+drm-amd-display-add-null-check-for-top_pipe_to_progr.patch
+drm-amd-display-use-gpuvm_min_page_size_kbytes-for-d.patch
+ata-pata_serverworks-do-not-use-the-term-blacklist.patch
+ata-sata_sil-rename-sil_blacklist-to-sil_quirks.patch
+scsi-smartpqi-add-new-controller-pci-ids.patch
+hid-ignore-battery-for-all-elan-i2c-hid-devices.patch
+drm-amd-display-handle-null-stream_status-in-planes_.patch
+drm-amd-display-add-null-check-for-function-pointer-.patch
+drm-amd-display-add-null-check-for-function-pointer-.patch-29584
+drm-amd-display-check-null-pointers-before-using-dc-.patch
+drm-amd-display-add-null-check-for-afb-in-amdgpu_dm_.patch
+drm-amd-display-fix-double-free-issue-during-amdgpu-.patch
+drm-amdgpu-add-list-empty-check-to-avoid-null-pointe.patch
+jfs-ubsan-shift-out-of-bounds-in-dbfindbits.patch
+jfs-fix-uaf-in-dbfreebits.patch
+jfs-check-if-leafidx-greater-than-num-leaves-per-dma.patch
+scsi-smartpqi-correct-stream-detection.patch
+scsi-smartpqi-add-new-controller-pci-ids.patch-21617
+drm-msm-adreno-assign-msm_gpu-pdev-earlier-to-avoid-.patch
+jfs-fix-uninit-value-access-of-new_ea-in-ea_buffer.patch
+drm-amdgpu-add-raven1-gfxoff-quirk.patch
+drm-amdgpu-enable-gfxoff-quirk-on-hp-705g4.patch
+drm-amdkfd-fix-resource-leak-in-criu-restore-queue.patch
+hid-multitouch-add-support-for-thinkpad-x12-gen-2-kb.patch
+platform-x86-touchscreen_dmi-add-nanote-next-quirk.patch
+platform-x86-amd-pmf-add-quirk-for-tuf-gaming-a14.patch
+drm-stm-ltdc-reset-plane-transparency-after-plane-di.patch
+drm-amd-display-check-null-initialized-variables.patch
+drm-amd-display-check-phantom_stream-before-it-is-us.patch
+drm-amd-display-check-stream-before-comparing-them.patch
+drm-amd-display-check-link_res-hpo_dp_link_enc-befor.patch
+drm-amd-display-fix-index-out-of-bounds-in-dcn30-deg.patch
+drm-amd-display-fix-index-out-of-bounds-in-degamma-h.patch
+drm-amd-display-fix-index-out-of-bounds-in-dcn30-col.patch
+drm-amdgpu-gfx9-properly-handle-error-ints-on-all-pi.patch
+drm-amd-display-avoid-overflow-assignment-in-link_dp.patch
+drm-amd-display-initialize-get_bytes_per_element-s-d.patch
+drm-printer-allow-null-data-in-devcoredump-printer.patch
+perf-x86-avoid-missing-caller-address-in-stack-trace.patch
+scsi-aacraid-rearrange-order-of-struct-aac_srb_unit.patch
+scsi-lpfc-validate-hdwq-pointers-before-dereferencin.patch
+scsi-lpfc-fix-unsolicited-flogi-kref-imbalance-when-.patch
+scsi-lpfc-update-prlo-handling-in-direct-attached-to.patch
+drm-amdgpu-fix-unchecked-return-value-warning-for-am.patch
+drm-amdgpu-fix-unchecked-return-value-warning-for-am.patch-12177
+perf-fix-event_function_call-locking.patch
+scsi-ncr5380-initialize-buffer-for-msg-in-and-status.patch
+drm-radeon-r100-handle-unknown-family-in-r100_cp_ini.patch
+drm-amdgpu-block-mmr_read-ioctl-in-reset.patch
+drm-amdgpu-gfx9-use-rlc-safe-mode-for-soft-recovery.patch
+drm-amdgpu-gfx11-enter-safe-mode-before-touching-cp_.patch
+drm-xe-use-topology-to-determine-page-fault-queue-si.patch
+drm-amd-pm-ensure-the-fw_info-is-not-null-before-usi.patch
+drm-amdkfd-check-int-source-id-for-utcl2-poison-even.patch
+drm-xe-drop-warn-on-xe_guc_pc_gucrc_disable-in-guc-p.patch
+of-irq-refer-to-actual-buffer-size-in-of_irq_parse_o.patch
+powerpc-pseries-use-correct-data-types-from-pseries_.patch
+ovl-fsync-after-metadata-copy-up.patch
+drm-amdgpu-gfx11-use-rlc-safe-mode-for-soft-recovery.patch
+drm-amdgpu-gfx10-use-rlc-safe-mode-for-soft-recovery.patch
+platform-x86-lenovo-ymc-ignore-the-0x0-state.patch
+tools-hv-add-memory-allocation-check-in-hv_fcopy_sta.patch
+hid-i2c-hid-ensure-various-commands-do-not-interfere.patch
+ksmbd-add-refcnt-to-ksmbd_conn-struct.patch
+platform-mellanox-mlxbf-pmc-fix-lockdep-warning.patch
+platform-x86-x86-android-tablets-adjust-xiaomi-pad-2.patch
+ext4-don-t-set-sb_rdonly-after-filesystem-errors.patch
+bpf-make-the-pointer-returned-by-iter-next-method-va.patch
+ext4-ext4_search_dir-should-return-a-proper-error.patch
+ext4-avoid-use-after-free-in-ext4_ext_show_leaf.patch
+ext4-fix-i_data_sem-unlock-order-in-ext4_ind_migrate.patch
+bpftool-fix-undefined-behavior-caused-by-shifting-in.patch
+iomap-handle-a-post-direct-i-o-invalidate-race-in-io.patch
+bpftool-fix-undefined-behavior-in-qsort-null-0.patch
+bpf-fix-a-sdiv-overflow-issue.patch
--- /dev/null
+From 45ce775ff434bd03718f2f9f38625b2cb0b5c6f2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 23 Aug 2024 08:11:52 +0800
+Subject: tcp: avoid reusing FIN_WAIT2 when trying to find port in connect()
+ process
+
+From: Jason Xing <kernelxing@tencent.com>
+
+[ Upstream commit 0d9e5df4a257afc3a471a82961ace9a22b88295a ]
+
+We found that one close-wait socket was reset by the other side
+due to a new connection reusing the same port which is beyond our
+expectation, so we have to investigate the underlying reason.
+
+The following experiment is conducted in the test environment. We
+limit the port range from 40000 to 40010 and delay the time to close()
+after receiving a fin from the active close side, which can help us
+easily reproduce like what happened in production.
+
+Here are three connections captured by tcpdump:
+127.0.0.1.40002 > 127.0.0.1.9999: Flags [S], seq 2965525191
+127.0.0.1.9999 > 127.0.0.1.40002: Flags [S.], seq 2769915070
+127.0.0.1.40002 > 127.0.0.1.9999: Flags [.], ack 1
+127.0.0.1.40002 > 127.0.0.1.9999: Flags [F.], seq 1, ack 1
+// a few seconds later, within 60 seconds
+127.0.0.1.40002 > 127.0.0.1.9999: Flags [S], seq 2965590730
+127.0.0.1.9999 > 127.0.0.1.40002: Flags [.], ack 2
+127.0.0.1.40002 > 127.0.0.1.9999: Flags [R], seq 2965525193
+// later, very quickly
+127.0.0.1.40002 > 127.0.0.1.9999: Flags [S], seq 2965590730
+127.0.0.1.9999 > 127.0.0.1.40002: Flags [S.], seq 3120990805
+127.0.0.1.40002 > 127.0.0.1.9999: Flags [.], ack 1
+
+As we can see, the first flow is reset because:
+1) client starts a new connection, I mean, the second one
+2) client tries to find a suitable port which is a timewait socket
+ (its state is timewait, substate is fin_wait2)
+3) client occupies that timewait port to send a SYN
+4) server finds a corresponding close-wait socket in ehash table,
+ then replies with a challenge ack
+5) client sends an RST to terminate this old close-wait socket.
+
+I don't think the port selection algo can choose a FIN_WAIT2 socket
+when we turn on tcp_tw_reuse because on the server side there
+remain unread data. In some cases, if one side haven't call close() yet,
+we should not consider it as expendable and treat it at will.
+
+Even though, sometimes, the server isn't able to call close() as soon
+as possible like what we expect, it can not be terminated easily,
+especially due to a second unrelated connection happening.
+
+After this patch, we can see the expected failure if we start a
+connection when all the ports are occupied in fin_wait2 state:
+"Ncat: Cannot assign requested address."
+
+Reported-by: Jade Dong <jadedong@tencent.com>
+Signed-off-by: Jason Xing <kernelxing@tencent.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20240823001152.31004-1-kerneljasonxing@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/tcp_ipv4.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
+index da0f502553991..7874b3718bc3c 100644
+--- a/net/ipv4/tcp_ipv4.c
++++ b/net/ipv4/tcp_ipv4.c
+@@ -118,6 +118,9 @@ int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp)
+ struct tcp_sock *tp = tcp_sk(sk);
+ int ts_recent_stamp;
+
++ if (tw->tw_substate == TCP_FIN_WAIT2)
++ reuse = 0;
++
+ if (reuse == 2) {
+ /* Still does not detect *everything* that goes through
+ * lo, since we require a loopback src or dst address
+--
+2.43.0
+
--- /dev/null
+From 1d04e383af2fa259bc3cfa1ae29b18b9a186144e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 1 Aug 2024 19:35:37 +0100
+Subject: tipc: guard against string buffer overrun
+
+From: Simon Horman <horms@kernel.org>
+
+[ Upstream commit 6555a2a9212be6983d2319d65276484f7c5f431a ]
+
+Smatch reports that copying media_name and if_name to name_parts may
+overwrite the destination.
+
+ .../bearer.c:166 bearer_name_validate() error: strcpy() 'media_name' too large for 'name_parts->media_name' (32 vs 16)
+ .../bearer.c:167 bearer_name_validate() error: strcpy() 'if_name' too large for 'name_parts->if_name' (1010102 vs 16)
+
+This does seem to be the case so guard against this possibility by using
+strscpy() and failing if truncation occurs.
+
+Introduced by commit b97bf3fd8f6a ("[TIPC] Initial merge")
+
+Compile tested only.
+
+Reviewed-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20240801-tipic-overrun-v2-1-c5b869d1f074@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/tipc/bearer.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
+index 5a526ebafeb4b..3c9e25f6a1d22 100644
+--- a/net/tipc/bearer.c
++++ b/net/tipc/bearer.c
+@@ -163,8 +163,12 @@ static int bearer_name_validate(const char *name,
+
+ /* return bearer name components, if necessary */
+ if (name_parts) {
+- strcpy(name_parts->media_name, media_name);
+- strcpy(name_parts->if_name, if_name);
++ if (strscpy(name_parts->media_name, media_name,
++ TIPC_MAX_MEDIA_NAME) < 0)
++ return 0;
++ if (strscpy(name_parts->if_name, if_name,
++ TIPC_MAX_IF_NAME) < 0)
++ return 0;
+ }
+ return 1;
+ }
+--
+2.43.0
+
--- /dev/null
+From 2bcbd25b52f61aaf240438243ca56e7f9fda35a0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 6 Sep 2024 02:13:33 -0700
+Subject: tools/hv: Add memory allocation check in hv_fcopy_start
+
+From: Zhu Jun <zhujun2@cmss.chinamobile.com>
+
+[ Upstream commit 94e86b174d103d941b4afc4f016af8af9e5352fa ]
+
+Added error handling for memory allocation failures
+of file_name and path_name.
+
+Signed-off-by: Zhu Jun <zhujun2@cmss.chinamobile.com>
+Reviewed-by: Dexuan Cui <decui@microsoft.com>
+Tested-by: Saurabh Sengar <ssengar@linux.microsoft.com>
+Link: https://lore.kernel.org/r/20240906091333.11419-1-zhujun2@cmss.chinamobile.com
+Signed-off-by: Wei Liu <wei.liu@kernel.org>
+Message-ID: <20240906091333.11419-1-zhujun2@cmss.chinamobile.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/hv/hv_fcopy_uio_daemon.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/tools/hv/hv_fcopy_uio_daemon.c b/tools/hv/hv_fcopy_uio_daemon.c
+index 3ce316cc9f970..7a00f3066a980 100644
+--- a/tools/hv/hv_fcopy_uio_daemon.c
++++ b/tools/hv/hv_fcopy_uio_daemon.c
+@@ -296,6 +296,13 @@ static int hv_fcopy_start(struct hv_start_fcopy *smsg_in)
+ file_name = (char *)malloc(file_size * sizeof(char));
+ path_name = (char *)malloc(path_size * sizeof(char));
+
++ if (!file_name || !path_name) {
++ free(file_name);
++ free(path_name);
++ syslog(LOG_ERR, "Can't allocate memory for file name and/or path name");
++ return HV_E_FAIL;
++ }
++
+ wcstoutf8(file_name, (__u16 *)in_file_name, file_size);
+ wcstoutf8(path_name, (__u16 *)in_path_name, path_size);
+
+--
+2.43.0
+
--- /dev/null
+From f37f1865e22086d812ac5227efd2ba3a6b28133b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 7 Aug 2024 23:51:39 +0200
+Subject: tools/nolibc: powerpc: limit stack-protector workaround to GCC
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Thomas Weißschuh <linux@weissschuh.net>
+
+[ Upstream commit 1daea158d0aae0770371f3079305a29fdb66829e ]
+
+As mentioned in the comment, the workaround for
+__attribute__((no_stack_protector)) is only necessary on GCC.
+Avoid applying the workaround on clang, as clang does not recognize
+__attribute__((__optimize__)) and would fail.
+
+Acked-by: Willy Tarreau <w@1wt.eu>
+Link: https://lore.kernel.org/r/20240807-nolibc-llvm-v2-3-c20f2f5fc7c2@weissschuh.net
+Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/include/nolibc/arch-powerpc.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/tools/include/nolibc/arch-powerpc.h b/tools/include/nolibc/arch-powerpc.h
+index ac212e6185b26..41ebd394b90c7 100644
+--- a/tools/include/nolibc/arch-powerpc.h
++++ b/tools/include/nolibc/arch-powerpc.h
+@@ -172,7 +172,7 @@
+ _ret; \
+ })
+
+-#ifndef __powerpc64__
++#if !defined(__powerpc64__) && !defined(__clang__)
+ /* FIXME: For 32-bit PowerPC, with newer gcc compilers (e.g. gcc 13.1.0),
+ * "omit-frame-pointer" fails with __attribute__((no_stack_protector)) but
+ * works with __attribute__((__optimize__("-fno-stack-protector")))
+--
+2.43.0
+
--- /dev/null
+From 2ea063330328c53e62f471028a5c2dcf81290ec2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 18 Jul 2024 15:47:44 +0200
+Subject: tools/x86/kcpuid: Protect against faulty "max subleaf" values
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Ahmed S. Darwish <darwi@linutronix.de>
+
+[ Upstream commit cf96ab1a966b87b09fdd9e8cc8357d2d00776a3a ]
+
+Protect against the kcpuid code parsing faulty max subleaf numbers
+through a min() expression. Thus, ensuring that max_subleaf will always
+be ≤ MAX_SUBLEAF_NUM.
+
+Use "u32" for the subleaf numbers since kcpuid is compiled with -Wextra,
+which includes signed/unsigned comparisons warnings.
+
+Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Link: https://lore.kernel.org/all/20240718134755.378115-5-darwi@linutronix.de
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/arch/x86/kcpuid/kcpuid.c | 12 +++++-------
+ 1 file changed, 5 insertions(+), 7 deletions(-)
+
+diff --git a/tools/arch/x86/kcpuid/kcpuid.c b/tools/arch/x86/kcpuid/kcpuid.c
+index 24b7d017ec2c1..b7965dfff33a9 100644
+--- a/tools/arch/x86/kcpuid/kcpuid.c
++++ b/tools/arch/x86/kcpuid/kcpuid.c
+@@ -7,7 +7,8 @@
+ #include <string.h>
+ #include <getopt.h>
+
+-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
++#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
++#define min(a, b) (((a) < (b)) ? (a) : (b))
+
+ typedef unsigned int u32;
+ typedef unsigned long long u64;
+@@ -207,12 +208,9 @@ static void raw_dump_range(struct cpuid_range *range)
+ #define MAX_SUBLEAF_NUM 32
+ struct cpuid_range *setup_cpuid_range(u32 input_eax)
+ {
+- u32 max_func, idx_func;
+- int subleaf;
++ u32 max_func, idx_func, subleaf, max_subleaf;
++ u32 eax, ebx, ecx, edx, f = input_eax;
+ struct cpuid_range *range;
+- u32 eax, ebx, ecx, edx;
+- u32 f = input_eax;
+- int max_subleaf;
+ bool allzero;
+
+ eax = input_eax;
+@@ -258,7 +256,7 @@ struct cpuid_range *setup_cpuid_range(u32 input_eax)
+ * others have to be tried (0xf)
+ */
+ if (f == 0x7 || f == 0x14 || f == 0x17 || f == 0x18)
+- max_subleaf = (eax & 0xff) + 1;
++ max_subleaf = min((eax & 0xff) + 1, max_subleaf);
+
+ if (f == 0xb)
+ max_subleaf = 2;
+--
+2.43.0
+
--- /dev/null
+From 3665bac96756fc8530b8e6e7a1501920a4c8567a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 4 Jul 2024 12:38:11 +0530
+Subject: wifi: ath11k: fix array out-of-bound access in SoC stats
+
+From: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
+
+[ Upstream commit 69f253e46af98af17e3efa3e5dfa72fcb7d1983d ]
+
+Currently, the ath11k_soc_dp_stats::hal_reo_error array is defined with a
+maximum size of DP_REO_DST_RING_MAX. However, the ath11k_dp_process_rx()
+function access ath11k_soc_dp_stats::hal_reo_error using the REO
+destination SRNG ring ID, which is incorrect. SRNG ring ID differ from
+normal ring ID, and this usage leads to out-of-bounds array access. To fix
+this issue, modify ath11k_dp_process_rx() to use the normal ring ID
+directly instead of the SRNG ring ID to avoid out-of-bounds array access.
+
+Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
+
+Signed-off-by: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
+Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
+Link: https://patch.msgid.link/20240704070811.4186543-3-quic_periyasa@quicinc.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ath/ath11k/dp_rx.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c
+index aabde24d87632..88c7a7289d06e 100644
+--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
+@@ -2697,7 +2697,7 @@ int ath11k_dp_process_rx(struct ath11k_base *ab, int ring_id,
+ if (unlikely(push_reason !=
+ HAL_REO_DEST_RING_PUSH_REASON_ROUTING_INSTRUCTION)) {
+ dev_kfree_skb_any(msdu);
+- ab->soc_stats.hal_reo_error[dp->reo_dst_ring[ring_id].ring_id]++;
++ ab->soc_stats.hal_reo_error[ring_id]++;
+ continue;
+ }
+
+--
+2.43.0
+
--- /dev/null
+From 3f3ee8b33967bc78c764a4200e7a903d0f9d02c2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 4 Jul 2024 12:38:10 +0530
+Subject: wifi: ath12k: fix array out-of-bound access in SoC stats
+
+From: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
+
+[ Upstream commit e106b7ad13c1d246adaa57df73edb8f8b8acb240 ]
+
+Currently, the ath12k_soc_dp_stats::hal_reo_error array is defined with a
+maximum size of DP_REO_DST_RING_MAX. However, the ath12k_dp_rx_process()
+function access ath12k_soc_dp_stats::hal_reo_error using the REO
+destination SRNG ring ID, which is incorrect. SRNG ring ID differ from
+normal ring ID, and this usage leads to out-of-bounds array access. To
+fix this issue, modify ath12k_dp_rx_process() to use the normal ring ID
+directly instead of the SRNG ring ID to avoid out-of-bounds array access.
+
+Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
+
+Signed-off-by: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
+Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
+Link: https://patch.msgid.link/20240704070811.4186543-2-quic_periyasa@quicinc.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ath/ath12k/dp_rx.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c
+index 3cdc4c51d6dfe..f8767496fa543 100644
+--- a/drivers/net/wireless/ath/ath12k/dp_rx.c
++++ b/drivers/net/wireless/ath/ath12k/dp_rx.c
+@@ -2702,7 +2702,7 @@ int ath12k_dp_rx_process(struct ath12k_base *ab, int ring_id,
+ if (push_reason !=
+ HAL_REO_DEST_RING_PUSH_REASON_ROUTING_INSTRUCTION) {
+ dev_kfree_skb_any(msdu);
+- ab->soc_stats.hal_reo_error[dp->reo_dst_ring[ring_id].ring_id]++;
++ ab->soc_stats.hal_reo_error[ring_id]++;
+ continue;
+ }
+
+--
+2.43.0
+
--- /dev/null
+From f44fb444ccfb8db1ee0cbed0eac8c37665a16374 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 25 Jul 2024 14:17:43 +0300
+Subject: wifi: ath9k: fix possible integer overflow in ath9k_get_et_stats()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Dmitry Kandybka <d.kandybka@gmail.com>
+
+[ Upstream commit 3f66f26703093886db81f0610b97a6794511917c ]
+
+In 'ath9k_get_et_stats()', promote TX stats counters to 'u64'
+to avoid possible integer overflow. Compile tested only.
+
+Found by Linux Verification Center (linuxtesting.org) with SVACE.
+
+Signed-off-by: Dmitry Kandybka <d.kandybka@gmail.com>
+Acked-by: Toke Høiland-Jørgensen <toke@toke.dk>
+Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
+Link: https://patch.msgid.link/20240725111743.14422-1-d.kandybka@gmail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ath/ath9k/debug.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
+index bf3da631c69fd..51abc470125b3 100644
+--- a/drivers/net/wireless/ath/ath9k/debug.c
++++ b/drivers/net/wireless/ath/ath9k/debug.c
+@@ -1325,11 +1325,11 @@ void ath9k_get_et_stats(struct ieee80211_hw *hw,
+ struct ath_softc *sc = hw->priv;
+ int i = 0;
+
+- data[i++] = (sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].tx_pkts_all +
++ data[i++] = ((u64)sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].tx_pkts_all +
+ sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BK)].tx_pkts_all +
+ sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VI)].tx_pkts_all +
+ sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VO)].tx_pkts_all);
+- data[i++] = (sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].tx_bytes_all +
++ data[i++] = ((u64)sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].tx_bytes_all +
+ sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BK)].tx_bytes_all +
+ sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VI)].tx_bytes_all +
+ sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VO)].tx_bytes_all);
+--
+2.43.0
+
--- /dev/null
+From c63db31fcb616e4286db225e28fd16cef7345c91 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 12 Aug 2024 16:24:46 +0200
+Subject: wifi: ath9k_htc: Use __skb_set_length() for resetting urb before
+ resubmit
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Toke Høiland-Jørgensen <toke@redhat.com>
+
+[ Upstream commit 94745807f3ebd379f23865e6dab196f220664179 ]
+
+Syzbot points out that skb_trim() has a sanity check on the existing length of
+the skb, which can be uninitialised in some error paths. The intent here is
+clearly just to reset the length to zero before resubmitting, so switch to
+calling __skb_set_length(skb, 0) directly. In addition, __skb_set_length()
+already contains a call to skb_reset_tail_pointer(), so remove the redundant
+call.
+
+The syzbot report came from ath9k_hif_usb_reg_in_cb(), but there's a similar
+usage of skb_trim() in ath9k_hif_usb_rx_cb(), change both while we're at it.
+
+Reported-by: syzbot+98afa303be379af6cdb2@syzkaller.appspotmail.com
+Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
+Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
+Link: https://patch.msgid.link/20240812142447.12328-1-toke@toke.dk
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ath/ath9k/hif_usb.c | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
+index 0c7841f952287..a3733c9b484e4 100644
+--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
++++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
+@@ -716,8 +716,7 @@ static void ath9k_hif_usb_rx_cb(struct urb *urb)
+ }
+
+ resubmit:
+- skb_reset_tail_pointer(skb);
+- skb_trim(skb, 0);
++ __skb_set_length(skb, 0);
+
+ usb_anchor_urb(urb, &hif_dev->rx_submitted);
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+@@ -754,8 +753,7 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb)
+ case -ESHUTDOWN:
+ goto free_skb;
+ default:
+- skb_reset_tail_pointer(skb);
+- skb_trim(skb, 0);
++ __skb_set_length(skb, 0);
+
+ goto resubmit;
+ }
+--
+2.43.0
+
--- /dev/null
+From 12b90ae642652779cbfe61cc4b6f69f86f8e300c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 16 Aug 2024 16:24:18 +0200
+Subject: wifi: cfg80211: Set correct chandef when starting CAC
+
+From: Issam Hamdi <ih@simonwunderlich.de>
+
+[ Upstream commit 20361712880396e44ce80aaeec2d93d182035651 ]
+
+When starting CAC in a mode other than AP mode, it return a
+"WARNING: CPU: 0 PID: 63 at cfg80211_chandef_dfs_usable+0x20/0xaf [cfg80211]"
+caused by the chandef.chan being null at the end of CAC.
+
+Solution: Ensure the channel definition is set for the different modes
+when starting CAC to avoid getting a NULL 'chan' at the end of CAC.
+
+ Call Trace:
+ ? show_regs.part.0+0x14/0x16
+ ? __warn+0x67/0xc0
+ ? cfg80211_chandef_dfs_usable+0x20/0xaf [cfg80211]
+ ? report_bug+0xa7/0x130
+ ? exc_overflow+0x30/0x30
+ ? handle_bug+0x27/0x50
+ ? exc_invalid_op+0x18/0x60
+ ? handle_exception+0xf6/0xf6
+ ? exc_overflow+0x30/0x30
+ ? cfg80211_chandef_dfs_usable+0x20/0xaf [cfg80211]
+ ? exc_overflow+0x30/0x30
+ ? cfg80211_chandef_dfs_usable+0x20/0xaf [cfg80211]
+ ? regulatory_propagate_dfs_state.cold+0x1b/0x4c [cfg80211]
+ ? cfg80211_propagate_cac_done_wk+0x1a/0x30 [cfg80211]
+ ? process_one_work+0x165/0x280
+ ? worker_thread+0x120/0x3f0
+ ? kthread+0xc2/0xf0
+ ? process_one_work+0x280/0x280
+ ? kthread_complete_and_exit+0x20/0x20
+ ? ret_from_fork+0x19/0x24
+
+Reported-by: Kretschmer Mathias <mathias.kretschmer@fit.fraunhofer.de>
+Signed-off-by: Issam Hamdi <ih@simonwunderlich.de>
+Link: https://patch.msgid.link/20240816142418.3381951-1-ih@simonwunderlich.de
+[shorten subject, remove OCB, reorder cases to match previous list]
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/wireless/nl80211.c | 15 ++++++++++++++-
+ 1 file changed, 14 insertions(+), 1 deletion(-)
+
+diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
+index e3bf14e489c5d..9675ceaa5bf60 100644
+--- a/net/wireless/nl80211.c
++++ b/net/wireless/nl80211.c
+@@ -10024,7 +10024,20 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
+
+ err = rdev_start_radar_detection(rdev, dev, &chandef, cac_time_ms);
+ if (!err) {
+- wdev->links[0].ap.chandef = chandef;
++ switch (wdev->iftype) {
++ case NL80211_IFTYPE_AP:
++ case NL80211_IFTYPE_P2P_GO:
++ wdev->links[0].ap.chandef = chandef;
++ break;
++ case NL80211_IFTYPE_ADHOC:
++ wdev->u.ibss.chandef = chandef;
++ break;
++ case NL80211_IFTYPE_MESH_POINT:
++ wdev->u.mesh.chandef = chandef;
++ break;
++ default:
++ break;
++ }
+ wdev->cac_started = true;
+ wdev->cac_start_time = jiffies;
+ wdev->cac_time_ms = cac_time_ms;
+--
+2.43.0
+
--- /dev/null
+From acc1127d65e9c0ff1fe4c2e397c7eed9873769b3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 8 Aug 2024 23:22:49 +0300
+Subject: wifi: iwlwifi: allow only CN mcc from WRDD
+
+From: Anjaneyulu <pagadala.yesu.anjaneyulu@intel.com>
+
+[ Upstream commit ff5aabe7c2a4a4b089a9ced0cb3d0e284963a7dd ]
+
+Block other mcc expect CN from WRDD ACPI.
+
+Signed-off-by: Anjaneyulu <pagadala.yesu.anjaneyulu@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20240808232017.fe6ea7aa4b39.I86004687a2963fe26f990770aca103e2f5cb1628@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 5 +++++
+ drivers/net/wireless/intel/iwlwifi/fw/regulatory.h | 2 ++
+ drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 2 +-
+ drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 2 --
+ 4 files changed, 8 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
+index ba9e656037a20..9b3d3405fb83d 100644
+--- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
++++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
+@@ -356,6 +356,11 @@ int iwl_acpi_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc)
+ }
+
+ mcc_val = wifi_pkg->package.elements[1].integer.value;
++ if (mcc_val != BIOS_MCC_CHINA) {
++ ret = -EINVAL;
++ IWL_DEBUG_RADIO(fwrt, "ACPI WRDD is supported only for CN\n");
++ goto out_free;
++ }
+
+ mcc[0] = (mcc_val >> 8) & 0xff;
+ mcc[1] = mcc_val & 0xff;
+diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h
+index 633c9ad9af841..ecf482647617c 100644
+--- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h
++++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h
+@@ -45,6 +45,8 @@
+ #define IWL_WTAS_ENABLE_IEC_MSK 0x4
+ #define IWL_WTAS_USA_UHB_MSK BIT(16)
+
++#define BIOS_MCC_CHINA 0x434e
++
+ /*
+ * The profile for revision 2 is a superset of revision 1, which is in
+ * turn a superset of revision 0. So we can store all revisions
+diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
+index fb982d4fe8510..2cf878f237ac6 100644
+--- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
++++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
+@@ -638,7 +638,7 @@ int iwl_uefi_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc)
+ goto out;
+ }
+
+- if (data->mcc != UEFI_MCC_CHINA) {
++ if (data->mcc != BIOS_MCC_CHINA) {
+ ret = -EINVAL;
+ IWL_DEBUG_RADIO(fwrt, "UEFI WRDD is supported only for CN\n");
+ goto out;
+diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
+index 1f8884ca8997c..e0ef981cd8f28 100644
+--- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
++++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
+@@ -149,8 +149,6 @@ struct uefi_cnv_var_splc {
+ u32 default_pwr_limit;
+ } __packed;
+
+-#define UEFI_MCC_CHINA 0x434e
+-
+ /* struct uefi_cnv_var_wrdd - WRDD table as defined in UEFI
+ * @revision: the revision of the table
+ * @mcc: country identifier as defined in ISO/IEC 3166-1 Alpha 2 code
+--
+2.43.0
+
--- /dev/null
+From a52126c39e9cb42d5da72fad02f626bc0f9f2470 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 25 Aug 2024 19:17:09 +0300
+Subject: wifi: iwlwifi: mvm: avoid NULL pointer dereference
+
+From: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+
+[ Upstream commit 557a6cd847645e667f3b362560bd7e7c09aac284 ]
+
+iwl_mvm_tx_skb_sta() and iwl_mvm_tx_mpdu() verify that the mvmvsta
+pointer is not NULL.
+It retrieves this pointer using iwl_mvm_sta_from_mac80211, which is
+dereferencing the ieee80211_sta pointer.
+If sta is NULL, iwl_mvm_sta_from_mac80211 will dereference a NULL
+pointer.
+Fix this by checking the sta pointer before retrieving the mvmsta
+from it. If sta is not NULL, then mvmsta isn't either.
+
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Reviewed-by: Johannes Berg <johannes.berg@intel.com>
+Link: https://patch.msgid.link/20240825191257.880921ce23b7.I340052d70ab6d3410724ce955eb00da10e08188f@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
+index 1d695ece93e9e..51c12d70e8c23 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
++++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
+@@ -1195,6 +1195,9 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
+ bool is_ampdu = false;
+ int hdrlen;
+
++ if (WARN_ON_ONCE(!sta))
++ return -1;
++
+ mvmsta = iwl_mvm_sta_from_mac80211(sta);
+ fc = hdr->frame_control;
+ hdrlen = ieee80211_hdrlen(fc);
+@@ -1202,9 +1205,6 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
+ if (IWL_MVM_NON_TRANSMITTING_AP && ieee80211_is_probe_resp(fc))
+ return -1;
+
+- if (WARN_ON_ONCE(!mvmsta))
+- return -1;
+-
+ if (WARN_ON_ONCE(mvmsta->deflink.sta_id == IWL_MVM_INVALID_STA))
+ return -1;
+
+@@ -1335,7 +1335,7 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
+ int iwl_mvm_tx_skb_sta(struct iwl_mvm *mvm, struct sk_buff *skb,
+ struct ieee80211_sta *sta)
+ {
+- struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
++ struct iwl_mvm_sta *mvmsta;
+ struct ieee80211_tx_info info;
+ struct sk_buff_head mpdus_skbs;
+ struct ieee80211_vif *vif;
+@@ -1344,9 +1344,11 @@ int iwl_mvm_tx_skb_sta(struct iwl_mvm *mvm, struct sk_buff *skb,
+ struct sk_buff *orig_skb = skb;
+ const u8 *addr3;
+
+- if (WARN_ON_ONCE(!mvmsta))
++ if (WARN_ON_ONCE(!sta))
+ return -1;
+
++ mvmsta = iwl_mvm_sta_from_mac80211(sta);
++
+ if (WARN_ON_ONCE(mvmsta->deflink.sta_id == IWL_MVM_INVALID_STA))
+ return -1;
+
+--
+2.43.0
+
--- /dev/null
+From bde3ed62dce95a8ad41ec0a20088e2569d184351 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 8 Aug 2024 23:22:48 +0300
+Subject: wifi: iwlwifi: mvm: drop wrong STA selection in TX
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+[ Upstream commit 1c7e1068a7c9c39ed27636db93e71911e0045419 ]
+
+This shouldn't happen at all, since in station mode all MMPDUs
+go through the TXQ for the STA, and not this function. There
+may or may not be a race in mac80211 through which this might
+happen for some frames while a station is being added, but in
+that case we can also just drop the frame and pretend the STA
+didn't exist yet.
+
+Also, the code is simply wrong since it uses deflink, and it's
+not easy to fix it since the mvmvif->ap_sta pointer cannot be
+used without the mutex, and perhaps the right link might not
+even be known.
+
+Just drop the frame at that point instead of trying to fix it
+up.
+
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20240808232017.45ad105dc7fe.I6d45c82e5758395d9afb8854057ded03c7dc81d7@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../net/wireless/intel/iwlwifi/mvm/mac80211.c | 16 +++-------------
+ 1 file changed, 3 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+index 83551d962a46c..6673a4e467c0b 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
++++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+@@ -834,20 +834,10 @@ void iwl_mvm_mac_tx(struct ieee80211_hw *hw,
+ if (ieee80211_is_mgmt(hdr->frame_control))
+ sta = NULL;
+
+- /* If there is no sta, and it's not offchannel - send through AP */
++ /* this shouldn't even happen: just drop */
+ if (!sta && info->control.vif->type == NL80211_IFTYPE_STATION &&
+- !offchannel) {
+- struct iwl_mvm_vif *mvmvif =
+- iwl_mvm_vif_from_mac80211(info->control.vif);
+- u8 ap_sta_id = READ_ONCE(mvmvif->deflink.ap_sta_id);
+-
+- if (ap_sta_id < mvm->fw->ucode_capa.num_stations) {
+- /* mac80211 holds rcu read lock */
+- sta = rcu_dereference(mvm->fw_id_to_mac_id[ap_sta_id]);
+- if (IS_ERR_OR_NULL(sta))
+- goto drop;
+- }
+- }
++ !offchannel)
++ goto drop;
+
+ if (tmp_sta && !sta && link_id != IEEE80211_LINK_UNSPECIFIED &&
+ !ieee80211_is_probe_resp(hdr->frame_control)) {
+--
+2.43.0
+
--- /dev/null
+From 63f36f15e9fa2304adc241a76f7b9165db1b83b6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 25 Aug 2024 08:56:37 +0300
+Subject: wifi: iwlwifi: mvm: Fix a race in scan abort flow
+
+From: Ilan Peer <ilan.peer@intel.com>
+
+[ Upstream commit 87c1c28a9aa149489e1667f5754fc24f4973d2d0 ]
+
+When the upper layer requests to cancel an ongoing scan, a race
+is possible in which by the time the driver starts to handle the
+upper layers scan cancel flow, the FW already completed handling
+the scan request and the driver received the scan complete
+notification but still did not handle the notification. In such a
+case the FW will simply ignore the scan abort request coming from
+the driver, no notification would arrive from the FW and the entire
+abort flow would be considered a failure.
+
+To better handle this, check the status code returned by the FW for
+the scan abort command. In case the status indicates that
+no scan was aborted, complete the scan abort flow with success, i.e.,
+the scan was aborted, as the flow is expected to consume the scan
+complete notification.
+
+Signed-off-by: Ilan Peer <ilan.peer@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20240825085558.483989d3baef.I3340556a222388504c6330b333360bf77d10f9e2@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../net/wireless/intel/iwlwifi/fw/api/scan.h | 13 ++++++
+ drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 42 +++++++++++++++----
+ 2 files changed, 47 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h
+index 6684506f4fc48..6cf237850ea0c 100644
+--- a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h
++++ b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h
+@@ -1132,6 +1132,19 @@ struct iwl_umac_scan_abort {
+ __le32 flags;
+ } __packed; /* SCAN_ABORT_CMD_UMAC_API_S_VER_1 */
+
++/**
++ * enum iwl_umac_scan_abort_status
++ *
++ * @IWL_UMAC_SCAN_ABORT_STATUS_SUCCESS: scan was successfully aborted
++ * @IWL_UMAC_SCAN_ABORT_STATUS_IN_PROGRESS: scan abort is in progress
++ * @IWL_UMAC_SCAN_ABORT_STATUS_NOT_FOUND: nothing to abort
++ */
++enum iwl_umac_scan_abort_status {
++ IWL_UMAC_SCAN_ABORT_STATUS_SUCCESS = 0,
++ IWL_UMAC_SCAN_ABORT_STATUS_IN_PROGRESS,
++ IWL_UMAC_SCAN_ABORT_STATUS_NOT_FOUND,
++};
++
+ /**
+ * struct iwl_umac_scan_complete
+ * @uid: scan id, &enum iwl_umac_scan_uid_offsets
+diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
+index d7c276237c74e..d8a3d47f5c072 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
++++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
+@@ -3313,13 +3313,23 @@ void iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm,
+ mvm->scan_start);
+ }
+
+-static int iwl_mvm_umac_scan_abort(struct iwl_mvm *mvm, int type)
++static int iwl_mvm_umac_scan_abort(struct iwl_mvm *mvm, int type, bool *wait)
+ {
+- struct iwl_umac_scan_abort cmd = {};
++ struct iwl_umac_scan_abort abort_cmd = {};
++ struct iwl_host_cmd cmd = {
++ .id = WIDE_ID(IWL_ALWAYS_LONG_GROUP, SCAN_ABORT_UMAC),
++ .len = { sizeof(abort_cmd), },
++ .data = { &abort_cmd, },
++ .flags = CMD_SEND_IN_RFKILL,
++ };
++
+ int uid, ret;
++ u32 status = IWL_UMAC_SCAN_ABORT_STATUS_NOT_FOUND;
+
+ lockdep_assert_held(&mvm->mutex);
+
++ *wait = true;
++
+ /* We should always get a valid index here, because we already
+ * checked that this type of scan was running in the generic
+ * code.
+@@ -3328,17 +3338,28 @@ static int iwl_mvm_umac_scan_abort(struct iwl_mvm *mvm, int type)
+ if (WARN_ON_ONCE(uid < 0))
+ return uid;
+
+- cmd.uid = cpu_to_le32(uid);
++ abort_cmd.uid = cpu_to_le32(uid);
+
+ IWL_DEBUG_SCAN(mvm, "Sending scan abort, uid %u\n", uid);
+
+- ret = iwl_mvm_send_cmd_pdu(mvm,
+- WIDE_ID(IWL_ALWAYS_LONG_GROUP, SCAN_ABORT_UMAC),
+- CMD_SEND_IN_RFKILL, sizeof(cmd), &cmd);
++ ret = iwl_mvm_send_cmd_status(mvm, &cmd, &status);
++
++ IWL_DEBUG_SCAN(mvm, "Scan abort: ret=%d, status=%u\n", ret, status);
+ if (!ret)
+ mvm->scan_uid_status[uid] = type << IWL_MVM_SCAN_STOPPING_SHIFT;
+
+- IWL_DEBUG_SCAN(mvm, "Scan abort: ret=%d\n", ret);
++ /* Handle the case that the FW is no longer familiar with the scan that
++ * is to be stopped. In such a case, it is expected that the scan
++ * complete notification was already received but not yet processed.
++ * In such a case, there is no need to wait for a scan complete
++ * notification and the flow should continue similar to the case that
++ * the scan was really aborted.
++ */
++ if (status == IWL_UMAC_SCAN_ABORT_STATUS_NOT_FOUND) {
++ mvm->scan_uid_status[uid] = type << IWL_MVM_SCAN_STOPPING_SHIFT;
++ *wait = false;
++ }
++
+ return ret;
+ }
+
+@@ -3348,6 +3369,7 @@ static int iwl_mvm_scan_stop_wait(struct iwl_mvm *mvm, int type)
+ static const u16 scan_done_notif[] = { SCAN_COMPLETE_UMAC,
+ SCAN_OFFLOAD_COMPLETE, };
+ int ret;
++ bool wait = true;
+
+ lockdep_assert_held(&mvm->mutex);
+
+@@ -3359,7 +3381,7 @@ static int iwl_mvm_scan_stop_wait(struct iwl_mvm *mvm, int type)
+ IWL_DEBUG_SCAN(mvm, "Preparing to stop scan, type %x\n", type);
+
+ if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN))
+- ret = iwl_mvm_umac_scan_abort(mvm, type);
++ ret = iwl_mvm_umac_scan_abort(mvm, type, &wait);
+ else
+ ret = iwl_mvm_lmac_scan_abort(mvm);
+
+@@ -3367,6 +3389,10 @@ static int iwl_mvm_scan_stop_wait(struct iwl_mvm *mvm, int type)
+ IWL_DEBUG_SCAN(mvm, "couldn't stop scan type %d\n", type);
+ iwl_remove_notification(&mvm->notif_wait, &wait_scan_done);
+ return ret;
++ } else if (!wait) {
++ IWL_DEBUG_SCAN(mvm, "no need to wait for scan type %d\n", type);
++ iwl_remove_notification(&mvm->notif_wait, &wait_scan_done);
++ return 0;
+ }
+
+ return iwl_wait_notification(&mvm->notif_wait, &wait_scan_done,
+--
+2.43.0
+
--- /dev/null
+From 00dde574a872171c2b39aec712379fbb9573f54f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 29 Jul 2024 20:20:05 +0300
+Subject: wifi: iwlwifi: mvm: use correct key iteration
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+[ Upstream commit 4f1591d292277eec51d027405a92f0d4ef5e299e ]
+
+In the cases changed here, key iteration isn't done from
+an RCU critical section, but rather using the wiphy lock
+as protection. Therefore, just use ieee80211_iter_keys().
+The link switch case can therefore also use sync commands.
+
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20240729201718.69a2d18580c1.I2148e04d4b467d0b100beac8f7e449bfaaf775a5@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c
+index 8a38fc4b0b0f9..455f5f4175064 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c
++++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c
+@@ -144,7 +144,7 @@ static void iwl_mvm_mld_update_sta_key(struct ieee80211_hw *hw,
+ if (sta != data->sta || key->link_id >= 0)
+ return;
+
+- err = iwl_mvm_send_cmd_pdu(mvm, cmd_id, CMD_ASYNC, sizeof(cmd), &cmd);
++ err = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cmd), &cmd);
+
+ if (err)
+ data->err = err;
+@@ -162,8 +162,8 @@ int iwl_mvm_mld_update_sta_keys(struct iwl_mvm *mvm,
+ .new_sta_mask = new_sta_mask,
+ };
+
+- ieee80211_iter_keys_rcu(mvm->hw, vif, iwl_mvm_mld_update_sta_key,
+- &data);
++ ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_mld_update_sta_key,
++ &data);
+ return data.err;
+ }
+
+@@ -402,7 +402,7 @@ void iwl_mvm_sec_key_remove_ap(struct iwl_mvm *mvm,
+ if (!sec_key_ver)
+ return;
+
+- ieee80211_iter_keys_rcu(mvm->hw, vif,
+- iwl_mvm_sec_key_remove_ap_iter,
+- (void *)(uintptr_t)link_id);
++ ieee80211_iter_keys(mvm->hw, vif,
++ iwl_mvm_sec_key_remove_ap_iter,
++ (void *)(uintptr_t)link_id);
+ }
+--
+2.43.0
+
--- /dev/null
+From f55b2fdf66edf1fd4b128db20b01511e66e84562 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 27 Aug 2024 09:49:40 +0200
+Subject: wifi: mac80211: fix RCU list iterations
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+[ Upstream commit ac35180032fbc5d80b29af00ba4881815ceefcb6 ]
+
+There are a number of places where RCU list iteration is
+used, but that aren't (always) called with RCU held. Use
+just list_for_each_entry() in most, and annotate iface
+iteration with the required locks.
+
+Reviewed-by: Miriam Rachel Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20240827094939.ed8ac0b2f897.I8443c9c3c0f8051841353491dae758021b53115e@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/mac80211/chan.c | 4 +++-
+ net/mac80211/mlme.c | 2 +-
+ net/mac80211/scan.c | 2 +-
+ net/mac80211/util.c | 4 +++-
+ 4 files changed, 8 insertions(+), 4 deletions(-)
+
+diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
+index e6a7ff6ca6797..db5675d24e488 100644
+--- a/net/mac80211/chan.c
++++ b/net/mac80211/chan.c
+@@ -281,7 +281,9 @@ ieee80211_get_max_required_bw(struct ieee80211_link_data *link)
+ enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT;
+ struct sta_info *sta;
+
+- list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) {
++ lockdep_assert_wiphy(sdata->local->hw.wiphy);
++
++ list_for_each_entry(sta, &sdata->local->sta_list, list) {
+ if (sdata != sta->sdata &&
+ !(sta->sdata->bss && sta->sdata->bss == sdata->bss))
+ continue;
+diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
+index 1faf4d7c115f0..71cc5eb35bfcb 100644
+--- a/net/mac80211/mlme.c
++++ b/net/mac80211/mlme.c
+@@ -1020,7 +1020,7 @@ static bool ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
+ bool disable_mu_mimo = false;
+ struct ieee80211_sub_if_data *other;
+
+- list_for_each_entry_rcu(other, &local->interfaces, list) {
++ list_for_each_entry(other, &local->interfaces, list) {
+ if (other->vif.bss_conf.mu_mimo_owner) {
+ disable_mu_mimo = true;
+ break;
+diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
+index 1c5d99975ad04..3b2bde6360bcb 100644
+--- a/net/mac80211/scan.c
++++ b/net/mac80211/scan.c
+@@ -504,7 +504,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
+ * the scan was in progress; if there was none this will
+ * just be a no-op for the particular interface.
+ */
+- list_for_each_entry_rcu(sdata, &local->interfaces, list) {
++ list_for_each_entry(sdata, &local->interfaces, list) {
+ if (ieee80211_sdata_running(sdata))
+ wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work);
+ }
+diff --git a/net/mac80211/util.c b/net/mac80211/util.c
+index c11dbe82ae1b3..d10e0c528c1bf 100644
+--- a/net/mac80211/util.c
++++ b/net/mac80211/util.c
+@@ -751,7 +751,9 @@ static void __iterate_interfaces(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata;
+ bool active_only = iter_flags & IEEE80211_IFACE_ITER_ACTIVE;
+
+- list_for_each_entry_rcu(sdata, &local->interfaces, list) {
++ list_for_each_entry_rcu(sdata, &local->interfaces, list,
++ lockdep_is_held(&local->iflist_mtx) ||
++ lockdep_is_held(&local->hw.wiphy->mtx)) {
+ switch (sdata->vif.type) {
+ case NL80211_IFTYPE_MONITOR:
+ if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE))
+--
+2.43.0
+
--- /dev/null
+From 0e08acaf63290196183136ca301a62d8f383794e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 27 Aug 2024 11:30:03 +0200
+Subject: wifi: mt76: mt7915: add dummy HW offload of IEEE 802.11 fragmentation
+
+From: Benjamin Lin <benjamin-jw.lin@mediatek.com>
+
+[ Upstream commit f2cc859149240d910fdc6405717673e0b84bfda8 ]
+
+Currently, CONNAC2 series do not support encryption for fragmented Tx frames.
+Therefore, add dummy function mt7915_set_frag_threshold() to prevent SW
+IEEE 802.11 fragmentation.
+
+Signed-off-by: Benjamin Lin <benjamin-jw.lin@mediatek.com>
+Link: https://patch.msgid.link/20240827093011.18621-16-nbd@nbd.name
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/mediatek/mt76/mt7915/init.c | 1 +
+ drivers/net/wireless/mediatek/mt76/mt7915/main.c | 7 +++++++
+ 2 files changed, 8 insertions(+)
+
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
+index 7bc3b4cd35925..6bef96e3d2a3d 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
+@@ -400,6 +400,7 @@ mt7915_init_wiphy(struct mt7915_phy *phy)
+ ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD);
+ ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID);
+ ieee80211_hw_set(hw, WANT_MONITOR_VIF);
++ ieee80211_hw_set(hw, SUPPORTS_TX_FRAG);
+
+ hw->max_tx_fragments = 4;
+
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
+index eea41b29f0967..3b2dcb410e0f0 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
+@@ -1577,6 +1577,12 @@ mt7915_twt_teardown_request(struct ieee80211_hw *hw,
+ mutex_unlock(&dev->mt76.mutex);
+ }
+
++static int
++mt7915_set_frag_threshold(struct ieee80211_hw *hw, u32 val)
++{
++ return 0;
++}
++
+ static int
+ mt7915_set_radar_background(struct ieee80211_hw *hw,
+ struct cfg80211_chan_def *chandef)
+@@ -1707,6 +1713,7 @@ const struct ieee80211_ops mt7915_ops = {
+ .sta_set_decap_offload = mt7915_sta_set_decap_offload,
+ .add_twt_setup = mt7915_mac_add_twt_setup,
+ .twt_teardown_request = mt7915_twt_teardown_request,
++ .set_frag_threshold = mt7915_set_frag_threshold,
+ CFG80211_TESTMODE_CMD(mt76_testmode_cmd)
+ CFG80211_TESTMODE_DUMP(mt76_testmode_dump)
+ #ifdef CONFIG_MAC80211_DEBUGFS
+--
+2.43.0
+
--- /dev/null
+From 14d88646cadae3d8d26340cd2e063dd088c15da5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 27 Aug 2024 11:29:54 +0200
+Subject: wifi: mt76: mt7915: disable tx worker during tx BA session
+ enable/disable
+
+From: Felix Fietkau <nbd@nbd.name>
+
+[ Upstream commit 256cbd26fbafb30ba3314339106e5c594e9bd5f9 ]
+
+Avoids firmware race condition.
+
+Link: https://patch.msgid.link/20240827093011.18621-7-nbd@nbd.name
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
+index 9599adf104b16..758249b20c222 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
+@@ -690,13 +690,17 @@ int mt7915_mcu_add_tx_ba(struct mt7915_dev *dev,
+ {
+ struct mt7915_sta *msta = (struct mt7915_sta *)params->sta->drv_priv;
+ struct mt7915_vif *mvif = msta->vif;
++ int ret;
+
++ mt76_worker_disable(&dev->mt76.tx_worker);
+ if (enable && !params->amsdu)
+ msta->wcid.amsdu = false;
++ ret = mt76_connac_mcu_sta_ba(&dev->mt76, &mvif->mt76, params,
++ MCU_EXT_CMD(STA_REC_UPDATE),
++ enable, true);
++ mt76_worker_enable(&dev->mt76.tx_worker);
+
+- return mt76_connac_mcu_sta_ba(&dev->mt76, &mvif->mt76, params,
+- MCU_EXT_CMD(STA_REC_UPDATE),
+- enable, true);
++ return ret;
+ }
+
+ int mt7915_mcu_add_rx_ba(struct mt7915_dev *dev,
+--
+2.43.0
+
--- /dev/null
+From d9e99ceffe723df4602667857ab801d64e258eb8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 27 Aug 2024 11:30:04 +0200
+Subject: wifi: mt76: mt7915: hold dev->mt76.mutex while disabling tx worker
+
+From: Felix Fietkau <nbd@nbd.name>
+
+[ Upstream commit 8f7152f10cb434f954aeff85ca1be9cd4d01912b ]
+
+Prevent racing against other functions disabling the same worker
+
+Link: https://patch.msgid.link/20240827093011.18621-17-nbd@nbd.name
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
+index 8008ce3fa6c7e..387d47e9fcd38 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
+@@ -1537,12 +1537,14 @@ void mt7915_mac_reset_work(struct work_struct *work)
+ set_bit(MT76_RESET, &phy2->mt76->state);
+ cancel_delayed_work_sync(&phy2->mt76->mac_work);
+ }
++
++ mutex_lock(&dev->mt76.mutex);
++
+ mt76_worker_disable(&dev->mt76.tx_worker);
+ mt76_for_each_q_rx(&dev->mt76, i)
+ napi_disable(&dev->mt76.napi[i]);
+ napi_disable(&dev->mt76.tx_napi);
+
+- mutex_lock(&dev->mt76.mutex);
+
+ if (mtk_wed_device_active(&dev->mt76.mmio.wed))
+ mtk_wed_device_stop(&dev->mt76.mmio.wed);
+--
+2.43.0
+
--- /dev/null
+From 6c70350cbdd8f21a143cf0f0cf7910f3711e1329 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 21 Aug 2024 15:23:51 -0600
+Subject: wifi: mwifiex: Fix memcpy() field-spanning write warning in
+ mwifiex_cmd_802_11_scan_ext()
+
+From: Gustavo A. R. Silva <gustavoars@kernel.org>
+
+[ Upstream commit 498365e52bebcbc36a93279fe7e9d6aec8479cee ]
+
+Replace one-element array with a flexible-array member in
+`struct host_cmd_ds_802_11_scan_ext`.
+
+With this, fix the following warning:
+
+elo 16 17:51:58 surfacebook kernel: ------------[ cut here ]------------
+elo 16 17:51:58 surfacebook kernel: memcpy: detected field-spanning write (size 243) of single field "ext_scan->tlv_buffer" at drivers/net/wireless/marvell/mwifiex/scan.c:2239 (size 1)
+elo 16 17:51:58 surfacebook kernel: WARNING: CPU: 0 PID: 498 at drivers/net/wireless/marvell/mwifiex/scan.c:2239 mwifiex_cmd_802_11_scan_ext+0x83/0x90 [mwifiex]
+
+Reported-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Closes: https://lore.kernel.org/linux-hardening/ZsZNgfnEwOcPdCly@black.fi.intel.com/
+Signed-off-by: Gustavo A. R. Silva <gustavoars@kernel.org>
+Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Acked-by: Brian Norris <briannorris@chromium.org>
+Signed-off-by: Kalle Valo <kvalo@kernel.org>
+Link: https://patch.msgid.link/ZsZa5xRcsLq9D+RX@elsanto
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/marvell/mwifiex/fw.h | 2 +-
+ drivers/net/wireless/marvell/mwifiex/scan.c | 3 +--
+ 2 files changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h
+index 3adc447b715f6..5b072120e3f21 100644
+--- a/drivers/net/wireless/marvell/mwifiex/fw.h
++++ b/drivers/net/wireless/marvell/mwifiex/fw.h
+@@ -1587,7 +1587,7 @@ struct host_cmd_ds_802_11_scan_rsp {
+
+ struct host_cmd_ds_802_11_scan_ext {
+ u32 reserved;
+- u8 tlv_buffer[1];
++ u8 tlv_buffer[];
+ } __packed;
+
+ struct mwifiex_ie_types_bss_mode {
+diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c
+index 0326b121747cb..17ce84f5207e3 100644
+--- a/drivers/net/wireless/marvell/mwifiex/scan.c
++++ b/drivers/net/wireless/marvell/mwifiex/scan.c
+@@ -2530,8 +2530,7 @@ int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv,
+ ext_scan_resp = &resp->params.ext_scan;
+
+ tlv = (void *)ext_scan_resp->tlv_buffer;
+- buf_left = le16_to_cpu(resp->size) - (sizeof(*ext_scan_resp) + S_DS_GEN
+- - 1);
++ buf_left = le16_to_cpu(resp->size) - (sizeof(*ext_scan_resp) + S_DS_GEN);
+
+ while (buf_left >= sizeof(struct mwifiex_ie_types_header)) {
+ type = le16_to_cpu(tlv->type);
+--
+2.43.0
+
--- /dev/null
+From 37fb0453726edd6f10f31d80cacd649c66d7fe6f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 18 Jul 2024 15:06:15 +0800
+Subject: wifi: rtw88: select WANT_DEV_COREDUMP
+
+From: Zong-Zhe Yang <kevin_yang@realtek.com>
+
+[ Upstream commit 7e989b0c1e33210c07340bf5228aa83ea52515b5 ]
+
+We have invoked device coredump when fw crash.
+Should select WANT_DEV_COREDUMP by ourselves.
+
+Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com>
+Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
+Link: https://patch.msgid.link/20240718070616.42217-1-pkshih@realtek.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/realtek/rtw88/Kconfig | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/net/wireless/realtek/rtw88/Kconfig b/drivers/net/wireless/realtek/rtw88/Kconfig
+index 22838ede03cd8..02b0d698413be 100644
+--- a/drivers/net/wireless/realtek/rtw88/Kconfig
++++ b/drivers/net/wireless/realtek/rtw88/Kconfig
+@@ -12,6 +12,7 @@ if RTW88
+
+ config RTW88_CORE
+ tristate
++ select WANT_DEV_COREDUMP
+
+ config RTW88_PCI
+ tristate
+--
+2.43.0
+
--- /dev/null
+From 2208d13d0fb0ebbb11858943afceada65d4a03c7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 2 Sep 2024 09:58:03 +0800
+Subject: wifi: rtw89: avoid reading out of bounds when loading TX power FW
+ elements
+
+From: Zong-Zhe Yang <kevin_yang@realtek.com>
+
+[ Upstream commit ed2e4bb17a4884cf29c3347353d8aabb7265b46c ]
+
+Because the loop-expression will do one more time before getting false from
+cond-expression, the original code copied one more entry size beyond valid
+region.
+
+Fix it by moving the entry copy to loop-body.
+
+Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com>
+Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
+Link: https://patch.msgid.link/20240902015803.20420-1-pkshih@realtek.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/realtek/rtw89/core.h | 18 ++++++++++++------
+ 1 file changed, 12 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
+index 112bdd95fc6ea..504660ee3cba3 100644
+--- a/drivers/net/wireless/realtek/rtw89/core.h
++++ b/drivers/net/wireless/realtek/rtw89/core.h
+@@ -3888,16 +3888,22 @@ struct rtw89_txpwr_conf {
+ const void *data;
+ };
+
++static inline bool rtw89_txpwr_entcpy(void *entry, const void *cursor, u8 size,
++ const struct rtw89_txpwr_conf *conf)
++{
++ u8 valid_size = min(size, conf->ent_sz);
++
++ memcpy(entry, cursor, valid_size);
++ return true;
++}
++
+ #define rtw89_txpwr_conf_valid(conf) (!!(conf)->data)
+
+ #define rtw89_for_each_in_txpwr_conf(entry, cursor, conf) \
+- for (typecheck(const void *, cursor), (cursor) = (conf)->data, \
+- memcpy(&(entry), cursor, \
+- min_t(u8, sizeof(entry), (conf)->ent_sz)); \
++ for (typecheck(const void *, cursor), (cursor) = (conf)->data; \
+ (cursor) < (conf)->data + (conf)->num_ents * (conf)->ent_sz; \
+- (cursor) += (conf)->ent_sz, \
+- memcpy(&(entry), cursor, \
+- min_t(u8, sizeof(entry), (conf)->ent_sz)))
++ (cursor) += (conf)->ent_sz) \
++ if (rtw89_txpwr_entcpy(&(entry), cursor, sizeof(entry), conf))
+
+ struct rtw89_txpwr_byrate_data {
+ struct rtw89_txpwr_conf conf;
+--
+2.43.0
+
--- /dev/null
+From eed3c62494f930d48250a891c000992fe9e72b95 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 31 Jul 2024 15:05:04 +0800
+Subject: wifi: rtw89: avoid to add interface to list twice when SER
+
+From: Chih-Kang Chang <gary.chang@realtek.com>
+
+[ Upstream commit 7dd5d2514a8ea58f12096e888b0bd050d7eae20a ]
+
+If SER L2 occurs during the WoWLAN resume flow, the add interface flow
+is triggered by ieee80211_reconfig(). However, due to
+rtw89_wow_resume() return failure, it will cause the add interface flow
+to be executed again, resulting in a double add list and causing a kernel
+panic. Therefore, we have added a check to prevent double adding of the
+list.
+
+list_add double add: new=ffff99d6992e2010, prev=ffff99d6992e2010, next=ffff99d695302628.
+------------[ cut here ]------------
+kernel BUG at lib/list_debug.c:37!
+invalid opcode: 0000 [#1] PREEMPT SMP NOPTI
+CPU: 0 PID: 9 Comm: kworker/0:1 Tainted: G W O 6.6.30-02659-gc18865c4dfbd #1 770df2933251a0e3c888ba69d1053a817a6376a7
+Hardware name: HP Grunt/Grunt, BIOS Google_Grunt.11031.169.0 06/24/2021
+Workqueue: events_freezable ieee80211_restart_work [mac80211]
+RIP: 0010:__list_add_valid_or_report+0x5e/0xb0
+Code: c7 74 18 48 39 ce 74 13 b0 01 59 5a 5e 5f 41 58 41 59 41 5a 5d e9 e2 d6 03 00 cc 48 c7 c7 8d 4f 17 83 48 89 c2 e8 02 c0 00 00 <0f> 0b 48 c7 c7 aa 8c 1c 83 e8 f4 bf 00 00 0f 0b 48 c7 c7 c8 bc 12
+RSP: 0018:ffffa91b8007bc50 EFLAGS: 00010246
+RAX: 0000000000000058 RBX: ffff99d6992e0900 RCX: a014d76c70ef3900
+RDX: ffffa91b8007bae8 RSI: 00000000ffffdfff RDI: 0000000000000001
+RBP: ffffa91b8007bc88 R08: 0000000000000000 R09: ffffa91b8007bae0
+R10: 00000000ffffdfff R11: ffffffff83a79800 R12: ffff99d695302060
+R13: ffff99d695300900 R14: ffff99d6992e1be0 R15: ffff99d6992e2010
+FS: 0000000000000000(0000) GS:ffff99d6aac00000(0000) knlGS:0000000000000000
+CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+CR2: 000078fbdba43480 CR3: 000000010e464000 CR4: 00000000001506f0
+Call Trace:
+ <TASK>
+ ? __die_body+0x1f/0x70
+ ? die+0x3d/0x60
+ ? do_trap+0xa4/0x110
+ ? __list_add_valid_or_report+0x5e/0xb0
+ ? do_error_trap+0x6d/0x90
+ ? __list_add_valid_or_report+0x5e/0xb0
+ ? handle_invalid_op+0x30/0x40
+ ? __list_add_valid_or_report+0x5e/0xb0
+ ? exc_invalid_op+0x3c/0x50
+ ? asm_exc_invalid_op+0x16/0x20
+ ? __list_add_valid_or_report+0x5e/0xb0
+ rtw89_ops_add_interface+0x309/0x310 [rtw89_core 7c32b1ee6854761c0321027c8a58c5160e41f48f]
+ drv_add_interface+0x5c/0x130 [mac80211 83e989e6e616bd5b4b8a2b0a9f9352a2c385a3bc]
+ ieee80211_reconfig+0x241/0x13d0 [mac80211 83e989e6e616bd5b4b8a2b0a9f9352a2c385a3bc]
+ ? finish_wait+0x3e/0x90
+ ? synchronize_rcu_expedited+0x174/0x260
+ ? sync_rcu_exp_done_unlocked+0x50/0x50
+ ? wake_bit_function+0x40/0x40
+ ieee80211_restart_work+0xf0/0x140 [mac80211 83e989e6e616bd5b4b8a2b0a9f9352a2c385a3bc]
+ process_scheduled_works+0x1e5/0x480
+ worker_thread+0xea/0x1e0
+ kthread+0xdb/0x110
+ ? move_linked_works+0x90/0x90
+ ? kthread_associate_blkcg+0xa0/0xa0
+ ret_from_fork+0x3b/0x50
+ ? kthread_associate_blkcg+0xa0/0xa0
+ ret_from_fork_asm+0x11/0x20
+ </TASK>
+Modules linked in: dm_integrity async_xor xor async_tx lz4 lz4_compress zstd zstd_compress zram zsmalloc rfcomm cmac uinput algif_hash algif_skcipher af_alg btusb btrtl iio_trig_hrtimer industrialio_sw_trigger btmtk industrialio_configfs btbcm btintel uvcvideo videobuf2_vmalloc iio_trig_sysfs videobuf2_memops videobuf2_v4l2 videobuf2_common uvc snd_hda_codec_hdmi veth snd_hda_intel snd_intel_dspcfg acpi_als snd_hda_codec industrialio_triggered_buffer kfifo_buf snd_hwdep industrialio i2c_piix4 snd_hda_core designware_i2s ip6table_nat snd_soc_max98357a xt_MASQUERADE xt_cgroup snd_soc_acp_rt5682_mach fuse rtw89_8922ae(O) rtw89_8922a(O) rtw89_pci(O) rtw89_core(O) 8021q mac80211(O) bluetooth ecdh_generic ecc cfg80211 r8152 mii joydev
+gsmi: Log Shutdown Reason 0x03
+---[ end trace 0000000000000000 ]---
+
+Signed-off-by: Chih-Kang Chang <gary.chang@realtek.com>
+Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
+Link: https://patch.msgid.link/20240731070506.46100-4-pkshih@realtek.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/realtek/rtw89/mac80211.c | 4 +++-
+ drivers/net/wireless/realtek/rtw89/util.h | 18 ++++++++++++++++++
+ 2 files changed, 21 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c
+index 1ec97250e88e5..4fae0bd566f6a 100644
+--- a/drivers/net/wireless/realtek/rtw89/mac80211.c
++++ b/drivers/net/wireless/realtek/rtw89/mac80211.c
+@@ -126,7 +126,9 @@ static int rtw89_ops_add_interface(struct ieee80211_hw *hw,
+ rtwvif->rtwdev = rtwdev;
+ rtwvif->roc.state = RTW89_ROC_IDLE;
+ rtwvif->offchan = false;
+- list_add_tail(&rtwvif->list, &rtwdev->rtwvifs_list);
++ if (!rtw89_rtwvif_in_list(rtwdev, rtwvif))
++ list_add_tail(&rtwvif->list, &rtwdev->rtwvifs_list);
++
+ INIT_WORK(&rtwvif->update_beacon_work, rtw89_core_update_beacon_work);
+ INIT_DELAYED_WORK(&rtwvif->roc.roc_work, rtw89_roc_work);
+ rtw89_leave_ps_mode(rtwdev);
+diff --git a/drivers/net/wireless/realtek/rtw89/util.h b/drivers/net/wireless/realtek/rtw89/util.h
+index e2ed4565025dd..d4ee9078a4f48 100644
+--- a/drivers/net/wireless/realtek/rtw89/util.h
++++ b/drivers/net/wireless/realtek/rtw89/util.h
+@@ -14,6 +14,24 @@
+ #define rtw89_for_each_rtwvif(rtwdev, rtwvif) \
+ list_for_each_entry(rtwvif, &(rtwdev)->rtwvifs_list, list)
+
++/* Before adding rtwvif to list, we need to check if it already exist, beacase
++ * in some case such as SER L2 happen during WoWLAN flow, calling reconfig
++ * twice cause the list to be added twice.
++ */
++static inline bool rtw89_rtwvif_in_list(struct rtw89_dev *rtwdev,
++ struct rtw89_vif *new)
++{
++ struct rtw89_vif *rtwvif;
++
++ lockdep_assert_held(&rtwdev->mutex);
++
++ rtw89_for_each_rtwvif(rtwdev, rtwvif)
++ if (rtwvif == new)
++ return true;
++
++ return false;
++}
++
+ /* The result of negative dividend and positive divisor is undefined, but it
+ * should be one case of round-down or round-up. So, make it round-down if the
+ * result is round-up.
+--
+2.43.0
+
--- /dev/null
+From 734cd1e85b41c0dad76090e9a8036a6a59c983c9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 9 Aug 2024 15:20:10 +0800
+Subject: wifi: rtw89: correct base HT rate mask for firmware
+
+From: Ping-Ke Shih <pkshih@realtek.com>
+
+[ Upstream commit 45742881f9eee2a4daeb6008e648a460dd3742cd ]
+
+Coverity reported that u8 rx_mask << 24 will become signed 32 bits, which
+casting to unsigned 64 bits will do sign extension. For example,
+putting 0x80000000 (signed 32 bits) to a u64 variable will become
+0xFFFFFFFF_80000000.
+
+The real case we meet is:
+ rx_mask[0...3] = ff ff 00 00
+ ra_mask = 0xffffffff_ff0ff000
+
+After this fix:
+ rx_mask[0...3] = ff ff 00 00
+ ra_mask = 0x00000000_ff0ff000
+
+Fortunately driver does bitwise-AND with incorrect ra_mask and supported
+rates (1ss and 2ss rate only) afterward, so the final rate mask of
+original code is still correct.
+
+Addresses-Coverity-ID: 1504762 ("Unintended sign extension")
+
+Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
+Link: https://patch.msgid.link/20240809072012.84152-5-pkshih@realtek.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/realtek/rtw89/phy.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c
+index a82b4c56a6f45..f7c6b019b5be4 100644
+--- a/drivers/net/wireless/realtek/rtw89/phy.c
++++ b/drivers/net/wireless/realtek/rtw89/phy.c
+@@ -352,8 +352,8 @@ static void rtw89_phy_ra_sta_update(struct rtw89_dev *rtwdev,
+ csi_mode = RTW89_RA_RPT_MODE_HT;
+ ra_mask |= ((u64)sta->deflink.ht_cap.mcs.rx_mask[3] << 48) |
+ ((u64)sta->deflink.ht_cap.mcs.rx_mask[2] << 36) |
+- (sta->deflink.ht_cap.mcs.rx_mask[1] << 24) |
+- (sta->deflink.ht_cap.mcs.rx_mask[0] << 12);
++ ((u64)sta->deflink.ht_cap.mcs.rx_mask[1] << 24) |
++ ((u64)sta->deflink.ht_cap.mcs.rx_mask[0] << 12);
+ high_rate_masks = rtw89_ra_mask_ht_rates;
+ if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)
+ stbc_en = 1;
+--
+2.43.0
+
--- /dev/null
+From bc6c84eac6dbd511053fc06ae92bad6cac8ca8a4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 28 Jul 2024 13:06:10 +0200
+Subject: x86/apic: Remove logical destination mode for 64-bit
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+[ Upstream commit 838ba7733e4e3a94a928e8d0a058de1811a58621 ]
+
+Logical destination mode of the local APIC is used for systems with up to
+8 CPUs. It has an advantage over physical destination mode as it allows to
+target multiple CPUs at once with IPIs.
+
+That advantage was definitely worth it when systems with up to 8 CPUs
+were state of the art for servers and workstations, but that's history.
+
+Aside of that there are systems which fail to work with logical destination
+mode as the ACPI/DMI quirks show and there are AMD Zen1 systems out there
+which fail when interrupt remapping is enabled as reported by Rob and
+Christian. The latter problem can be cured by firmware updates, but not all
+OEMs distribute the required changes.
+
+Physical destination mode is guaranteed to work because it is the only way
+to get a CPU up and running via the INIT/INIT/STARTUP sequence.
+
+As the number of CPUs keeps increasing, logical destination mode becomes a
+less used code path so there is no real good reason to keep it around.
+
+Therefore remove logical destination mode support for 64-bit and default to
+physical destination mode.
+
+Reported-by: Rob Newcater <rob@durendal.co.uk>
+Reported-by: Christian Heusel <christian@heusel.eu>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Tested-by: Borislav Petkov (AMD) <bp@alien8.de>
+Tested-by: Rob Newcater <rob@durendal.co.uk>
+Link: https://lore.kernel.org/all/877cd5u671.ffs@tglx
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/include/asm/apic.h | 8 --
+ arch/x86/kernel/apic/apic_flat_64.c | 119 ++--------------------------
+ 2 files changed, 7 insertions(+), 120 deletions(-)
+
+diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h
+index 9327eb00e96d0..be2045a18e69b 100644
+--- a/arch/x86/include/asm/apic.h
++++ b/arch/x86/include/asm/apic.h
+@@ -345,20 +345,12 @@ extern struct apic *apic;
+ * APIC drivers are probed based on how they are listed in the .apicdrivers
+ * section. So the order is important and enforced by the ordering
+ * of different apic driver files in the Makefile.
+- *
+- * For the files having two apic drivers, we use apic_drivers()
+- * to enforce the order with in them.
+ */
+ #define apic_driver(sym) \
+ static const struct apic *__apicdrivers_##sym __used \
+ __aligned(sizeof(struct apic *)) \
+ __section(".apicdrivers") = { &sym }
+
+-#define apic_drivers(sym1, sym2) \
+- static struct apic *__apicdrivers_##sym1##sym2[2] __used \
+- __aligned(sizeof(struct apic *)) \
+- __section(".apicdrivers") = { &sym1, &sym2 }
+-
+ extern struct apic *__apicdrivers[], *__apicdrivers_end[];
+
+ /*
+diff --git a/arch/x86/kernel/apic/apic_flat_64.c b/arch/x86/kernel/apic/apic_flat_64.c
+index f37ad3392fec9..e0308d8c4e6c2 100644
+--- a/arch/x86/kernel/apic/apic_flat_64.c
++++ b/arch/x86/kernel/apic/apic_flat_64.c
+@@ -8,129 +8,25 @@
+ * Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and
+ * James Cleverdon.
+ */
+-#include <linux/cpumask.h>
+ #include <linux/export.h>
+-#include <linux/acpi.h>
+
+-#include <asm/jailhouse_para.h>
+ #include <asm/apic.h>
+
+ #include "local.h"
+
+-static struct apic apic_physflat;
+-static struct apic apic_flat;
+-
+-struct apic *apic __ro_after_init = &apic_flat;
+-EXPORT_SYMBOL_GPL(apic);
+-
+-static int flat_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
+-{
+- return 1;
+-}
+-
+-static void _flat_send_IPI_mask(unsigned long mask, int vector)
+-{
+- unsigned long flags;
+-
+- local_irq_save(flags);
+- __default_send_IPI_dest_field(mask, vector, APIC_DEST_LOGICAL);
+- local_irq_restore(flags);
+-}
+-
+-static void flat_send_IPI_mask(const struct cpumask *cpumask, int vector)
+-{
+- unsigned long mask = cpumask_bits(cpumask)[0];
+-
+- _flat_send_IPI_mask(mask, vector);
+-}
+-
+-static void
+-flat_send_IPI_mask_allbutself(const struct cpumask *cpumask, int vector)
+-{
+- unsigned long mask = cpumask_bits(cpumask)[0];
+- int cpu = smp_processor_id();
+-
+- if (cpu < BITS_PER_LONG)
+- __clear_bit(cpu, &mask);
+-
+- _flat_send_IPI_mask(mask, vector);
+-}
+-
+-static u32 flat_get_apic_id(u32 x)
++static u32 physflat_get_apic_id(u32 x)
+ {
+ return (x >> 24) & 0xFF;
+ }
+
+-static int flat_probe(void)
++static int physflat_probe(void)
+ {
+ return 1;
+ }
+
+-static struct apic apic_flat __ro_after_init = {
+- .name = "flat",
+- .probe = flat_probe,
+- .acpi_madt_oem_check = flat_acpi_madt_oem_check,
+-
+- .dest_mode_logical = true,
+-
+- .disable_esr = 0,
+-
+- .init_apic_ldr = default_init_apic_ldr,
+- .cpu_present_to_apicid = default_cpu_present_to_apicid,
+-
+- .max_apic_id = 0xFE,
+- .get_apic_id = flat_get_apic_id,
+-
+- .calc_dest_apicid = apic_flat_calc_apicid,
+-
+- .send_IPI = default_send_IPI_single,
+- .send_IPI_mask = flat_send_IPI_mask,
+- .send_IPI_mask_allbutself = flat_send_IPI_mask_allbutself,
+- .send_IPI_allbutself = default_send_IPI_allbutself,
+- .send_IPI_all = default_send_IPI_all,
+- .send_IPI_self = default_send_IPI_self,
+- .nmi_to_offline_cpu = true,
+-
+- .read = native_apic_mem_read,
+- .write = native_apic_mem_write,
+- .eoi = native_apic_mem_eoi,
+- .icr_read = native_apic_icr_read,
+- .icr_write = native_apic_icr_write,
+- .wait_icr_idle = apic_mem_wait_icr_idle,
+- .safe_wait_icr_idle = apic_mem_wait_icr_idle_timeout,
+-};
+-
+-/*
+- * Physflat mode is used when there are more than 8 CPUs on a system.
+- * We cannot use logical delivery in this case because the mask
+- * overflows, so use physical mode.
+- */
+ static int physflat_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
+ {
+-#ifdef CONFIG_ACPI
+- /*
+- * Quirk: some x86_64 machines can only use physical APIC mode
+- * regardless of how many processors are present (x86_64 ES7000
+- * is an example).
+- */
+- if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
+- (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL)) {
+- printk(KERN_DEBUG "system APIC only can use physical flat");
+- return 1;
+- }
+-
+- if (!strncmp(oem_id, "IBM", 3) && !strncmp(oem_table_id, "EXA", 3)) {
+- printk(KERN_DEBUG "IBM Summit detected, will use apic physical");
+- return 1;
+- }
+-#endif
+-
+- return 0;
+-}
+-
+-static int physflat_probe(void)
+-{
+- return apic == &apic_physflat || num_possible_cpus() > 8 || jailhouse_paravirt();
++ return 1;
+ }
+
+ static struct apic apic_physflat __ro_after_init = {
+@@ -146,7 +42,7 @@ static struct apic apic_physflat __ro_after_init = {
+ .cpu_present_to_apicid = default_cpu_present_to_apicid,
+
+ .max_apic_id = 0xFE,
+- .get_apic_id = flat_get_apic_id,
++ .get_apic_id = physflat_get_apic_id,
+
+ .calc_dest_apicid = apic_default_calc_apicid,
+
+@@ -166,8 +62,7 @@ static struct apic apic_physflat __ro_after_init = {
+ .wait_icr_idle = apic_mem_wait_icr_idle,
+ .safe_wait_icr_idle = apic_mem_wait_icr_idle_timeout,
+ };
++apic_driver(apic_physflat);
+
+-/*
+- * We need to check for physflat first, so this order is important.
+- */
+-apic_drivers(apic_physflat, apic_flat);
++struct apic *apic __ro_after_init = &apic_physflat;
++EXPORT_SYMBOL_GPL(apic);
+--
+2.43.0
+
--- /dev/null
+From 1247c64e6d9c800b7749ed463d0d5fcb8b11d2b5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 29 Aug 2024 12:24:37 -0700
+Subject: x86/bugs: Add missing NO_SSB flag
+
+From: Daniel Sneddon <daniel.sneddon@linux.intel.com>
+
+[ Upstream commit 23e12b54acf621f4f03381dca91cc5f1334f21fd ]
+
+The Moorefield and Lightning Mountain Atom processors are
+missing the NO_SSB flag in the vulnerabilities whitelist.
+This will cause unaffected parts to incorrectly be reported
+as vulnerable. Add the missing flag.
+
+These parts are currently out of service and were verified
+internally with archived documentation that they need the
+NO_SSB flag.
+
+Closes: https://lore.kernel.org/lkml/CAEJ9NQdhh+4GxrtG1DuYgqYhvc0hi-sKZh-2niukJ-MyFLntAA@mail.gmail.com/
+Reported-by: Shanavas.K.S <shanavasks@gmail.com>
+Signed-off-by: Daniel Sneddon <daniel.sneddon@linux.intel.com>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Link: https://lore.kernel.org/r/20240829192437.4074196-1-daniel.sneddon@linux.intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/kernel/cpu/common.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
+index d4e539d4e158c..be307c9ef263d 100644
+--- a/arch/x86/kernel/cpu/common.c
++++ b/arch/x86/kernel/cpu/common.c
+@@ -1165,8 +1165,8 @@ static const __initconst struct x86_cpu_id cpu_vuln_whitelist[] = {
+
+ VULNWL_INTEL(INTEL_CORE_YONAH, NO_SSB),
+
+- VULNWL_INTEL(INTEL_ATOM_AIRMONT_MID, NO_L1TF | MSBDS_ONLY | NO_SWAPGS | NO_ITLB_MULTIHIT),
+- VULNWL_INTEL(INTEL_ATOM_AIRMONT_NP, NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT),
++ VULNWL_INTEL(INTEL_ATOM_AIRMONT_MID, NO_SSB | NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT | MSBDS_ONLY),
++ VULNWL_INTEL(INTEL_ATOM_AIRMONT_NP, NO_SSB | NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT),
+
+ VULNWL_INTEL(INTEL_ATOM_GOLDMONT, NO_MDS | NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO),
+ VULNWL_INTEL(INTEL_ATOM_GOLDMONT_D, NO_MDS | NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO),
+--
+2.43.0
+
--- /dev/null
+From 986dc2c2467899b7682044ebe7521334f2f4cede Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 4 Sep 2024 10:07:11 -0500
+Subject: x86/bugs: Fix handling when SRSO mitigation is disabled
+
+From: David Kaplan <david.kaplan@amd.com>
+
+[ Upstream commit 1dbb6b1495d472806fef1f4c94f5b3e4c89a3c1d ]
+
+When the SRSO mitigation is disabled, either via mitigations=off or
+spec_rstack_overflow=off, the warning about the lack of IBPB-enhancing
+microcode is printed anyway.
+
+This is unnecessary since the user has turned off the mitigation.
+
+ [ bp: Massage, drop SBPB rationale as it doesn't matter because when
+ mitigations are disabled x86_pred_cmd is not being used anyway. ]
+
+Signed-off-by: David Kaplan <david.kaplan@amd.com>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Acked-by: Josh Poimboeuf <jpoimboe@kernel.org>
+Link: https://lore.kernel.org/r/20240904150711.193022-1-david.kaplan@amd.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/kernel/cpu/bugs.c | 14 +++++---------
+ 1 file changed, 5 insertions(+), 9 deletions(-)
+
+diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c
+index b6f927f6c567e..47c84503ad9be 100644
+--- a/arch/x86/kernel/cpu/bugs.c
++++ b/arch/x86/kernel/cpu/bugs.c
+@@ -2545,10 +2545,9 @@ static void __init srso_select_mitigation(void)
+ {
+ bool has_microcode = boot_cpu_has(X86_FEATURE_IBPB_BRTYPE);
+
+- if (cpu_mitigations_off())
+- return;
+-
+- if (!boot_cpu_has_bug(X86_BUG_SRSO)) {
++ if (!boot_cpu_has_bug(X86_BUG_SRSO) ||
++ cpu_mitigations_off() ||
++ srso_cmd == SRSO_CMD_OFF) {
+ if (boot_cpu_has(X86_FEATURE_SBPB))
+ x86_pred_cmd = PRED_CMD_SBPB;
+ return;
+@@ -2579,11 +2578,6 @@ static void __init srso_select_mitigation(void)
+ }
+
+ switch (srso_cmd) {
+- case SRSO_CMD_OFF:
+- if (boot_cpu_has(X86_FEATURE_SBPB))
+- x86_pred_cmd = PRED_CMD_SBPB;
+- return;
+-
+ case SRSO_CMD_MICROCODE:
+ if (has_microcode) {
+ srso_mitigation = SRSO_MITIGATION_MICROCODE;
+@@ -2637,6 +2631,8 @@ static void __init srso_select_mitigation(void)
+ pr_err("WARNING: kernel not compiled with MITIGATION_SRSO.\n");
+ }
+ break;
++ default:
++ break;
+ }
+
+ out:
+--
+2.43.0
+
--- /dev/null
+From 74433630ece2430c4fc67cd26b6841c9e2d320a1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 2 Aug 2024 18:15:34 +0200
+Subject: x86/ioapic: Handle allocation failures gracefully
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+[ Upstream commit 830802a0fea8fb39d3dc9fb7d6b5581e1343eb1f ]
+
+Breno observed panics when using failslab under certain conditions during
+runtime:
+
+ can not alloc irq_pin_list (-1,0,20)
+ Kernel panic - not syncing: IO-APIC: failed to add irq-pin. Can not proceed
+
+ panic+0x4e9/0x590
+ mp_irqdomain_alloc+0x9ab/0xa80
+ irq_domain_alloc_irqs_locked+0x25d/0x8d0
+ __irq_domain_alloc_irqs+0x80/0x110
+ mp_map_pin_to_irq+0x645/0x890
+ acpi_register_gsi_ioapic+0xe6/0x150
+ hpet_open+0x313/0x480
+
+That's a pointless panic which is a leftover of the historic IO/APIC code
+which panic'ed during early boot when the interrupt allocation failed.
+
+The only place which might justify panic is the PIT/HPET timer_check() code
+which tries to figure out whether the timer interrupt is delivered through
+the IO/APIC. But that code does not require to handle interrupt allocation
+failures. If the interrupt cannot be allocated then timer delivery fails
+and it either panics due to that or falls back to legacy mode.
+
+Cure this by removing the panic wrapper around __add_pin_to_irq_node() and
+making mp_irqdomain_alloc() aware of the failure condition and handle it as
+any other failure in this function gracefully.
+
+Reported-by: Breno Leitao <leitao@debian.org>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Tested-by: Breno Leitao <leitao@debian.org>
+Tested-by: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
+Link: https://lore.kernel.org/all/ZqfJmUF8sXIyuSHN@gmail.com
+Link: https://lore.kernel.org/all/20240802155440.275200843@linutronix.de
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/kernel/apic/io_apic.c | 46 ++++++++++++++++------------------
+ 1 file changed, 22 insertions(+), 24 deletions(-)
+
+diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
+index 477b740b2f267..d1ec1dcb637af 100644
+--- a/arch/x86/kernel/apic/io_apic.c
++++ b/arch/x86/kernel/apic/io_apic.c
+@@ -352,27 +352,26 @@ static void ioapic_mask_entry(int apic, int pin)
+ * shared ISA-space IRQs, so we have to support them. We are super
+ * fast in the common case, and fast for shared ISA-space IRQs.
+ */
+-static int __add_pin_to_irq_node(struct mp_chip_data *data,
+- int node, int apic, int pin)
++static bool add_pin_to_irq_node(struct mp_chip_data *data, int node, int apic, int pin)
+ {
+ struct irq_pin_list *entry;
+
+- /* don't allow duplicates */
+- for_each_irq_pin(entry, data->irq_2_pin)
++ /* Don't allow duplicates */
++ for_each_irq_pin(entry, data->irq_2_pin) {
+ if (entry->apic == apic && entry->pin == pin)
+- return 0;
++ return true;
++ }
+
+ entry = kzalloc_node(sizeof(struct irq_pin_list), GFP_ATOMIC, node);
+ if (!entry) {
+- pr_err("can not alloc irq_pin_list (%d,%d,%d)\n",
+- node, apic, pin);
+- return -ENOMEM;
++ pr_err("Cannot allocate irq_pin_list (%d,%d,%d)\n", node, apic, pin);
++ return false;
+ }
++
+ entry->apic = apic;
+ entry->pin = pin;
+ list_add_tail(&entry->list, &data->irq_2_pin);
+-
+- return 0;
++ return true;
+ }
+
+ static void __remove_pin_from_irq(struct mp_chip_data *data, int apic, int pin)
+@@ -387,13 +386,6 @@ static void __remove_pin_from_irq(struct mp_chip_data *data, int apic, int pin)
+ }
+ }
+
+-static void add_pin_to_irq_node(struct mp_chip_data *data,
+- int node, int apic, int pin)
+-{
+- if (__add_pin_to_irq_node(data, node, apic, pin))
+- panic("IO-APIC: failed to add irq-pin. Can not proceed\n");
+-}
+-
+ /*
+ * Reroute an IRQ to a different pin.
+ */
+@@ -1002,8 +994,7 @@ static int alloc_isa_irq_from_domain(struct irq_domain *domain,
+ if (irq_data && irq_data->parent_data) {
+ if (!mp_check_pin_attr(irq, info))
+ return -EBUSY;
+- if (__add_pin_to_irq_node(irq_data->chip_data, node, ioapic,
+- info->ioapic.pin))
++ if (!add_pin_to_irq_node(irq_data->chip_data, node, ioapic, info->ioapic.pin))
+ return -ENOMEM;
+ } else {
+ info->flags |= X86_IRQ_ALLOC_LEGACY;
+@@ -3017,10 +3008,8 @@ int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
+ return -ENOMEM;
+
+ ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, info);
+- if (ret < 0) {
+- kfree(data);
+- return ret;
+- }
++ if (ret < 0)
++ goto free_data;
+
+ INIT_LIST_HEAD(&data->irq_2_pin);
+ irq_data->hwirq = info->ioapic.pin;
+@@ -3029,7 +3018,10 @@ int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
+ irq_data->chip_data = data;
+ mp_irqdomain_get_attr(mp_pin_to_gsi(ioapic, pin), data, info);
+
+- add_pin_to_irq_node(data, ioapic_alloc_attr_node(info), ioapic, pin);
++ if (!add_pin_to_irq_node(data, ioapic_alloc_attr_node(info), ioapic, pin)) {
++ ret = -ENOMEM;
++ goto free_irqs;
++ }
+
+ mp_preconfigure_entry(data);
+ mp_register_handler(virq, data->is_level);
+@@ -3044,6 +3036,12 @@ int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
+ ioapic, mpc_ioapic_id(ioapic), pin, virq,
+ data->is_level, data->active_low);
+ return 0;
++
++free_irqs:
++ irq_domain_free_irqs_parent(domain, virq, nr_irqs);
++free_data:
++ kfree(data);
++ return ret;
+ }
+
+ void mp_irqdomain_free(struct irq_domain *domain, unsigned int virq,
+--
+2.43.0
+
--- /dev/null
+From e399b48d8b623fd1f4970d915351f766915b170d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 17 Jul 2024 16:31:20 -0500
+Subject: x86/kexec: Add EFI config table identity mapping for kexec kernel
+
+From: Tao Liu <ltao@redhat.com>
+
+[ Upstream commit 5760929f6545c651682de3c2c6c6786816b17bb1 ]
+
+A kexec kernel boot failure is sometimes observed on AMD CPUs due to an
+unmapped EFI config table array. This can be seen when "nogbpages" is on
+the kernel command line, and has been observed as a full BIOS reboot rather
+than a successful kexec.
+
+This was also the cause of reported regressions attributed to Commit
+7143c5f4cf20 ("x86/mm/ident_map: Use gbpages only where full GB page should
+be mapped.") which was subsequently reverted.
+
+To avoid this page fault, explicitly include the EFI config table array in
+the kexec identity map.
+
+Further explanation:
+
+The following 2 commits caused the EFI config table array to be
+accessed when enabling sev at kernel startup.
+
+ commit ec1c66af3a30 ("x86/compressed/64: Detect/setup SEV/SME features
+ earlier during boot")
+ commit c01fce9cef84 ("x86/compressed: Add SEV-SNP feature
+ detection/setup")
+
+This is in the code that examines whether SEV should be enabled or not, so
+it can even affect systems that are not SEV capable.
+
+This may result in a page fault if the EFI config table array's address is
+unmapped. Since the page fault occurs before the new kernel establishes its
+own identity map and page fault routines, it is unrecoverable and kexec
+fails.
+
+Most often, this problem is not seen because the EFI config table array
+gets included in the map by the luck of being placed at a memory address
+close enough to other memory areas that *are* included in the map created
+by kexec.
+
+Both the "nogbpages" command line option and the "use gpbages only where
+full GB page should be mapped" change greatly reduce the chance of being
+included in the map by luck, which is why the problem appears.
+
+Signed-off-by: Tao Liu <ltao@redhat.com>
+Signed-off-by: Steve Wahl <steve.wahl@hpe.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Tested-by: Pavin Joseph <me@pavinjoseph.com>
+Tested-by: Sarah Brofeldt <srhb@dbc.dk>
+Tested-by: Eric Hagberg <ehagberg@gmail.com>
+Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
+Link: https://lore.kernel.org/all/20240717213121.3064030-2-steve.wahl@hpe.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/kernel/machine_kexec_64.c | 27 +++++++++++++++++++++++++++
+ 1 file changed, 27 insertions(+)
+
+diff --git a/arch/x86/kernel/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c
+index cc0f7f70b17ba..9c9ac606893e9 100644
+--- a/arch/x86/kernel/machine_kexec_64.c
++++ b/arch/x86/kernel/machine_kexec_64.c
+@@ -28,6 +28,7 @@
+ #include <asm/setup.h>
+ #include <asm/set_memory.h>
+ #include <asm/cpu.h>
++#include <asm/efi.h>
+
+ #ifdef CONFIG_ACPI
+ /*
+@@ -87,6 +88,8 @@ map_efi_systab(struct x86_mapping_info *info, pgd_t *level4p)
+ {
+ #ifdef CONFIG_EFI
+ unsigned long mstart, mend;
++ void *kaddr;
++ int ret;
+
+ if (!efi_enabled(EFI_BOOT))
+ return 0;
+@@ -102,6 +105,30 @@ map_efi_systab(struct x86_mapping_info *info, pgd_t *level4p)
+ if (!mstart)
+ return 0;
+
++ ret = kernel_ident_mapping_init(info, level4p, mstart, mend);
++ if (ret)
++ return ret;
++
++ kaddr = memremap(mstart, mend - mstart, MEMREMAP_WB);
++ if (!kaddr) {
++ pr_err("Could not map UEFI system table\n");
++ return -ENOMEM;
++ }
++
++ mstart = efi_config_table;
++
++ if (efi_enabled(EFI_64BIT)) {
++ efi_system_table_64_t *stbl = (efi_system_table_64_t *)kaddr;
++
++ mend = mstart + sizeof(efi_config_table_64_t) * stbl->nr_tables;
++ } else {
++ efi_system_table_32_t *stbl = (efi_system_table_32_t *)kaddr;
++
++ mend = mstart + sizeof(efi_config_table_32_t) * stbl->nr_tables;
++ }
++
++ memunmap(kaddr);
++
+ return kernel_ident_mapping_init(info, level4p, mstart, mend);
+ #endif
+ return 0;
+--
+2.43.0
+
--- /dev/null
+From 82b519ecb2fd30fb62d54b2fd0a31bd750389840 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 17 Jul 2024 16:31:21 -0500
+Subject: x86/mm/ident_map: Use gbpages only where full GB page should be
+ mapped.
+
+From: Steve Wahl <steve.wahl@hpe.com>
+
+[ Upstream commit cc31744a294584a36bf764a0ffa3255a8e69f036 ]
+
+When ident_pud_init() uses only GB pages to create identity maps, large
+ranges of addresses not actually requested can be included in the resulting
+table; a 4K request will map a full GB. This can include a lot of extra
+address space past that requested, including areas marked reserved by the
+BIOS. That allows processor speculation into reserved regions, that on UV
+systems can cause system halts.
+
+Only use GB pages when map creation requests include the full GB page of
+space. Fall back to using smaller 2M pages when only portions of a GB page
+are included in the request.
+
+No attempt is made to coalesce mapping requests. If a request requires a
+map entry at the 2M (pmd) level, subsequent mapping requests within the
+same 1G region will also be at the pmd level, even if adjacent or
+overlapping such requests could have been combined to map a full GB page.
+Existing usage starts with larger regions and then adds smaller regions, so
+this should not have any great consequence.
+
+Signed-off-by: Steve Wahl <steve.wahl@hpe.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Tested-by: Pavin Joseph <me@pavinjoseph.com>
+Tested-by: Sarah Brofeldt <srhb@dbc.dk>
+Tested-by: Eric Hagberg <ehagberg@gmail.com>
+Link: https://lore.kernel.org/all/20240717213121.3064030-3-steve.wahl@hpe.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/mm/ident_map.c | 23 ++++++++++++++++++-----
+ 1 file changed, 18 insertions(+), 5 deletions(-)
+
+diff --git a/arch/x86/mm/ident_map.c b/arch/x86/mm/ident_map.c
+index 968d7005f4a72..a204a332c71fc 100644
+--- a/arch/x86/mm/ident_map.c
++++ b/arch/x86/mm/ident_map.c
+@@ -26,18 +26,31 @@ static int ident_pud_init(struct x86_mapping_info *info, pud_t *pud_page,
+ for (; addr < end; addr = next) {
+ pud_t *pud = pud_page + pud_index(addr);
+ pmd_t *pmd;
++ bool use_gbpage;
+
+ next = (addr & PUD_MASK) + PUD_SIZE;
+ if (next > end)
+ next = end;
+
+- if (info->direct_gbpages) {
+- pud_t pudval;
++ /* if this is already a gbpage, this portion is already mapped */
++ if (pud_leaf(*pud))
++ continue;
++
++ /* Is using a gbpage allowed? */
++ use_gbpage = info->direct_gbpages;
+
+- if (pud_present(*pud))
+- continue;
++ /* Don't use gbpage if it maps more than the requested region. */
++ /* at the begining: */
++ use_gbpage &= ((addr & ~PUD_MASK) == 0);
++ /* ... or at the end: */
++ use_gbpage &= ((next & ~PUD_MASK) == 0);
++
++ /* Never overwrite existing mappings */
++ use_gbpage &= !pud_present(*pud);
++
++ if (use_gbpage) {
++ pud_t pudval;
+
+- addr &= PUD_MASK;
+ pudval = __pud((addr - info->offset) | info->page_flag);
+ set_pud(pud, pudval);
+ continue;
+--
+2.43.0
+
--- /dev/null
+From a9e240fd744a39556fff7f3dc083d4a4bae11caf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 2 Aug 2024 06:13:14 +0000
+Subject: x86/pkeys: Add PKRU as a parameter in signal handling functions
+
+From: Aruna Ramakrishna <aruna.ramakrishna@oracle.com>
+
+[ Upstream commit 24cf2bc982ffe02aeffb4a3885c71751a2c7023b ]
+
+Assume there's a multithreaded application that runs untrusted user
+code. Each thread has its stack/code protected by a non-zero PKEY, and the
+PKRU register is set up such that only that particular non-zero PKEY is
+enabled. Each thread also sets up an alternate signal stack to handle
+signals, which is protected by PKEY zero. The PKEYs man page documents that
+the PKRU will be reset to init_pkru when the signal handler is invoked,
+which means that PKEY zero access will be enabled. But this reset happens
+after the kernel attempts to push fpu state to the alternate stack, which
+is not (yet) accessible by the kernel, which leads to a new SIGSEGV being
+sent to the application, terminating it.
+
+Enabling both the non-zero PKEY (for the thread) and PKEY zero in
+userspace will not work for this use case. It cannot have the alt stack
+writeable by all - the rationale here is that the code running in that
+thread (using a non-zero PKEY) is untrusted and should not have access
+to the alternate signal stack (that uses PKEY zero), to prevent the
+return address of a function from being changed. The expectation is that
+kernel should be able to set up the alternate signal stack and deliver
+the signal to the application even if PKEY zero is explicitly disabled
+by the application. The signal handler accessibility should not be
+dictated by whatever PKRU value the thread sets up.
+
+The PKRU register is managed by XSAVE, which means the sigframe contents
+must match the register contents - which is not the case here. It's
+required that the signal frame contains the user-defined PKRU value (so
+that it is restored correctly from sigcontext) but the actual register must
+be reset to init_pkru so that the alt stack is accessible and the signal
+can be delivered to the application. It seems that the proper fix here
+would be to remove PKRU from the XSAVE framework and manage it separately,
+which is quite complicated. As a workaround, do this:
+
+ orig_pkru = rdpkru();
+ wrpkru(orig_pkru & init_pkru_value);
+ xsave_to_user_sigframe();
+ put_user(pkru_sigframe_addr, orig_pkru)
+
+In preparation for writing PKRU to sigframe, pass PKRU as an additional
+parameter down the call chain from get_sigframe().
+
+No functional change.
+
+Signed-off-by: Aruna Ramakrishna <aruna.ramakrishna@oracle.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Link: https://lore.kernel.org/all/20240802061318.2140081-2-aruna.ramakrishna@oracle.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/include/asm/fpu/signal.h | 2 +-
+ arch/x86/kernel/fpu/signal.c | 6 +++---
+ arch/x86/kernel/signal.c | 3 ++-
+ 3 files changed, 6 insertions(+), 5 deletions(-)
+
+diff --git a/arch/x86/include/asm/fpu/signal.h b/arch/x86/include/asm/fpu/signal.h
+index 611fa41711aff..eccc75bc9c4f3 100644
+--- a/arch/x86/include/asm/fpu/signal.h
++++ b/arch/x86/include/asm/fpu/signal.h
+@@ -29,7 +29,7 @@ fpu__alloc_mathframe(unsigned long sp, int ia32_frame,
+
+ unsigned long fpu__get_fpstate_size(void);
+
+-extern bool copy_fpstate_to_sigframe(void __user *buf, void __user *fp, int size);
++extern bool copy_fpstate_to_sigframe(void __user *buf, void __user *fp, int size, u32 pkru);
+ extern void fpu__clear_user_states(struct fpu *fpu);
+ extern bool fpu__restore_sig(void __user *buf, int ia32_frame);
+
+diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c
+index 247f2225aa9f3..2b3b9e140dd41 100644
+--- a/arch/x86/kernel/fpu/signal.c
++++ b/arch/x86/kernel/fpu/signal.c
+@@ -156,7 +156,7 @@ static inline bool save_xstate_epilog(void __user *buf, int ia32_frame,
+ return !err;
+ }
+
+-static inline int copy_fpregs_to_sigframe(struct xregs_state __user *buf)
++static inline int copy_fpregs_to_sigframe(struct xregs_state __user *buf, u32 pkru)
+ {
+ if (use_xsave())
+ return xsave_to_user_sigframe(buf);
+@@ -185,7 +185,7 @@ static inline int copy_fpregs_to_sigframe(struct xregs_state __user *buf)
+ * For [f]xsave state, update the SW reserved fields in the [f]xsave frame
+ * indicating the absence/presence of the extended state to the user.
+ */
+-bool copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size)
++bool copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size, u32 pkru)
+ {
+ struct task_struct *tsk = current;
+ struct fpstate *fpstate = tsk->thread.fpu.fpstate;
+@@ -228,7 +228,7 @@ bool copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size)
+ fpregs_restore_userregs();
+
+ pagefault_disable();
+- ret = copy_fpregs_to_sigframe(buf_fx);
++ ret = copy_fpregs_to_sigframe(buf_fx, pkru);
+ pagefault_enable();
+ fpregs_unlock();
+
+diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c
+index 31b6f5dddfc27..1f1e8e0ac5a34 100644
+--- a/arch/x86/kernel/signal.c
++++ b/arch/x86/kernel/signal.c
+@@ -84,6 +84,7 @@ get_sigframe(struct ksignal *ksig, struct pt_regs *regs, size_t frame_size,
+ unsigned long math_size = 0;
+ unsigned long sp = regs->sp;
+ unsigned long buf_fx = 0;
++ u32 pkru = read_pkru();
+
+ /* redzone */
+ if (!ia32_frame)
+@@ -139,7 +140,7 @@ get_sigframe(struct ksignal *ksig, struct pt_regs *regs, size_t frame_size,
+ }
+
+ /* save i387 and extended state */
+- if (!copy_fpstate_to_sigframe(*fpstate, (void __user *)buf_fx, math_size))
++ if (!copy_fpstate_to_sigframe(*fpstate, (void __user *)buf_fx, math_size, pkru))
+ return (void __user *)-1L;
+
+ return (void __user *)sp;
+--
+2.43.0
+
--- /dev/null
+From dd65e95f89bc8480375ad65f989670f175e34941 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 2 Aug 2024 06:13:17 +0000
+Subject: x86/pkeys: Restore altstack access in sigreturn()
+
+From: Aruna Ramakrishna <aruna.ramakrishna@oracle.com>
+
+[ Upstream commit d10b554919d4cc8fa8fe2e95b57ad2624728c8e4 ]
+
+A process can disable access to the alternate signal stack by not
+enabling the altstack's PKEY in the PKRU register.
+
+Nevertheless, the kernel updates the PKRU temporarily for signal
+handling. However, in sigreturn(), restore_sigcontext() will restore the
+PKRU to the user-defined PKRU value.
+
+This will cause restore_altstack() to fail with a SIGSEGV as it needs read
+access to the altstack which is prohibited by the user-defined PKRU value.
+
+Fix this by restoring altstack before restoring PKRU.
+
+Signed-off-by: Aruna Ramakrishna <aruna.ramakrishna@oracle.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Link: https://lore.kernel.org/all/20240802061318.2140081-5-aruna.ramakrishna@oracle.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/kernel/signal_64.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/arch/x86/kernel/signal_64.c b/arch/x86/kernel/signal_64.c
+index 8a94053c54446..ee9453891901b 100644
+--- a/arch/x86/kernel/signal_64.c
++++ b/arch/x86/kernel/signal_64.c
+@@ -260,13 +260,13 @@ SYSCALL_DEFINE0(rt_sigreturn)
+
+ set_current_blocked(&set);
+
+- if (!restore_sigcontext(regs, &frame->uc.uc_mcontext, uc_flags))
++ if (restore_altstack(&frame->uc.uc_stack))
+ goto badframe;
+
+- if (restore_signal_shadow_stack())
++ if (!restore_sigcontext(regs, &frame->uc.uc_mcontext, uc_flags))
+ goto badframe;
+
+- if (restore_altstack(&frame->uc.uc_stack))
++ if (restore_signal_shadow_stack())
+ goto badframe;
+
+ return regs->ax;
+--
+2.43.0
+
--- /dev/null
+From 2981a1b5973d0439ff4c0188563f420e0422ca23 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 8 Jul 2024 13:22:06 -0700
+Subject: x86/syscall: Avoid memcpy() for ia32 syscall_get_arguments()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Kees Cook <kees@kernel.org>
+
+[ Upstream commit d19d638b1e6cf746263ef60b7d0dee0204d8216a ]
+
+Modern (fortified) memcpy() prefers to avoid writing (or reading) beyond
+the end of the addressed destination (or source) struct member:
+
+In function ‘fortify_memcpy_chk’,
+ inlined from ‘syscall_get_arguments’ at ./arch/x86/include/asm/syscall.h:85:2,
+ inlined from ‘populate_seccomp_data’ at kernel/seccomp.c:258:2,
+ inlined from ‘__seccomp_filter’ at kernel/seccomp.c:1231:3:
+./include/linux/fortify-string.h:580:25: error: call to ‘__read_overflow2_field’ declared with attribute warning: detected read beyond size of field (2nd parameter); maybe use struct_group()? [-Werror=attribute-warning]
+ 580 | __read_overflow2_field(q_size_field, size);
+ | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+As already done for x86_64 and compat mode, do not use memcpy() to
+extract syscall arguments from struct pt_regs but rather just perform
+direct assignments. Binary output differences are negligible, and actually
+ends up using less stack space:
+
+- sub $0x84,%esp
++ sub $0x6c,%esp
+
+and less text size:
+
+ text data bss dec hex filename
+ 10794 252 0 11046 2b26 gcc-32b/kernel/seccomp.o.stock
+ 10714 252 0 10966 2ad6 gcc-32b/kernel/seccomp.o.after
+
+Closes: https://lore.kernel.org/lkml/9b69fb14-df89-4677-9c82-056ea9e706f5@gmail.com/
+Reported-by: Mirsad Todorovac <mtodorovac69@gmail.com>
+Signed-off-by: Kees Cook <kees@kernel.org>
+Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
+Reviewed-by: Gustavo A. R. Silva <gustavoars@kernel.org>
+Acked-by: Dave Hansen <dave.hansen@linux.intel.com>
+Tested-by: Mirsad Todorovac <mtodorovac69@gmail.com>
+Link: https://lore.kernel.org/all/20240708202202.work.477-kees%40kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/include/asm/syscall.h | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/arch/x86/include/asm/syscall.h b/arch/x86/include/asm/syscall.h
+index 2fc7bc3863ff6..7c488ff0c7641 100644
+--- a/arch/x86/include/asm/syscall.h
++++ b/arch/x86/include/asm/syscall.h
+@@ -82,7 +82,12 @@ static inline void syscall_get_arguments(struct task_struct *task,
+ struct pt_regs *regs,
+ unsigned long *args)
+ {
+- memcpy(args, ®s->bx, 6 * sizeof(args[0]));
++ args[0] = regs->bx;
++ args[1] = regs->cx;
++ args[2] = regs->dx;
++ args[3] = regs->si;
++ args[4] = regs->di;
++ args[5] = regs->bp;
+ }
+
+ static inline int syscall_get_arch(struct task_struct *task)
+--
+2.43.0
+