From: Sasha Levin Date: Sun, 6 Oct 2024 15:11:22 +0000 (-0400) Subject: Fixes for 6.10 X-Git-Tag: v6.6.55~135 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a652ac366655c36c35d752c9cf42385152c4fd07;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for 6.10 Signed-off-by: Sasha Levin --- diff --git a/queue-6.10/acpi-cppc-add-support-for-setting-epp-register-in-ff.patch b/queue-6.10/acpi-cppc-add-support-for-setting-epp-register-in-ff.patch new file mode 100644 index 00000000000..e811d5c717b --- /dev/null +++ b/queue-6.10/acpi-cppc-add-support-for-setting-epp-register-in-ff.patch @@ -0,0 +1,74 @@ +From 37388a81aab1a4c4fcf870fc68df3fb28291c49e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Sep 2024 22:15:24 -0500 +Subject: ACPI: CPPC: Add support for setting EPP register in FFH +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Mario Limonciello + +[ Upstream commit aaf21ac93909e08a12931173336bdb52ac8499f1 ] + +Some Asus AMD systems are reported to not be able to change EPP values +because the BIOS doesn't advertise support for the CPPC MSR and the PCC +region is not configured. + +However the ACPI 6.2 specification allows CPC registers to be declared +in FFH: +``` +Starting with ACPI Specification 6.2, all _CPC registers can be in +PCC, System Memory, System IO, or Functional Fixed Hardware address +spaces. OSPM support for this more flexible register space scheme +is indicated by the “Flexible Address Space for CPPC Registers” _OSC +bit. +``` + +If this _OSC has been set allow using FFH to configure EPP. + +Reported-by: al0uette@outlook.com +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=218686 +Suggested-by: al0uette@outlook.com +Tested-by: vderp@icloud.com +Tested-by: al0uette@outlook.com +Signed-off-by: Mario Limonciello +Link: https://patch.msgid.link/20240910031524.106387-1-superm1@kernel.org +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/cppc_acpi.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c +index 2a588e4ed4af4..6a048d44fbcf6 100644 +--- a/drivers/acpi/cppc_acpi.c ++++ b/drivers/acpi/cppc_acpi.c +@@ -103,6 +103,11 @@ static DEFINE_PER_CPU(struct cpc_desc *, cpc_desc_ptr); + (cpc)->cpc_entry.reg.space_id == \ + ACPI_ADR_SPACE_PLATFORM_COMM) + ++/* Check if a CPC register is in FFH */ ++#define CPC_IN_FFH(cpc) ((cpc)->type == ACPI_TYPE_BUFFER && \ ++ (cpc)->cpc_entry.reg.space_id == \ ++ ACPI_ADR_SPACE_FIXED_HARDWARE) ++ + /* Check if a CPC register is in SystemMemory */ + #define CPC_IN_SYSTEM_MEMORY(cpc) ((cpc)->type == ACPI_TYPE_BUFFER && \ + (cpc)->cpc_entry.reg.space_id == \ +@@ -1519,9 +1524,12 @@ int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool enable) + /* after writing CPC, transfer the ownership of PCC to platform */ + ret = send_pcc_cmd(pcc_ss_id, CMD_WRITE); + up_write(&pcc_ss_data->pcc_lock); ++ } else if (osc_cpc_flexible_adr_space_confirmed && ++ CPC_SUPPORTED(epp_set_reg) && CPC_IN_FFH(epp_set_reg)) { ++ ret = cpc_write(cpu, epp_set_reg, perf_ctrls->energy_perf); + } else { + ret = -ENOTSUPP; +- pr_debug("_CPC in PCC is not supported\n"); ++ pr_debug("_CPC in PCC and _CPC in FFH are not supported\n"); + } + + return ret; +-- +2.43.0 + diff --git a/queue-6.10/acpi-ec-do-not-release-locks-during-operation-region.patch b/queue-6.10/acpi-ec-do-not-release-locks-during-operation-region.patch new file mode 100644 index 00000000000..05feed119cb --- /dev/null +++ b/queue-6.10/acpi-ec-do-not-release-locks-during-operation-region.patch @@ -0,0 +1,166 @@ +From 076c028fbcdc9eb276b319b82f74e1d62c54d959 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jul 2024 18:26:54 +0200 +Subject: ACPI: EC: Do not release locks during operation region accesses + +From: Rafael J. Wysocki + +[ Upstream commit dc171114926ec390ab90f46534545420ec03e458 ] + +It is not particularly useful to release locks (the EC mutex and the +ACPI global lock, if present) and re-acquire them immediately thereafter +during EC address space accesses in acpi_ec_space_handler(). + +First, releasing them for a while before grabbing them again does not +really help anyone because there may not be enough time for another +thread to acquire them. + +Second, if another thread successfully acquires them and carries out +a new EC write or read in the middle if an operation region access in +progress, it may confuse the EC firmware, especially after the burst +mode has been enabled. + +Finally, manipulating the locks after writing or reading every single +byte of data is overhead that it is better to avoid. + +Accordingly, modify the code to carry out EC address space accesses +entirely without releasing the locks. + +Signed-off-by: Rafael J. Wysocki +Reviewed-by: Hans de Goede +Link: https://patch.msgid.link/12473338.O9o76ZdvQC@rjwysocki.net +Signed-off-by: Sasha Levin +--- + drivers/acpi/ec.c | 55 +++++++++++++++++++++++++++++++++++++++++------ + 1 file changed, 49 insertions(+), 6 deletions(-) + +diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c +index 38d2f6e6b12b4..25399f6dde7e2 100644 +--- a/drivers/acpi/ec.c ++++ b/drivers/acpi/ec.c +@@ -783,6 +783,9 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, + unsigned long tmp; + int ret = 0; + ++ if (t->rdata) ++ memset(t->rdata, 0, t->rlen); ++ + /* start transaction */ + spin_lock_irqsave(&ec->lock, tmp); + /* Enable GPE for command processing (IBF=0/OBF=1) */ +@@ -819,8 +822,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) + + if (!ec || (!t) || (t->wlen && !t->wdata) || (t->rlen && !t->rdata)) + return -EINVAL; +- if (t->rdata) +- memset(t->rdata, 0, t->rlen); + + mutex_lock(&ec->mutex); + if (ec->global_lock) { +@@ -847,7 +848,7 @@ static int acpi_ec_burst_enable(struct acpi_ec *ec) + .wdata = NULL, .rdata = &d, + .wlen = 0, .rlen = 1}; + +- return acpi_ec_transaction(ec, &t); ++ return acpi_ec_transaction_unlocked(ec, &t); + } + + static int acpi_ec_burst_disable(struct acpi_ec *ec) +@@ -857,7 +858,7 @@ static int acpi_ec_burst_disable(struct acpi_ec *ec) + .wlen = 0, .rlen = 0}; + + return (acpi_ec_read_status(ec) & ACPI_EC_FLAG_BURST) ? +- acpi_ec_transaction(ec, &t) : 0; ++ acpi_ec_transaction_unlocked(ec, &t) : 0; + } + + static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 *data) +@@ -873,6 +874,19 @@ static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 *data) + return result; + } + ++static int acpi_ec_read_unlocked(struct acpi_ec *ec, u8 address, u8 *data) ++{ ++ int result; ++ u8 d; ++ struct transaction t = {.command = ACPI_EC_COMMAND_READ, ++ .wdata = &address, .rdata = &d, ++ .wlen = 1, .rlen = 1}; ++ ++ result = acpi_ec_transaction_unlocked(ec, &t); ++ *data = d; ++ return result; ++} ++ + static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data) + { + u8 wdata[2] = { address, data }; +@@ -883,6 +897,16 @@ static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data) + return acpi_ec_transaction(ec, &t); + } + ++static int acpi_ec_write_unlocked(struct acpi_ec *ec, u8 address, u8 data) ++{ ++ u8 wdata[2] = { address, data }; ++ struct transaction t = {.command = ACPI_EC_COMMAND_WRITE, ++ .wdata = wdata, .rdata = NULL, ++ .wlen = 2, .rlen = 0}; ++ ++ return acpi_ec_transaction_unlocked(ec, &t); ++} ++ + int ec_read(u8 addr, u8 *val) + { + int err; +@@ -1323,6 +1347,7 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address, + struct acpi_ec *ec = handler_context; + int result = 0, i, bytes = bits / 8; + u8 *value = (u8 *)value64; ++ u32 glk; + + if ((address > 0xFF) || !value || !handler_context) + return AE_BAD_PARAMETER; +@@ -1330,13 +1355,25 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address, + if (function != ACPI_READ && function != ACPI_WRITE) + return AE_BAD_PARAMETER; + ++ mutex_lock(&ec->mutex); ++ ++ if (ec->global_lock) { ++ acpi_status status; ++ ++ status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); ++ if (ACPI_FAILURE(status)) { ++ result = -ENODEV; ++ goto unlock; ++ } ++ } ++ + if (ec->busy_polling || bits > 8) + acpi_ec_burst_enable(ec); + + for (i = 0; i < bytes; ++i, ++address, ++value) { + result = (function == ACPI_READ) ? +- acpi_ec_read(ec, address, value) : +- acpi_ec_write(ec, address, *value); ++ acpi_ec_read_unlocked(ec, address, value) : ++ acpi_ec_write_unlocked(ec, address, *value); + if (result < 0) + break; + } +@@ -1344,6 +1381,12 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address, + if (ec->busy_polling || bits > 8) + acpi_ec_burst_disable(ec); + ++ if (ec->global_lock) ++ acpi_release_global_lock(glk); ++ ++unlock: ++ mutex_unlock(&ec->mutex); ++ + switch (result) { + case -EINVAL: + return AE_BAD_PARAMETER; +-- +2.43.0 + diff --git a/queue-6.10/acpi-pad-fix-crash-in-exit_round_robin.patch b/queue-6.10/acpi-pad-fix-crash-in-exit_round_robin.patch new file mode 100644 index 00000000000..2063e081885 --- /dev/null +++ b/queue-6.10/acpi-pad-fix-crash-in-exit_round_robin.patch @@ -0,0 +1,96 @@ +From c82a268eeb0d10b9b08ebd401ff7243df48358d5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 25 Aug 2024 23:13:52 +0900 +Subject: ACPI: PAD: fix crash in exit_round_robin() + +From: Seiji Nishikawa + +[ Upstream commit 0a2ed70a549e61c5181bad5db418d223b68ae932 ] + +The kernel occasionally crashes in cpumask_clear_cpu(), which is called +within exit_round_robin(), because when executing clear_bit(nr, addr) with +nr set to 0xffffffff, the address calculation may cause misalignment within +the memory, leading to access to an invalid memory address. + +---------- +BUG: unable to handle kernel paging request at ffffffffe0740618 + ... +CPU: 3 PID: 2919323 Comm: acpi_pad/14 Kdump: loaded Tainted: G OE X --------- - - 4.18.0-425.19.2.el8_7.x86_64 #1 + ... +RIP: 0010:power_saving_thread+0x313/0x411 [acpi_pad] +Code: 89 cd 48 89 d3 eb d1 48 c7 c7 55 70 72 c0 e8 64 86 b0 e4 c6 05 0d a1 02 00 01 e9 bc fd ff ff 45 89 e4 42 8b 04 a5 20 82 72 c0 48 0f b3 05 f4 9c 01 00 42 c7 04 a5 20 82 72 c0 ff ff ff ff 31 +RSP: 0018:ff72a5d51fa77ec8 EFLAGS: 00010202 +RAX: 00000000ffffffff RBX: ff462981e5d8cb80 RCX: 0000000000000000 +RDX: 0000000000000000 RSI: 0000000000000246 RDI: 0000000000000246 +RBP: ff46297556959d80 R08: 0000000000000382 R09: ff46297c8d0f38d8 +R10: 0000000000000000 R11: 0000000000000001 R12: 000000000000000e +R13: 0000000000000000 R14: ffffffffffffffff R15: 000000000000000e +FS: 0000000000000000(0000) GS:ff46297a800c0000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: ffffffffe0740618 CR3: 0000007e20410004 CR4: 0000000000771ee0 +DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 +DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 +PKRU: 55555554 +Call Trace: + ? acpi_pad_add+0x120/0x120 [acpi_pad] + kthread+0x10b/0x130 + ? set_kthread_struct+0x50/0x50 + ret_from_fork+0x1f/0x40 + ... +CR2: ffffffffe0740618 + +crash> dis -lr ffffffffc0726923 + ... +/usr/src/debug/kernel-4.18.0-425.19.2.el8_7/linux-4.18.0-425.19.2.el8_7.x86_64/./include/linux/cpumask.h: 114 +0xffffffffc0726918 : mov %r12d,%r12d +/usr/src/debug/kernel-4.18.0-425.19.2.el8_7/linux-4.18.0-425.19.2.el8_7.x86_64/./include/linux/cpumask.h: 325 +0xffffffffc072691b : mov -0x3f8d7de0(,%r12,4),%eax +/usr/src/debug/kernel-4.18.0-425.19.2.el8_7/linux-4.18.0-425.19.2.el8_7.x86_64/./arch/x86/include/asm/bitops.h: 80 +0xffffffffc0726923 : lock btr %rax,0x19cf4(%rip) # 0xffffffffc0740620 + +crash> px tsk_in_cpu[14] +$66 = 0xffffffff + +crash> px 0xffffffffc072692c+0x19cf4 +$99 = 0xffffffffc0740620 + +crash> sym 0xffffffffc0740620 +ffffffffc0740620 (b) pad_busy_cpus_bits [acpi_pad] + +crash> px pad_busy_cpus_bits[0] +$42 = 0xfffc0 +---------- + +To fix this, ensure that tsk_in_cpu[tsk_index] != -1 before calling +cpumask_clear_cpu() in exit_round_robin(), just as it is done in +round_robin_cpu(). + +Signed-off-by: Seiji Nishikawa +Link: https://patch.msgid.link/20240825141352.25280-1-snishika@redhat.com +[ rjw: Subject edit, avoid updates to the same value ] +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/acpi_pad.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c +index bd1ad07f02907..e84509b19f94d 100644 +--- a/drivers/acpi/acpi_pad.c ++++ b/drivers/acpi/acpi_pad.c +@@ -132,8 +132,10 @@ static void exit_round_robin(unsigned int tsk_index) + { + struct cpumask *pad_busy_cpus = to_cpumask(pad_busy_cpus_bits); + +- cpumask_clear_cpu(tsk_in_cpu[tsk_index], pad_busy_cpus); +- tsk_in_cpu[tsk_index] = -1; ++ if (tsk_in_cpu[tsk_index] != -1) { ++ cpumask_clear_cpu(tsk_in_cpu[tsk_index], pad_busy_cpus); ++ tsk_in_cpu[tsk_index] = -1; ++ } + } + + static unsigned int idle_pct = 5; /* percentage */ +-- +2.43.0 + diff --git a/queue-6.10/acpi-resource-skip-irq-override-on-asus-vivobook-go-.patch b/queue-6.10/acpi-resource-skip-irq-override-on-asus-vivobook-go-.patch new file mode 100644 index 00000000000..da7d8c674fc --- /dev/null +++ b/queue-6.10/acpi-resource-skip-irq-override-on-asus-vivobook-go-.patch @@ -0,0 +1,48 @@ +From f40ceea36548d65154cbf4e71a6133f4fdc428c6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Sep 2024 21:43:05 -0400 +Subject: ACPI: resource: Skip IRQ override on Asus Vivobook Go E1404GAB + +From: Tamim Khan + +[ 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 +Link: https://patch.msgid.link/20240903014317.38858-1-tamim@fusetak.com +[ rjw: Changelog edits ] +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/resource.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c +index cb2aacbb93357..8a4726e2eb693 100644 +--- a/drivers/acpi/resource.c ++++ b/drivers/acpi/resource.c +@@ -503,6 +503,13 @@ static const struct dmi_system_id irq1_level_low_skip_override[] = { + DMI_MATCH(DMI_BOARD_NAME, "B2502FBA"), + }, + }, ++ { ++ /* Asus Vivobook Go E1404GAB */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), ++ DMI_MATCH(DMI_BOARD_NAME, "E1404GAB"), ++ }, ++ }, + { + /* Asus Vivobook E1504GA */ + .matches = { +-- +2.43.0 + diff --git a/queue-6.10/acpi-video-add-force_vendor-quirk-for-panasonic-toug.patch b/queue-6.10/acpi-video-add-force_vendor-quirk-for-panasonic-toug.patch new file mode 100644 index 00000000000..48332881dc8 --- /dev/null +++ b/queue-6.10/acpi-video-add-force_vendor-quirk-for-panasonic-toug.patch @@ -0,0 +1,45 @@ +From 868c366b71d3a9eddc22f45b52a14a0ce2dd4c36 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Sep 2024 14:44:19 +0200 +Subject: ACPI: video: Add force_vendor quirk for Panasonic Toughbook CF-18 + +From: Hans de Goede + +[ Upstream commit eb7b0f12e13ba99e64e3a690c2166895ed63b437 ] + +The Panasonic Toughbook CF-18 advertises both native and vendor backlight +control interfaces. But only the vendor one actually works. + +acpi_video_get_backlight_type() will pick the non working native backlight +by default, add a quirk to select the working vendor backlight instead. + +Signed-off-by: Hans de Goede +Link: https://patch.msgid.link/20240907124419.21195-1-hdegoede@redhat.com +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/video_detect.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c +index 75a5f559402f8..428a7399fe04a 100644 +--- a/drivers/acpi/video_detect.c ++++ b/drivers/acpi/video_detect.c +@@ -254,6 +254,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "PCG-FRV35"), + }, + }, ++ { ++ .callback = video_detect_force_vendor, ++ /* Panasonic Toughbook CF-18 */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Matsushita Electric Industrial"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "CF-18"), ++ }, ++ }, + + /* + * Toshiba models with Transflective display, these need to use +-- +2.43.0 + diff --git a/queue-6.10/acpica-check-null-return-of-acpi_allocate_zeroed-in-.patch b/queue-6.10/acpica-check-null-return-of-acpi_allocate_zeroed-in-.patch new file mode 100644 index 00000000000..c34ca1ccd99 --- /dev/null +++ b/queue-6.10/acpica-check-null-return-of-acpi_allocate_zeroed-in-.patch @@ -0,0 +1,41 @@ +From 145ecb817f92512d9578d61098adddcaae580434 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Jul 2024 14:05:48 +0800 +Subject: ACPICA: check null return of ACPI_ALLOCATE_ZEROED() in + acpi_db_convert_to_package() + +From: Pei Xiao + +[ Upstream commit a5242874488eba2b9062985bf13743c029821330 ] + +ACPICA commit 4d4547cf13cca820ff7e0f859ba83e1a610b9fd0 + +ACPI_ALLOCATE_ZEROED() may fail, elements might be NULL and will cause +NULL pointer dereference later. + +Link: https://github.com/acpica/acpica/commit/4d4547cf +Signed-off-by: Pei Xiao +Link: https://patch.msgid.link/tencent_4A21A2865B8B0A0D12CAEBEB84708EDDB505@qq.com +[ rjw: Subject and changelog edits ] +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/acpica/dbconvert.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/acpi/acpica/dbconvert.c b/drivers/acpi/acpica/dbconvert.c +index 2b84ac093698a..8dbab69320499 100644 +--- a/drivers/acpi/acpica/dbconvert.c ++++ b/drivers/acpi/acpica/dbconvert.c +@@ -174,6 +174,8 @@ acpi_status acpi_db_convert_to_package(char *string, union acpi_object *object) + elements = + ACPI_ALLOCATE_ZEROED(DB_DEFAULT_PKG_ELEMENTS * + sizeof(union acpi_object)); ++ if (!elements) ++ return (AE_NO_MEMORY); + + this = string; + for (i = 0; i < (DB_DEFAULT_PKG_ELEMENTS - 1); i++) { +-- +2.43.0 + diff --git a/queue-6.10/acpica-fix-memory-leak-if-acpi_ps_get_next_field-fai.patch b/queue-6.10/acpica-fix-memory-leak-if-acpi_ps_get_next_field-fai.patch new file mode 100644 index 00000000000..f5e64663777 --- /dev/null +++ b/queue-6.10/acpica-fix-memory-leak-if-acpi_ps_get_next_field-fai.patch @@ -0,0 +1,90 @@ +From c0c6bf048a70b21942f7ec237237ebe80fdfe5ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 14 Apr 2024 21:50:33 +0200 +Subject: ACPICA: Fix memory leak if acpi_ps_get_next_field() fails + +From: Armin Wolf + +[ Upstream commit e6169a8ffee8a012badd8c703716e761ce851b15 ] + +ACPICA commit 1280045754264841b119a5ede96cd005bc09b5a7 + +If acpi_ps_get_next_field() fails, the previously created field list +needs to be properly disposed before returning the status code. + +Link: https://github.com/acpica/acpica/commit/12800457 +Signed-off-by: Armin Wolf +[ rjw: Rename local variable to avoid compiler confusion ] +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/acpica/psargs.c | 39 ++++++++++++++++++++++++++++++++++++ + 1 file changed, 39 insertions(+) + +diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c +index 7debfd5ce0d86..28582adfc0aca 100644 +--- a/drivers/acpi/acpica/psargs.c ++++ b/drivers/acpi/acpica/psargs.c +@@ -25,6 +25,8 @@ acpi_ps_get_next_package_length(struct acpi_parse_state *parser_state); + static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state + *parser_state); + ++static void acpi_ps_free_field_list(union acpi_parse_object *start); ++ + /******************************************************************************* + * + * FUNCTION: acpi_ps_get_next_package_length +@@ -683,6 +685,39 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state + return_PTR(field); + } + ++/******************************************************************************* ++ * ++ * FUNCTION: acpi_ps_free_field_list ++ * ++ * PARAMETERS: start - First Op in field list ++ * ++ * RETURN: None. ++ * ++ * DESCRIPTION: Free all Op objects inside a field list. ++ * ++ ******************************************************************************/ ++ ++static void acpi_ps_free_field_list(union acpi_parse_object *start) ++{ ++ union acpi_parse_object *cur = start; ++ union acpi_parse_object *next; ++ union acpi_parse_object *arg; ++ ++ while (cur) { ++ next = cur->common.next; ++ ++ /* AML_INT_CONNECTION_OP can have a single argument */ ++ ++ arg = acpi_ps_get_arg(cur, 0); ++ if (arg) { ++ acpi_ps_free_op(arg); ++ } ++ ++ acpi_ps_free_op(cur); ++ cur = next; ++ } ++} ++ + /******************************************************************************* + * + * FUNCTION: acpi_ps_get_next_arg +@@ -751,6 +786,10 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, + while (parser_state->aml < parser_state->pkg_end) { + field = acpi_ps_get_next_field(parser_state); + if (!field) { ++ if (arg) { ++ acpi_ps_free_field_list(arg); ++ } ++ + return_ACPI_STATUS(AE_NO_MEMORY); + } + +-- +2.43.0 + diff --git a/queue-6.10/acpica-fix-memory-leak-if-acpi_ps_get_next_namepath-.patch b/queue-6.10/acpica-fix-memory-leak-if-acpi_ps_get_next_namepath-.patch new file mode 100644 index 00000000000..df8f5e65a8e --- /dev/null +++ b/queue-6.10/acpica-fix-memory-leak-if-acpi_ps_get_next_namepath-.patch @@ -0,0 +1,55 @@ +From 6c76b2d767d19ba6b7644b9c63968e96feba1472 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Apr 2024 20:50:11 +0200 +Subject: ACPICA: Fix memory leak if acpi_ps_get_next_namepath() fails + +From: Armin Wolf + +[ Upstream commit 5accb265f7a1b23e52b0ec42313d1e12895552f4 ] + +ACPICA commit 2802af722bbde7bf1a7ac68df68e179e2555d361 + +If acpi_ps_get_next_namepath() fails, the previously allocated +union acpi_parse_object needs to be freed before returning the +status code. + +The issue was first being reported on the Linux ACPI mailing list: + +Link: https://lore.kernel.org/linux-acpi/56f94776-484f-48c0-8855-dba8e6a7793b@yandex.ru/T/ +Link: https://github.com/acpica/acpica/commit/2802af72 +Signed-off-by: Armin Wolf +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/acpica/psargs.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c +index 422c074ed2897..7debfd5ce0d86 100644 +--- a/drivers/acpi/acpica/psargs.c ++++ b/drivers/acpi/acpica/psargs.c +@@ -820,6 +820,10 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, + acpi_ps_get_next_namepath(walk_state, parser_state, + arg, + ACPI_NOT_METHOD_CALL); ++ if (ACPI_FAILURE(status)) { ++ acpi_ps_free_op(arg); ++ return_ACPI_STATUS(status); ++ } + } else { + /* Single complex argument, nothing returned */ + +@@ -854,6 +858,10 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, + acpi_ps_get_next_namepath(walk_state, parser_state, + arg, + ACPI_POSSIBLE_METHOD_CALL); ++ if (ACPI_FAILURE(status)) { ++ acpi_ps_free_op(arg); ++ return_ACPI_STATUS(status); ++ } + + if (arg->common.aml_opcode == AML_INT_METHODCALL_OP) { + +-- +2.43.0 + diff --git a/queue-6.10/acpica-iasl-handle-empty-connection_node.patch b/queue-6.10/acpica-iasl-handle-empty-connection_node.patch new file mode 100644 index 00000000000..493ca7a42e6 --- /dev/null +++ b/queue-6.10/acpica-iasl-handle-empty-connection_node.patch @@ -0,0 +1,36 @@ +From 8d31bfb08347557b6f35c81e0321ac81209bc1f9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 11 Aug 2024 23:33:44 +0200 +Subject: ACPICA: iasl: handle empty connection_node + +From: Aleksandrs Vinarskis + +[ Upstream commit a0a2459b79414584af6c46dd8c6f866d8f1aa421 ] + +ACPICA commit 6c551e2c9487067d4b085333e7fe97e965a11625 + +Link: https://github.com/acpica/acpica/commit/6c551e2c +Signed-off-by: Aleksandrs Vinarskis +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/acpica/exprep.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/acpi/acpica/exprep.c b/drivers/acpi/acpica/exprep.c +index 08196fa17080e..82b1fa2d201fe 100644 +--- a/drivers/acpi/acpica/exprep.c ++++ b/drivers/acpi/acpica/exprep.c +@@ -437,6 +437,9 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info) + + if (info->connection_node) { + second_desc = info->connection_node->object; ++ if (second_desc == NULL) { ++ break; ++ } + if (!(second_desc->common.flags & AOPOBJ_DATA_VALID)) { + status = + acpi_ds_get_buffer_arguments(second_desc); +-- +2.43.0 + diff --git a/queue-6.10/alsa-asihpi-fix-potential-oob-array-access.patch b/queue-6.10/alsa-asihpi-fix-potential-oob-array-access.patch new file mode 100644 index 00000000000..3bfbe49d347 --- /dev/null +++ b/queue-6.10/alsa-asihpi-fix-potential-oob-array-access.patch @@ -0,0 +1,39 @@ +From 6e53134a0222a3ea9a9f849421ac8bf6c2f65abe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Aug 2024 11:14:42 +0200 +Subject: ALSA: asihpi: Fix potential OOB array access + +From: Takashi Iwai + +[ Upstream commit 7b986c7430a6bb68d523dac7bfc74cbd5b44ef96 ] + +ASIHPI driver stores some values in the static array upon a response +from the driver, and its index depends on the firmware. We shouldn't +trust it blindly. + +This patch adds a sanity check of the array index to fit in the array +size. + +Link: https://patch.msgid.link/20240808091454.30846-1-tiwai@suse.de +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/pci/asihpi/hpimsgx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/pci/asihpi/hpimsgx.c b/sound/pci/asihpi/hpimsgx.c +index d0caef2994818..b68e6bfbbfbab 100644 +--- a/sound/pci/asihpi/hpimsgx.c ++++ b/sound/pci/asihpi/hpimsgx.c +@@ -708,7 +708,7 @@ static u16 HPIMSGX__init(struct hpi_message *phm, + phr->error = HPI_ERROR_PROCESSING_MESSAGE; + return phr->error; + } +- if (hr.error == 0) { ++ if (hr.error == 0 && hr.u.s.adapter_index < HPI_MAX_ADAPTERS) { + /* the adapter was created successfully + save the mapping for future use */ + hpi_entry_points[hr.u.s.adapter_index] = entry_point_func; +-- +2.43.0 + diff --git a/queue-6.10/alsa-control-take-power_ref-lock-primarily.patch b/queue-6.10/alsa-control-take-power_ref-lock-primarily.patch new file mode 100644 index 00000000000..43236338cf9 --- /dev/null +++ b/queue-6.10/alsa-control-take-power_ref-lock-primarily.patch @@ -0,0 +1,182 @@ +From 4331b02c39d70d8410d61ee148e9343fe8017cc9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Jul 2024 18:06:58 +0200 +Subject: ALSA: control: Take power_ref lock primarily + +From: Takashi Iwai + +[ 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 +Signed-off-by: Sasha Levin +--- + sound/core/control.c | 54 ++++++++++++++++++++++++++++---------------- + 1 file changed, 34 insertions(+), 20 deletions(-) + +diff --git a/sound/core/control.c b/sound/core/control.c +index 1dd2337e29300..2151f19b432fd 100644 +--- a/sound/core/control.c ++++ b/sound/core/control.c +@@ -1164,9 +1164,7 @@ static int __snd_ctl_elem_info(struct snd_card *card, + #ifdef CONFIG_SND_DEBUG + info->access = 0; + #endif +- result = snd_power_ref_and_wait(card); +- if (!result) +- result = kctl->info(kctl, info); ++ result = kctl->info(kctl, info); + snd_power_unref(card); + if (result >= 0) { + snd_BUG_ON(info->access); +@@ -1205,12 +1203,17 @@ static int snd_ctl_elem_info(struct snd_ctl_file *ctl, + static int snd_ctl_elem_info_user(struct snd_ctl_file *ctl, + struct snd_ctl_elem_info __user *_info) + { ++ struct snd_card *card = ctl->card; + struct snd_ctl_elem_info info; + int result; + + if (copy_from_user(&info, _info, sizeof(info))) + return -EFAULT; ++ result = snd_power_ref_and_wait(card); ++ if (result) ++ return result; + result = snd_ctl_elem_info(ctl, &info); ++ snd_power_unref(card); + if (result < 0) + return result; + /* drop internal access flags */ +@@ -1254,10 +1257,7 @@ static int snd_ctl_elem_read(struct snd_card *card, + + if (!snd_ctl_skip_validation(&info)) + fill_remaining_elem_value(control, &info, pattern); +- ret = snd_power_ref_and_wait(card); +- if (!ret) +- ret = kctl->get(kctl, control); +- snd_power_unref(card); ++ ret = kctl->get(kctl, control); + if (ret < 0) + return ret; + if (!snd_ctl_skip_validation(&info) && +@@ -1282,7 +1282,11 @@ static int snd_ctl_elem_read_user(struct snd_card *card, + if (IS_ERR(control)) + return PTR_ERR(no_free_ptr(control)); + ++ result = snd_power_ref_and_wait(card); ++ if (result) ++ return result; + result = snd_ctl_elem_read(card, control); ++ snd_power_unref(card); + if (result < 0) + return result; + +@@ -1297,7 +1301,7 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, + struct snd_kcontrol *kctl; + struct snd_kcontrol_volatile *vd; + unsigned int index_offset; +- int result; ++ int result = 0; + + down_write(&card->controls_rwsem); + kctl = snd_ctl_find_id_locked(card, &control->id); +@@ -1315,9 +1319,8 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, + } + + snd_ctl_build_ioff(&control->id, kctl, index_offset); +- result = snd_power_ref_and_wait(card); + /* validate input values */ +- if (IS_ENABLED(CONFIG_SND_CTL_INPUT_VALIDATION) && !result) { ++ if (IS_ENABLED(CONFIG_SND_CTL_INPUT_VALIDATION)) { + struct snd_ctl_elem_info info; + + memset(&info, 0, sizeof(info)); +@@ -1329,7 +1332,6 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, + } + if (!result) + result = kctl->put(kctl, control); +- snd_power_unref(card); + if (result < 0) { + up_write(&card->controls_rwsem); + return result; +@@ -1358,7 +1360,11 @@ static int snd_ctl_elem_write_user(struct snd_ctl_file *file, + return PTR_ERR(no_free_ptr(control)); + + card = file->card; ++ result = snd_power_ref_and_wait(card); ++ if (result < 0) ++ return result; + result = snd_ctl_elem_write(card, file, control); ++ snd_power_unref(card); + if (result < 0) + return result; + +@@ -1827,7 +1833,7 @@ static int call_tlv_handler(struct snd_ctl_file *file, int op_flag, + {SNDRV_CTL_TLV_OP_CMD, SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND}, + }; + struct snd_kcontrol_volatile *vd = &kctl->vd[snd_ctl_get_ioff(kctl, id)]; +- int i, ret; ++ int i; + + /* Check support of the request for this element. */ + for (i = 0; i < ARRAY_SIZE(pairs); ++i) { +@@ -1845,11 +1851,7 @@ static int call_tlv_handler(struct snd_ctl_file *file, int op_flag, + vd->owner != NULL && vd->owner != file) + return -EPERM; + +- ret = snd_power_ref_and_wait(file->card); +- if (!ret) +- ret = kctl->tlv.c(kctl, op_flag, size, buf); +- snd_power_unref(file->card); +- return ret; ++ return kctl->tlv.c(kctl, op_flag, size, buf); + } + + static int read_tlv_buf(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id, +@@ -1962,16 +1964,28 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg + case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS: + return snd_ctl_subscribe_events(ctl, ip); + case SNDRV_CTL_IOCTL_TLV_READ: +- scoped_guard(rwsem_read, &ctl->card->controls_rwsem) ++ err = snd_power_ref_and_wait(card); ++ if (err < 0) ++ return err; ++ scoped_guard(rwsem_read, &card->controls_rwsem) + err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_READ); ++ snd_power_unref(card); + return err; + case SNDRV_CTL_IOCTL_TLV_WRITE: +- scoped_guard(rwsem_write, &ctl->card->controls_rwsem) ++ err = snd_power_ref_and_wait(card); ++ if (err < 0) ++ return err; ++ scoped_guard(rwsem_write, &card->controls_rwsem) + err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_WRITE); ++ snd_power_unref(card); + return err; + case SNDRV_CTL_IOCTL_TLV_COMMAND: +- scoped_guard(rwsem_write, &ctl->card->controls_rwsem) ++ err = snd_power_ref_and_wait(card); ++ if (err < 0) ++ return err; ++ scoped_guard(rwsem_write, &card->controls_rwsem) + err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_CMD); ++ snd_power_unref(card); + return err; + case SNDRV_CTL_IOCTL_POWER: + return -ENOPROTOOPT; +-- +2.43.0 + diff --git a/queue-6.10/alsa-hdsp-break-infinite-midi-input-flush-loop.patch b/queue-6.10/alsa-hdsp-break-infinite-midi-input-flush-loop.patch new file mode 100644 index 00000000000..2d3eec5633a --- /dev/null +++ b/queue-6.10/alsa-hdsp-break-infinite-midi-input-flush-loop.patch @@ -0,0 +1,60 @@ +From 59c6dfe6c79473990fab82e1f9fd34e57548d407 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Aug 2024 11:15:12 +0200 +Subject: ALSA: hdsp: Break infinite MIDI input flush loop + +From: Takashi Iwai + +[ Upstream commit c01f3815453e2d5f699ccd8c8c1f93a5b8669e59 ] + +The current MIDI input flush on HDSP and HDSPM drivers relies on the +hardware reporting the right value. If the hardware doesn't give the +proper value but returns -1, it may be stuck at an infinite loop. + +Add a counter and break if the loop is unexpectedly too long. + +Link: https://patch.msgid.link/20240808091513.31380-1-tiwai@suse.de +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/pci/rme9652/hdsp.c | 6 ++++-- + sound/pci/rme9652/hdspm.c | 6 ++++-- + 2 files changed, 8 insertions(+), 4 deletions(-) + +diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c +index e7d1b43471a29..713ca262a0e97 100644 +--- a/sound/pci/rme9652/hdsp.c ++++ b/sound/pci/rme9652/hdsp.c +@@ -1298,8 +1298,10 @@ static int snd_hdsp_midi_output_possible (struct hdsp *hdsp, int id) + + static void snd_hdsp_flush_midi_input (struct hdsp *hdsp, int id) + { +- while (snd_hdsp_midi_input_available (hdsp, id)) +- snd_hdsp_midi_read_byte (hdsp, id); ++ int count = 256; ++ ++ while (snd_hdsp_midi_input_available(hdsp, id) && --count) ++ snd_hdsp_midi_read_byte(hdsp, id); + } + + static int snd_hdsp_midi_output_write (struct hdsp_midi *hmidi) +diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c +index 267c7848974ae..74215f57f4fc9 100644 +--- a/sound/pci/rme9652/hdspm.c ++++ b/sound/pci/rme9652/hdspm.c +@@ -1838,8 +1838,10 @@ static inline int snd_hdspm_midi_output_possible (struct hdspm *hdspm, int id) + + static void snd_hdspm_flush_midi_input(struct hdspm *hdspm, int id) + { +- while (snd_hdspm_midi_input_available (hdspm, id)) +- snd_hdspm_midi_read_byte (hdspm, id); ++ int count = 256; ++ ++ while (snd_hdspm_midi_input_available(hdspm, id) && --count) ++ snd_hdspm_midi_read_byte(hdspm, id); + } + + static int snd_hdspm_midi_output_write (struct hdspm_midi *hmidi) +-- +2.43.0 + diff --git a/queue-6.10/alsa-usb-audio-add-input-value-sanity-checks-for-sta.patch b/queue-6.10/alsa-usb-audio-add-input-value-sanity-checks-for-sta.patch new file mode 100644 index 00000000000..deba322db24 --- /dev/null +++ b/queue-6.10/alsa-usb-audio-add-input-value-sanity-checks-for-sta.patch @@ -0,0 +1,140 @@ +From 183c49ca6224fed8501ca0589452922d15c7520b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Aug 2024 14:46:50 +0200 +Subject: ALSA: usb-audio: Add input value sanity checks for standard types + +From: Takashi Iwai + +[ Upstream commit 901e85677ec0bb9a69fb9eab1feafe0c4eb7d07e ] + +For an invalid input value that is out of the given range, currently +USB-audio driver corrects the value silently and accepts without +errors. This is no wrong behavior, per se, but the recent kselftest +rather wants to have an error in such a case, hence a different +behavior is expected now. + +This patch adds a sanity check at each control put for the standard +mixer types and returns an error if an invalid value is given. + +Note that this covers only the standard mixer types. The mixer quirks +that have own control callbacks would need different coverage. + +Link: https://patch.msgid.link/20240806124651.28203-1-tiwai@suse.de +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/mixer.c | 35 +++++++++++++++++++++++++++-------- + sound/usb/mixer.h | 1 + + 2 files changed, 28 insertions(+), 8 deletions(-) + +diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c +index 8cc2d4937f340..197fd07e69edd 100644 +--- a/sound/usb/mixer.c ++++ b/sound/usb/mixer.c +@@ -1377,6 +1377,19 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval, + + #define get_min_max(cval, def) get_min_max_with_quirks(cval, def, NULL) + ++/* get the max value advertised via control API */ ++static int get_max_exposed(struct usb_mixer_elem_info *cval) ++{ ++ if (!cval->max_exposed) { ++ if (cval->res) ++ cval->max_exposed = ++ DIV_ROUND_UP(cval->max - cval->min, cval->res); ++ else ++ cval->max_exposed = cval->max - cval->min; ++ } ++ return cval->max_exposed; ++} ++ + /* get a feature/mixer unit info */ + static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +@@ -1389,11 +1402,8 @@ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol, + else + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = cval->channels; +- if (cval->val_type == USB_MIXER_BOOLEAN || +- cval->val_type == USB_MIXER_INV_BOOLEAN) { +- uinfo->value.integer.min = 0; +- uinfo->value.integer.max = 1; +- } else { ++ if (cval->val_type != USB_MIXER_BOOLEAN && ++ cval->val_type != USB_MIXER_INV_BOOLEAN) { + if (!cval->initialized) { + get_min_max_with_quirks(cval, 0, kcontrol); + if (cval->initialized && cval->dBmin >= cval->dBmax) { +@@ -1405,10 +1415,10 @@ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol, + &kcontrol->id); + } + } +- uinfo->value.integer.min = 0; +- uinfo->value.integer.max = +- DIV_ROUND_UP(cval->max - cval->min, cval->res); + } ++ ++ uinfo->value.integer.min = 0; ++ uinfo->value.integer.max = get_max_exposed(cval); + return 0; + } + +@@ -1449,6 +1459,7 @@ static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) + { + struct usb_mixer_elem_info *cval = kcontrol->private_data; ++ int max_val = get_max_exposed(cval); + int c, cnt, val, oval, err; + int changed = 0; + +@@ -1461,6 +1472,8 @@ static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol, + if (err < 0) + return filter_error(cval, err); + val = ucontrol->value.integer.value[cnt]; ++ if (val < 0 || val > max_val) ++ return -EINVAL; + val = get_abs_value(cval, val); + if (oval != val) { + snd_usb_set_cur_mix_value(cval, c + 1, cnt, val); +@@ -1474,6 +1487,8 @@ static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol, + if (err < 0) + return filter_error(cval, err); + val = ucontrol->value.integer.value[0]; ++ if (val < 0 || val > max_val) ++ return -EINVAL; + val = get_abs_value(cval, val); + if (val != oval) { + snd_usb_set_cur_mix_value(cval, 0, 0, val); +@@ -2337,6 +2352,8 @@ static int mixer_ctl_procunit_put(struct snd_kcontrol *kcontrol, + if (err < 0) + return filter_error(cval, err); + val = ucontrol->value.integer.value[0]; ++ if (val < 0 || val > get_max_exposed(cval)) ++ return -EINVAL; + val = get_abs_value(cval, val); + if (val != oval) { + set_cur_ctl_value(cval, cval->control << 8, val); +@@ -2699,6 +2716,8 @@ static int mixer_ctl_selector_put(struct snd_kcontrol *kcontrol, + if (err < 0) + return filter_error(cval, err); + val = ucontrol->value.enumerated.item[0]; ++ if (val < 0 || val >= cval->max) /* here cval->max = # elements */ ++ return -EINVAL; + val = get_abs_value(cval, val); + if (val != oval) { + set_cur_ctl_value(cval, cval->control << 8, val); +diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h +index d43895c1ae5c6..167fbfcf01ace 100644 +--- a/sound/usb/mixer.h ++++ b/sound/usb/mixer.h +@@ -88,6 +88,7 @@ struct usb_mixer_elem_info { + int channels; + int val_type; + int min, max, res; ++ int max_exposed; /* control API exposes the value in 0..max_exposed */ + int dBmin, dBmax; + int cached; + int cache_val[MAX_CHANNELS]; +-- +2.43.0 + diff --git a/queue-6.10/alsa-usb-audio-add-logitech-audio-profile-quirk.patch b/queue-6.10/alsa-usb-audio-add-logitech-audio-profile-quirk.patch new file mode 100644 index 00000000000..8ad6c532123 --- /dev/null +++ b/queue-6.10/alsa-usb-audio-add-logitech-audio-profile-quirk.patch @@ -0,0 +1,40 @@ +From bfdd49be2ca1e406f156915b8f69438a78b96362 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Sep 2024 15:26:28 +0000 +Subject: ALSA: usb-audio: Add logitech Audio profile quirk + +From: Joshua Pius + +[ Upstream commit a51c925c11d7b855167e64b63eb4378e5adfc11d ] + +Specify shortnames for the following Logitech Devices: Rally bar, Rally +bar mini, Tap, MeetUp and Huddle. + +Signed-off-by: Joshua Pius +Link: https://patch.msgid.link/20240912152635.1859737-1-joshuapius@google.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/card.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/sound/usb/card.c b/sound/usb/card.c +index 778de9244f1e7..9c411b82a218d 100644 +--- a/sound/usb/card.c ++++ b/sound/usb/card.c +@@ -384,6 +384,12 @@ static const struct usb_audio_device_name usb_audio_names[] = { + /* Creative/Toshiba Multimedia Center SB-0500 */ + DEVICE_NAME(0x041e, 0x3048, "Toshiba", "SB-0500"), + ++ /* Logitech Audio Devices */ ++ DEVICE_NAME(0x046d, 0x0867, "Logitech, Inc.", "Logi-MeetUp"), ++ DEVICE_NAME(0x046d, 0x0874, "Logitech, Inc.", "Logi-Tap-Audio"), ++ DEVICE_NAME(0x046d, 0x087c, "Logitech, Inc.", "Logi-Huddle"), ++ DEVICE_NAME(0x046d, 0x0898, "Logitech, Inc.", "Logi-RB-Audio"), ++ DEVICE_NAME(0x046d, 0x08d2, "Logitech, Inc.", "Logi-RBM-Audio"), + DEVICE_NAME(0x046d, 0x0990, "Logitech, Inc.", "QuickCam Pro 9000"), + + DEVICE_NAME(0x05e1, 0x0408, "Syntek", "STK1160"), +-- +2.43.0 + diff --git a/queue-6.10/alsa-usb-audio-add-mixer-quirk-for-rme-digiface-usb.patch b/queue-6.10/alsa-usb-audio-add-mixer-quirk-for-rme-digiface-usb.patch new file mode 100644 index 00000000000..08d34f8331e --- /dev/null +++ b/queue-6.10/alsa-usb-audio-add-mixer-quirk-for-rme-digiface-usb.patch @@ -0,0 +1,482 @@ +From de5b52dd026d18af99bc8be132e464dba5c4a716 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Sep 2024 19:52:30 +0900 +Subject: ALSA: usb-audio: Add mixer quirk for RME Digiface USB + +From: Asahi Lina + +[ 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 +Link: https://patch.msgid.link/20240903-rme-digiface-v2-2-71b06c912e97@asahilina.net +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + 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 + #include + #include + #include +@@ -2926,6 +2927,415 @@ static int snd_bbfpro_controls_create(struct usb_mixer_interface *mixer) + return 0; + } + ++/* ++ * RME Digiface USB ++ */ ++ ++#define RME_DIGIFACE_READ_STATUS 17 ++#define RME_DIGIFACE_STATUS_REG0L 0 ++#define RME_DIGIFACE_STATUS_REG0H 1 ++#define RME_DIGIFACE_STATUS_REG1L 2 ++#define RME_DIGIFACE_STATUS_REG1H 3 ++#define RME_DIGIFACE_STATUS_REG2L 4 ++#define RME_DIGIFACE_STATUS_REG2H 5 ++#define RME_DIGIFACE_STATUS_REG3L 6 ++#define RME_DIGIFACE_STATUS_REG3H 7 ++ ++#define RME_DIGIFACE_CTL_REG1 16 ++#define RME_DIGIFACE_CTL_REG2 18 ++ ++/* Reg is overloaded, 0-7 for status halfwords or 16 or 18 for control registers */ ++#define RME_DIGIFACE_REGISTER(reg, mask) (((reg) << 16) | (mask)) ++#define RME_DIGIFACE_INVERT BIT(31) ++ ++/* Nonconst helpers */ ++#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) ++#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) ++ ++static int snd_rme_digiface_write_reg(struct snd_kcontrol *kcontrol, int item, u16 mask, u16 val) ++{ ++ struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); ++ struct snd_usb_audio *chip = list->mixer->chip; ++ struct usb_device *dev = chip->dev; ++ int err; ++ ++ err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), ++ item, ++ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, ++ val, mask, NULL, 0); ++ if (err < 0) ++ dev_err(&dev->dev, ++ "unable to issue control set request %d (ret = %d)", ++ item, err); ++ return err; ++} ++ ++static int snd_rme_digiface_read_status(struct snd_kcontrol *kcontrol, u32 status[4]) ++{ ++ struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); ++ struct snd_usb_audio *chip = list->mixer->chip; ++ struct usb_device *dev = chip->dev; ++ __le32 buf[4]; ++ int err; ++ ++ err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), ++ RME_DIGIFACE_READ_STATUS, ++ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, ++ 0, 0, ++ buf, sizeof(buf)); ++ if (err < 0) { ++ dev_err(&dev->dev, ++ "unable to issue status read request (ret = %d)", ++ err); ++ } else { ++ for (int i = 0; i < ARRAY_SIZE(buf); i++) ++ status[i] = le32_to_cpu(buf[i]); ++ } ++ return err; ++} ++ ++static int snd_rme_digiface_get_status_val(struct snd_kcontrol *kcontrol) ++{ ++ int err; ++ u32 status[4]; ++ bool invert = kcontrol->private_value & RME_DIGIFACE_INVERT; ++ u8 reg = (kcontrol->private_value >> 16) & 0xff; ++ u16 mask = kcontrol->private_value & 0xffff; ++ u16 val; ++ ++ err = snd_rme_digiface_read_status(kcontrol, status); ++ if (err < 0) ++ return err; ++ ++ switch (reg) { ++ /* Status register halfwords */ ++ case RME_DIGIFACE_STATUS_REG0L ... RME_DIGIFACE_STATUS_REG3H: ++ break; ++ case RME_DIGIFACE_CTL_REG1: /* Control register 1, present in halfword 3L */ ++ reg = RME_DIGIFACE_STATUS_REG3L; ++ break; ++ case RME_DIGIFACE_CTL_REG2: /* Control register 2, present in halfword 3H */ ++ reg = RME_DIGIFACE_STATUS_REG3H; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if (reg & 1) ++ val = status[reg >> 1] >> 16; ++ else ++ val = status[reg >> 1] & 0xffff; ++ ++ if (invert) ++ val ^= mask; ++ ++ return field_get(mask, val); ++} ++ ++static int snd_rme_digiface_rate_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ int freq = snd_rme_digiface_get_status_val(kcontrol); ++ ++ if (freq < 0) ++ return freq; ++ if (freq >= ARRAY_SIZE(snd_rme_rate_table)) ++ return -EIO; ++ ++ ucontrol->value.integer.value[0] = snd_rme_rate_table[freq]; ++ return 0; ++} ++ ++static int snd_rme_digiface_enum_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ int val = snd_rme_digiface_get_status_val(kcontrol); ++ ++ if (val < 0) ++ return val; ++ ++ ucontrol->value.enumerated.item[0] = val; ++ return 0; ++} ++ ++static int snd_rme_digiface_enum_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ bool invert = kcontrol->private_value & RME_DIGIFACE_INVERT; ++ u8 reg = (kcontrol->private_value >> 16) & 0xff; ++ u16 mask = kcontrol->private_value & 0xffff; ++ u16 val = field_prep(mask, ucontrol->value.enumerated.item[0]); ++ ++ if (invert) ++ val ^= mask; ++ ++ return snd_rme_digiface_write_reg(kcontrol, reg, mask, val); ++} ++ ++static int snd_rme_digiface_current_sync_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ int ret = snd_rme_digiface_enum_get(kcontrol, ucontrol); ++ ++ /* 7 means internal for current sync */ ++ if (ucontrol->value.enumerated.item[0] == 7) ++ ucontrol->value.enumerated.item[0] = 0; ++ ++ return ret; ++} ++ ++static int snd_rme_digiface_sync_state_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ u32 status[4]; ++ int err; ++ bool valid, sync; ++ ++ err = snd_rme_digiface_read_status(kcontrol, status); ++ if (err < 0) ++ return err; ++ ++ valid = status[0] & BIT(kcontrol->private_value); ++ sync = status[0] & BIT(5 + kcontrol->private_value); ++ ++ if (!valid) ++ ucontrol->value.enumerated.item[0] = SND_RME_CLOCK_NOLOCK; ++ else if (!sync) ++ ucontrol->value.enumerated.item[0] = SND_RME_CLOCK_LOCK; ++ else ++ ucontrol->value.enumerated.item[0] = SND_RME_CLOCK_SYNC; ++ return 0; ++} ++ ++ ++static int snd_rme_digiface_format_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ static const char *const format[] = { ++ "ADAT", "S/PDIF" ++ }; ++ ++ return snd_ctl_enum_info(uinfo, 1, ++ ARRAY_SIZE(format), format); ++} ++ ++ ++static int snd_rme_digiface_sync_source_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ static const char *const sync_sources[] = { ++ "Internal", "Input 1", "Input 2", "Input 3", "Input 4" ++ }; ++ ++ return snd_ctl_enum_info(uinfo, 1, ++ ARRAY_SIZE(sync_sources), sync_sources); ++} ++ ++static int snd_rme_digiface_rate_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; ++ uinfo->count = 1; ++ uinfo->value.integer.min = 0; ++ uinfo->value.integer.max = 200000; ++ uinfo->value.integer.step = 0; ++ return 0; ++} ++ ++static const struct snd_kcontrol_new snd_rme_digiface_controls[] = { ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Input 1 Sync", ++ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, ++ .info = snd_rme_sync_state_info, ++ .get = snd_rme_digiface_sync_state_get, ++ .private_value = 0, ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Input 1 Format", ++ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, ++ .info = snd_rme_digiface_format_info, ++ .get = snd_rme_digiface_enum_get, ++ .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG0H, BIT(0)) | ++ RME_DIGIFACE_INVERT, ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Input 1 Rate", ++ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, ++ .info = snd_rme_digiface_rate_info, ++ .get = snd_rme_digiface_rate_get, ++ .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG1L, GENMASK(3, 0)), ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Input 2 Sync", ++ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, ++ .info = snd_rme_sync_state_info, ++ .get = snd_rme_digiface_sync_state_get, ++ .private_value = 1, ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Input 2 Format", ++ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, ++ .info = snd_rme_digiface_format_info, ++ .get = snd_rme_digiface_enum_get, ++ .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG0L, BIT(13)) | ++ RME_DIGIFACE_INVERT, ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Input 2 Rate", ++ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, ++ .info = snd_rme_digiface_rate_info, ++ .get = snd_rme_digiface_rate_get, ++ .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG1L, GENMASK(7, 4)), ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Input 3 Sync", ++ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, ++ .info = snd_rme_sync_state_info, ++ .get = snd_rme_digiface_sync_state_get, ++ .private_value = 2, ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Input 3 Format", ++ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, ++ .info = snd_rme_digiface_format_info, ++ .get = snd_rme_digiface_enum_get, ++ .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG0L, BIT(14)) | ++ RME_DIGIFACE_INVERT, ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Input 3 Rate", ++ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, ++ .info = snd_rme_digiface_rate_info, ++ .get = snd_rme_digiface_rate_get, ++ .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG1L, GENMASK(11, 8)), ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Input 4 Sync", ++ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, ++ .info = snd_rme_sync_state_info, ++ .get = snd_rme_digiface_sync_state_get, ++ .private_value = 3, ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Input 4 Format", ++ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, ++ .info = snd_rme_digiface_format_info, ++ .get = snd_rme_digiface_enum_get, ++ .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG0L, GENMASK(15, 12)) | ++ RME_DIGIFACE_INVERT, ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Input 4 Rate", ++ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, ++ .info = snd_rme_digiface_rate_info, ++ .get = snd_rme_digiface_rate_get, ++ .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG1L, GENMASK(3, 0)), ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Output 1 Format", ++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, ++ .info = snd_rme_digiface_format_info, ++ .get = snd_rme_digiface_enum_get, ++ .put = snd_rme_digiface_enum_put, ++ .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_CTL_REG2, BIT(0)), ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Output 2 Format", ++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, ++ .info = snd_rme_digiface_format_info, ++ .get = snd_rme_digiface_enum_get, ++ .put = snd_rme_digiface_enum_put, ++ .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_CTL_REG2, BIT(1)), ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Output 3 Format", ++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, ++ .info = snd_rme_digiface_format_info, ++ .get = snd_rme_digiface_enum_get, ++ .put = snd_rme_digiface_enum_put, ++ .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_CTL_REG2, BIT(3)), ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Output 4 Format", ++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, ++ .info = snd_rme_digiface_format_info, ++ .get = snd_rme_digiface_enum_get, ++ .put = snd_rme_digiface_enum_put, ++ .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_CTL_REG2, BIT(4)), ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Sync Source", ++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, ++ .info = snd_rme_digiface_sync_source_info, ++ .get = snd_rme_digiface_enum_get, ++ .put = snd_rme_digiface_enum_put, ++ .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_CTL_REG1, GENMASK(2, 0)), ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Current Sync Source", ++ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, ++ .info = snd_rme_digiface_sync_source_info, ++ .get = snd_rme_digiface_current_sync_get, ++ .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG0L, GENMASK(12, 10)), ++ }, ++ { ++ /* ++ * This is writeable, but it is only set by the PCM rate. ++ * Mixer apps currently need to drive the mixer using raw USB requests, ++ * so they can also change this that way to configure the rate for ++ * stand-alone operation when the PCM is closed. ++ */ ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "System Rate", ++ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, ++ .info = snd_rme_rate_info, ++ .get = snd_rme_digiface_rate_get, ++ .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_CTL_REG1, GENMASK(6, 3)), ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Current Rate", ++ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, ++ .info = snd_rme_rate_info, ++ .get = snd_rme_digiface_rate_get, ++ .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG1H, GENMASK(7, 4)), ++ } ++}; ++ ++static int snd_rme_digiface_controls_create(struct usb_mixer_interface *mixer) ++{ ++ int err, i; ++ ++ for (i = 0; i < ARRAY_SIZE(snd_rme_digiface_controls); ++i) { ++ err = add_single_ctl_with_resume(mixer, 0, ++ NULL, ++ &snd_rme_digiface_controls[i], ++ NULL); ++ if (err < 0) ++ return err; ++ } ++ ++ return 0; ++} ++ + /* + * Pioneer DJ DJM Mixers + * +@@ -3484,6 +3894,9 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) + case USB_ID(0x2a39, 0x3fb0): /* RME Babyface Pro FS */ + err = snd_bbfpro_controls_create(mixer); + break; ++ case USB_ID(0x2a39, 0x3f8c): /* RME Digiface USB */ ++ err = snd_rme_digiface_controls_create(mixer); ++ break; + case USB_ID(0x2b73, 0x0017): /* Pioneer DJ DJM-250MK2 */ + err = snd_djm_controls_create(mixer, SND_DJM_250MK2_IDX); + break; +diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h +index 631b9ab80f6cd..24c981c9b2405 100644 +--- a/sound/usb/quirks-table.h ++++ b/sound/usb/quirks-table.h +@@ -3620,6 +3620,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * Three modes depending on sample rate band, + * with different channel counts for in/out + */ ++ { QUIRK_DATA_STANDARD_MIXER(0) }, + { + QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S32_LE, +-- +2.43.0 + diff --git a/queue-6.10/alsa-usb-audio-add-quirk-for-rme-digiface-usb.patch b/queue-6.10/alsa-usb-audio-add-quirk-for-rme-digiface-usb.patch new file mode 100644 index 00000000000..5b36fbf95dd --- /dev/null +++ b/queue-6.10/alsa-usb-audio-add-quirk-for-rme-digiface-usb.patch @@ -0,0 +1,299 @@ +From 0143f91d92e77cf7132c159380e7ff756b555bf0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Sep 2024 19:52:29 +0900 +Subject: ALSA: usb-audio: Add quirk for RME Digiface USB + +From: Cyan Nyan + +[ 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 +[Lina: Added 2x/4x sample rate support & boot/format quirks] +Co-developed-by: Asahi Lina +Signed-off-by: Asahi Lina +Link: https://patch.msgid.link/20240903-rme-digiface-v2-1-71b06c912e97@asahilina.net +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/quirks-table.h | 171 ++++++++++++++++++++++++++++++++++++++- + sound/usb/quirks.c | 58 +++++++++++++ + 2 files changed, 228 insertions(+), 1 deletion(-) + +diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h +index 8d22de8bc2a96..631b9ab80f6cd 100644 +--- a/sound/usb/quirks-table.h ++++ b/sound/usb/quirks-table.h +@@ -3604,6 +3604,175 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + } + }, +- ++{ ++ /* Only claim interface 0 */ ++ .match_flags = USB_DEVICE_ID_MATCH_VENDOR | ++ USB_DEVICE_ID_MATCH_PRODUCT | ++ USB_DEVICE_ID_MATCH_INT_CLASS | ++ USB_DEVICE_ID_MATCH_INT_NUMBER, ++ .idVendor = 0x2a39, ++ .idProduct = 0x3f8c, ++ .bInterfaceClass = USB_CLASS_VENDOR_SPEC, ++ .bInterfaceNumber = 0, ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { ++ /* ++ * Three modes depending on sample rate band, ++ * with different channel counts for in/out ++ */ ++ { ++ QUIRK_DATA_AUDIOFORMAT(0) { ++ .formats = SNDRV_PCM_FMTBIT_S32_LE, ++ .channels = 34, // outputs ++ .fmt_bits = 24, ++ .iface = 0, ++ .altsetting = 1, ++ .altset_idx = 1, ++ .endpoint = 0x02, ++ .ep_idx = 1, ++ .ep_attr = USB_ENDPOINT_XFER_ISOC | ++ USB_ENDPOINT_SYNC_ASYNC, ++ .rates = SNDRV_PCM_RATE_32000 | ++ SNDRV_PCM_RATE_44100 | ++ SNDRV_PCM_RATE_48000, ++ .rate_min = 32000, ++ .rate_max = 48000, ++ .nr_rates = 3, ++ .rate_table = (unsigned int[]) { ++ 32000, 44100, 48000, ++ }, ++ .sync_ep = 0x81, ++ .sync_iface = 0, ++ .sync_altsetting = 1, ++ .sync_ep_idx = 0, ++ .implicit_fb = 1, ++ }, ++ }, ++ { ++ QUIRK_DATA_AUDIOFORMAT(0) { ++ .formats = SNDRV_PCM_FMTBIT_S32_LE, ++ .channels = 18, // outputs ++ .fmt_bits = 24, ++ .iface = 0, ++ .altsetting = 1, ++ .altset_idx = 1, ++ .endpoint = 0x02, ++ .ep_idx = 1, ++ .ep_attr = USB_ENDPOINT_XFER_ISOC | ++ USB_ENDPOINT_SYNC_ASYNC, ++ .rates = SNDRV_PCM_RATE_64000 | ++ SNDRV_PCM_RATE_88200 | ++ SNDRV_PCM_RATE_96000, ++ .rate_min = 64000, ++ .rate_max = 96000, ++ .nr_rates = 3, ++ .rate_table = (unsigned int[]) { ++ 64000, 88200, 96000, ++ }, ++ .sync_ep = 0x81, ++ .sync_iface = 0, ++ .sync_altsetting = 1, ++ .sync_ep_idx = 0, ++ .implicit_fb = 1, ++ }, ++ }, ++ { ++ QUIRK_DATA_AUDIOFORMAT(0) { ++ .formats = SNDRV_PCM_FMTBIT_S32_LE, ++ .channels = 10, // outputs ++ .fmt_bits = 24, ++ .iface = 0, ++ .altsetting = 1, ++ .altset_idx = 1, ++ .endpoint = 0x02, ++ .ep_idx = 1, ++ .ep_attr = USB_ENDPOINT_XFER_ISOC | ++ USB_ENDPOINT_SYNC_ASYNC, ++ .rates = SNDRV_PCM_RATE_KNOT | ++ SNDRV_PCM_RATE_176400 | ++ SNDRV_PCM_RATE_192000, ++ .rate_min = 128000, ++ .rate_max = 192000, ++ .nr_rates = 3, ++ .rate_table = (unsigned int[]) { ++ 128000, 176400, 192000, ++ }, ++ .sync_ep = 0x81, ++ .sync_iface = 0, ++ .sync_altsetting = 1, ++ .sync_ep_idx = 0, ++ .implicit_fb = 1, ++ }, ++ }, ++ { ++ QUIRK_DATA_AUDIOFORMAT(0) { ++ .formats = SNDRV_PCM_FMTBIT_S32_LE, ++ .channels = 32, // inputs ++ .fmt_bits = 24, ++ .iface = 0, ++ .altsetting = 1, ++ .altset_idx = 1, ++ .endpoint = 0x81, ++ .ep_attr = USB_ENDPOINT_XFER_ISOC | ++ USB_ENDPOINT_SYNC_ASYNC, ++ .rates = SNDRV_PCM_RATE_32000 | ++ SNDRV_PCM_RATE_44100 | ++ SNDRV_PCM_RATE_48000, ++ .rate_min = 32000, ++ .rate_max = 48000, ++ .nr_rates = 3, ++ .rate_table = (unsigned int[]) { ++ 32000, 44100, 48000, ++ } ++ } ++ }, ++ { ++ QUIRK_DATA_AUDIOFORMAT(0) { ++ .formats = SNDRV_PCM_FMTBIT_S32_LE, ++ .channels = 16, // inputs ++ .fmt_bits = 24, ++ .iface = 0, ++ .altsetting = 1, ++ .altset_idx = 1, ++ .endpoint = 0x81, ++ .ep_attr = USB_ENDPOINT_XFER_ISOC | ++ USB_ENDPOINT_SYNC_ASYNC, ++ .rates = SNDRV_PCM_RATE_64000 | ++ SNDRV_PCM_RATE_88200 | ++ SNDRV_PCM_RATE_96000, ++ .rate_min = 64000, ++ .rate_max = 96000, ++ .nr_rates = 3, ++ .rate_table = (unsigned int[]) { ++ 64000, 88200, 96000, ++ } ++ } ++ }, ++ { ++ QUIRK_DATA_AUDIOFORMAT(0) { ++ .formats = SNDRV_PCM_FMTBIT_S32_LE, ++ .channels = 8, // inputs ++ .fmt_bits = 24, ++ .iface = 0, ++ .altsetting = 1, ++ .altset_idx = 1, ++ .endpoint = 0x81, ++ .ep_attr = USB_ENDPOINT_XFER_ISOC | ++ USB_ENDPOINT_SYNC_ASYNC, ++ .rates = SNDRV_PCM_RATE_KNOT | ++ SNDRV_PCM_RATE_176400 | ++ SNDRV_PCM_RATE_192000, ++ .rate_min = 128000, ++ .rate_max = 192000, ++ .nr_rates = 3, ++ .rate_table = (unsigned int[]) { ++ 128000, 176400, 192000, ++ } ++ } ++ }, ++ QUIRK_COMPOSITE_END ++ } ++ } ++}, + #undef USB_DEVICE_VENDOR_SPEC + #undef USB_AUDIO_DEVICE +diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c +index e7b68c67852e9..73da862a012c6 100644 +--- a/sound/usb/quirks.c ++++ b/sound/usb/quirks.c +@@ -1389,6 +1389,27 @@ static int snd_usb_motu_m_series_boot_quirk(struct usb_device *dev) + return 0; + } + ++static int snd_usb_rme_digiface_boot_quirk(struct usb_device *dev) ++{ ++ /* Disable mixer, internal clock, all outputs ADAT, 48kHz, TMS off */ ++ snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), ++ 16, 0x40, 0x2410, 0x7fff, NULL, 0); ++ snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), ++ 18, 0x40, 0x0104, 0xffff, NULL, 0); ++ ++ /* Disable loopback for all inputs */ ++ for (int ch = 0; ch < 32; ch++) ++ snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), ++ 22, 0x40, 0x400, ch, NULL, 0); ++ ++ /* Unity gain for all outputs */ ++ for (int ch = 0; ch < 34; ch++) ++ snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), ++ 21, 0x40, 0x9000, 0x100 + ch, NULL, 0); ++ ++ return 0; ++} ++ + /* + * Setup quirks + */ +@@ -1616,6 +1637,8 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev, + get_iface_desc(intf->altsetting)->bInterfaceNumber < 3) + return snd_usb_motu_microbookii_boot_quirk(dev); + break; ++ case USB_ID(0x2a39, 0x3f8c): /* RME Digiface USB */ ++ return snd_usb_rme_digiface_boot_quirk(dev); + } + + return 0; +@@ -1771,6 +1794,38 @@ static void mbox3_set_format_quirk(struct snd_usb_substream *subs, + dev_warn(&subs->dev->dev, "MBOX3: Couldn't set the sample rate"); + } + ++static const int rme_digiface_rate_table[] = { ++ 32000, 44100, 48000, 0, ++ 64000, 88200, 96000, 0, ++ 128000, 176400, 192000, 0, ++}; ++ ++static int rme_digiface_set_format_quirk(struct snd_usb_substream *subs) ++{ ++ unsigned int cur_rate = subs->data_endpoint->cur_rate; ++ u16 val; ++ int speed_mode; ++ int id; ++ ++ for (id = 0; id < ARRAY_SIZE(rme_digiface_rate_table); id++) { ++ if (rme_digiface_rate_table[id] == cur_rate) ++ break; ++ } ++ ++ if (id >= ARRAY_SIZE(rme_digiface_rate_table)) ++ return -EINVAL; ++ ++ /* 2, 3, 4 for 1x, 2x, 4x */ ++ speed_mode = (id >> 2) + 2; ++ val = (id << 3) | (speed_mode << 12); ++ ++ /* Set the sample rate */ ++ snd_usb_ctl_msg(subs->stream->chip->dev, ++ usb_sndctrlpipe(subs->stream->chip->dev, 0), ++ 16, 0x40, val, 0x7078, NULL, 0); ++ return 0; ++} ++ + void snd_usb_set_format_quirk(struct snd_usb_substream *subs, + const struct audioformat *fmt) + { +@@ -1795,6 +1850,9 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs, + case USB_ID(0x0dba, 0x5000): + mbox3_set_format_quirk(subs, fmt); /* Digidesign Mbox 3 */ + break; ++ case USB_ID(0x2a39, 0x3f8c): /* RME Digiface USB */ ++ rme_digiface_set_format_quirk(subs); ++ break; + } + } + +-- +2.43.0 + diff --git a/queue-6.10/alsa-usb-audio-define-macros-for-quirk-table-entries.patch b/queue-6.10/alsa-usb-audio-define-macros-for-quirk-table-entries.patch new file mode 100644 index 00000000000..a8f4f53def8 --- /dev/null +++ b/queue-6.10/alsa-usb-audio-define-macros-for-quirk-table-entries.patch @@ -0,0 +1,111 @@ +From f10c85ec1807c1cdb4f9e04fb650aa8f14fbbca0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Aug 2024 15:48:41 +0200 +Subject: ALSA: usb-audio: Define macros for quirk table entries + +From: Takashi Iwai + +[ Upstream commit 0c3ad39b791c2ecf718afcaca30e5ceafa939d5c ] + +Many entries in the USB-audio quirk tables have relatively complex +expressions. For improving the readability, introduce a few macros. +Those are applied in the following patch. + +Link: https://patch.msgid.link/20240814134844.2726-2-tiwai@suse.de +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/quirks-table.h | 77 ++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 77 insertions(+) + +diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h +index aaa6a515d0f8a..e3a25f4f68792 100644 +--- a/sound/usb/quirks-table.h ++++ b/sound/usb/quirks-table.h +@@ -35,6 +35,83 @@ + .bInterfaceClass = USB_CLASS_AUDIO, \ + .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL + ++/* Quirk .driver_info, followed by the definition of the quirk entry; ++ * put like QUIRK_DRIVER_INFO { ... } in each entry of the quirk table ++ */ ++#define QUIRK_DRIVER_INFO \ ++ .driver_info = (unsigned long)&(const struct snd_usb_audio_quirk) ++ ++/* ++ * Macros for quirk data entries ++ */ ++ ++/* Quirk data entry for ignoring the interface */ ++#define QUIRK_DATA_IGNORE(_ifno) \ ++ .ifnum = (_ifno), .type = QUIRK_IGNORE_INTERFACE ++/* Quirk data entry for a standard audio interface */ ++#define QUIRK_DATA_STANDARD_AUDIO(_ifno) \ ++ .ifnum = (_ifno), .type = QUIRK_AUDIO_STANDARD_INTERFACE ++/* Quirk data entry for a standard MIDI interface */ ++#define QUIRK_DATA_STANDARD_MIDI(_ifno) \ ++ .ifnum = (_ifno), .type = QUIRK_MIDI_STANDARD_INTERFACE ++/* Quirk data entry for a standard mixer interface */ ++#define QUIRK_DATA_STANDARD_MIXER(_ifno) \ ++ .ifnum = (_ifno), .type = QUIRK_AUDIO_STANDARD_MIXER ++ ++/* Quirk data entry for Yamaha MIDI */ ++#define QUIRK_DATA_MIDI_YAMAHA(_ifno) \ ++ .ifnum = (_ifno), .type = QUIRK_MIDI_YAMAHA ++/* Quirk data entry for Edirol UAxx */ ++#define QUIRK_DATA_EDIROL_UAXX(_ifno) \ ++ .ifnum = (_ifno), .type = QUIRK_AUDIO_EDIROL_UAXX ++/* Quirk data entry for raw bytes interface */ ++#define QUIRK_DATA_RAW_BYTES(_ifno) \ ++ .ifnum = (_ifno), .type = QUIRK_MIDI_RAW_BYTES ++ ++/* Quirk composite array terminator */ ++#define QUIRK_COMPOSITE_END { .ifnum = -1 } ++ ++/* Quirk data entry for composite quirks; ++ * followed by the quirk array that is terminated with QUIRK_COMPOSITE_END ++ * e.g. QUIRK_DATA_COMPOSITE { { quirk1 }, { quirk2 },..., QUIRK_COMPOSITE_END } ++ */ ++#define QUIRK_DATA_COMPOSITE \ ++ .ifnum = QUIRK_ANY_INTERFACE, \ ++ .type = QUIRK_COMPOSITE, \ ++ .data = &(const struct snd_usb_audio_quirk[]) ++ ++/* Quirk data entry for a fixed audio endpoint; ++ * followed by audioformat definition ++ * e.g. QUIRK_DATA_AUDIOFORMAT(n) { .formats = xxx, ... } ++ */ ++#define QUIRK_DATA_AUDIOFORMAT(_ifno) \ ++ .ifnum = (_ifno), \ ++ .type = QUIRK_AUDIO_FIXED_ENDPOINT, \ ++ .data = &(const struct audioformat) ++ ++/* Quirk data entry for a fixed MIDI endpoint; ++ * followed by snd_usb_midi_endpoint_info definition ++ * e.g. QUIRK_DATA_MIDI_FIXED_ENDPOINT(n) { .out_cables = x, .in_cables = y } ++ */ ++#define QUIRK_DATA_MIDI_FIXED_ENDPOINT(_ifno) \ ++ .ifnum = (_ifno), \ ++ .type = QUIRK_MIDI_FIXED_ENDPOINT, \ ++ .data = &(const struct snd_usb_midi_endpoint_info) ++/* Quirk data entry for a MIDIMAN MIDI endpoint */ ++#define QUIRK_DATA_MIDI_MIDIMAN(_ifno) \ ++ .ifnum = (_ifno), \ ++ .type = QUIRK_MIDI_MIDIMAN, \ ++ .data = &(const struct snd_usb_midi_endpoint_info) ++/* Quirk data entry for a EMAGIC MIDI endpoint */ ++#define QUIRK_DATA_MIDI_EMAGIC(_ifno) \ ++ .ifnum = (_ifno), \ ++ .type = QUIRK_MIDI_EMAGIC, \ ++ .data = &(const struct snd_usb_midi_endpoint_info) ++ ++/* ++ * Here we go... the quirk table definition begins: ++ */ ++ + /* FTDI devices */ + { + USB_DEVICE(0x0403, 0xb8d8), +-- +2.43.0 + diff --git a/queue-6.10/alsa-usb-audio-replace-complex-quirk-lines-with-macr.patch b/queue-6.10/alsa-usb-audio-replace-complex-quirk-lines-with-macr.patch new file mode 100644 index 00000000000..547da88c57f --- /dev/null +++ b/queue-6.10/alsa-usb-audio-replace-complex-quirk-lines-with-macr.patch @@ -0,0 +1,4000 @@ +From c6df1184fbe038fcae1a393857c9bdab1fd95cf9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Aug 2024 15:48:42 +0200 +Subject: ALSA: usb-audio: Replace complex quirk lines with macros + +From: Takashi Iwai + +[ Upstream commit d79e13f8e8abb5cd3a2a0f9fc9bc3fc750c5b06f ] + +Apply the newly introduced macros for reduce the complex expressions +and cast in the quirk table definitions. It results in a significant +code reduction, too. + +There should be no functional changes. + +Link: https://patch.msgid.link/20240814134844.2726-3-tiwai@suse.de +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/quirks-table.h | 2210 ++++++++++---------------------------- + 1 file changed, 593 insertions(+), 1617 deletions(-) + +diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h +index 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 + * for helping researching this data */ + USB_DEVICE(0x0582, 0x000c), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Roland", + .product_name = "SC-D70", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(0) }, ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, + { +- .ifnum = 2, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) { + .out_cables = 0x0007, + .in_cables = 0x0007 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -865,35 +653,23 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * the 96kHz sample rate. + */ + USB_DEVICE(0x0582, 0x0010), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "UA-5", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = -1 +- } ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, ++ { QUIRK_DATA_STANDARD_AUDIO(2) }, ++ QUIRK_COMPOSITE_END + } + } + }, + { + /* has ID 0x0013 when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x0012), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Roland", + .product_name = "XV-5050", +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } +@@ -902,12 +678,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* has ID 0x0015 when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x0014), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "UM-880", +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x01ff, + .in_cables = 0x01ff + } +@@ -916,74 +690,48 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* has ID 0x0017 when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x0016), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "SD-90", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(0) }, ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, + { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) { + .out_cables = 0x000f, + .in_cables = 0x000f + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, + { + /* has ID 0x001c when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x001b), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Roland", + .product_name = "MMP-2", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 1, +- .type = QUIRK_IGNORE_INTERFACE +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_IGNORE(0) }, ++ { QUIRK_DATA_IGNORE(1) }, + { +- .ifnum = 2, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, + { + /* has ID 0x001e when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x001d), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Roland", + .product_name = "V-SYNTH", +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } +@@ -992,12 +740,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* has ID 0x0024 when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x0023), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "UM-550", +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x003f, + .in_cables = 0x003f + } +@@ -1010,20 +756,13 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * and no MIDI. + */ + USB_DEVICE(0x0582, 0x0025), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "UA-20", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_IGNORE_INTERFACE +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_IGNORE(0) }, + { +- .ifnum = 1, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = & (const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(1) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 2, + .iface = 1, +@@ -1038,9 +777,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 2, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = & (const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(2) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 2, + .iface = 2, +@@ -1055,28 +792,22 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 3, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(3) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, + { + /* has ID 0x0028 when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x0027), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "SD-20", +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x0003, + .in_cables = 0x0007 + } +@@ -1085,12 +816,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* has ID 0x002a when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x0029), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "SD-80", +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x000f, + .in_cables = 0x000f + } +@@ -1103,39 +832,24 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * but offers only 16-bit PCM and no MIDI. + */ + USB_DEVICE_VENDOR_SPEC(0x0582, 0x002b), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "UA-700", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_EDIROL_UAXX +- }, +- { +- .ifnum = 2, +- .type = QUIRK_AUDIO_EDIROL_UAXX +- }, +- { +- .ifnum = 3, +- .type = QUIRK_AUDIO_EDIROL_UAXX +- }, +- { +- .ifnum = -1 +- } ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_EDIROL_UAXX(1) }, ++ { QUIRK_DATA_EDIROL_UAXX(2) }, ++ { QUIRK_DATA_EDIROL_UAXX(3) }, ++ QUIRK_COMPOSITE_END + } + } + }, + { + /* has ID 0x002e when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x002d), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Roland", + .product_name = "XV-2020", +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } +@@ -1144,12 +858,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* has ID 0x0030 when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x002f), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Roland", + .product_name = "VariOS", +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x0007, + .in_cables = 0x0007 + } +@@ -1158,12 +870,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* has ID 0x0034 when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x0033), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "PCR", +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x0003, + .in_cables = 0x0007 + } +@@ -1175,12 +885,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * later revisions use IDs 0x0054 and 0x00a2. + */ + USB_DEVICE(0x0582, 0x0037), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Roland", + .product_name = "Digital Piano", +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } +@@ -1193,39 +901,24 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * and no MIDI. + */ + USB_DEVICE_VENDOR_SPEC(0x0582, 0x003b), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "BOSS", + .product_name = "GS-10", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = & (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 3, +- .type = QUIRK_MIDI_STANDARD_INTERFACE +- }, +- { +- .ifnum = -1 +- } ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, ++ { QUIRK_DATA_STANDARD_AUDIO(2) }, ++ { QUIRK_DATA_STANDARD_MIDI(3) }, ++ QUIRK_COMPOSITE_END + } + } + }, + { + /* has ID 0x0041 when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x0040), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Roland", + .product_name = "GI-20", +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } +@@ -1234,12 +927,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* has ID 0x0043 when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x0042), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Roland", + .product_name = "RS-70", +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } +@@ -1248,36 +939,24 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* has ID 0x0049 when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x0047), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + /* .vendor_name = "EDIROL", */ + /* .product_name = "UR-80", */ +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DATA_COMPOSITE { + /* in the 96 kHz modes, only interface 1 is there */ +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = -1 +- } ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, ++ { QUIRK_DATA_STANDARD_AUDIO(2) }, ++ QUIRK_COMPOSITE_END + } + } + }, + { + /* has ID 0x004a when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x0048), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + /* .vendor_name = "EDIROL", */ + /* .product_name = "UR-80", */ +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x0003, + .in_cables = 0x0007 + } +@@ -1286,35 +965,23 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* has ID 0x004e when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x004c), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "PCR-A", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = -1 +- } ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, ++ { QUIRK_DATA_STANDARD_AUDIO(2) }, ++ QUIRK_COMPOSITE_END + } + } + }, + { + /* has ID 0x004f when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x004d), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "PCR-A", +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x0003, + .in_cables = 0x0007 + } +@@ -1326,76 +993,52 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * is standard compliant, but has only 16-bit PCM. + */ + USB_DEVICE(0x0582, 0x0050), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "UA-3FX", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = -1 +- } ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, ++ { QUIRK_DATA_STANDARD_AUDIO(2) }, ++ QUIRK_COMPOSITE_END + } + } + }, + { + USB_DEVICE(0x0582, 0x0052), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "UM-1SX", +- .ifnum = 0, +- .type = QUIRK_MIDI_STANDARD_INTERFACE ++ QUIRK_DATA_STANDARD_MIDI(0) + } + }, + { + USB_DEVICE(0x0582, 0x0060), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Roland", + .product_name = "EXR Series", +- .ifnum = 0, +- .type = QUIRK_MIDI_STANDARD_INTERFACE ++ QUIRK_DATA_STANDARD_MIDI(0) + } + }, + { + /* has ID 0x0066 when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x0064), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + /* .vendor_name = "EDIROL", */ + /* .product_name = "PCR-1", */ +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = -1 +- } ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, ++ { QUIRK_DATA_STANDARD_AUDIO(2) }, ++ QUIRK_COMPOSITE_END + } + } + }, + { + /* has ID 0x0067 when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x0065), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + /* .vendor_name = "EDIROL", */ + /* .product_name = "PCR-1", */ +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x0001, + .in_cables = 0x0003 + } +@@ -1404,12 +1047,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* has ID 0x006e when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x006d), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Roland", + .product_name = "FANTOM-X", +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } +@@ -1422,39 +1063,24 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * offers only 16-bit PCM at 44.1 kHz and no MIDI. + */ + USB_DEVICE_VENDOR_SPEC(0x0582, 0x0074), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "UA-25", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_EDIROL_UAXX +- }, +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_EDIROL_UAXX +- }, +- { +- .ifnum = 2, +- .type = QUIRK_AUDIO_EDIROL_UAXX +- }, +- { +- .ifnum = -1 +- } ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_EDIROL_UAXX(0) }, ++ { QUIRK_DATA_EDIROL_UAXX(1) }, ++ { QUIRK_DATA_EDIROL_UAXX(2) }, ++ QUIRK_COMPOSITE_END + } + } + }, + { + /* has ID 0x0076 when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x0075), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "BOSS", + .product_name = "DR-880", +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } +@@ -1463,12 +1089,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* has ID 0x007b when not in "Advanced Driver" mode */ + USB_DEVICE_VENDOR_SPEC(0x0582, 0x007a), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Roland", + /* "RD" or "RD-700SX"? */ +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x0003, + .in_cables = 0x0003 + } +@@ -1477,12 +1101,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* has ID 0x0081 when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x0080), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Roland", + .product_name = "G-70", +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } +@@ -1491,12 +1113,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* has ID 0x008c when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x008b), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "PC-50", +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } +@@ -1508,56 +1128,31 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * is standard compliant, but has only 16-bit PCM and no MIDI. + */ + USB_DEVICE(0x0582, 0x00a3), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "UA-4FX", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_EDIROL_UAXX +- }, +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_EDIROL_UAXX +- }, +- { +- .ifnum = 2, +- .type = QUIRK_AUDIO_EDIROL_UAXX +- }, +- { +- .ifnum = -1 +- } ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_EDIROL_UAXX(0) }, ++ { QUIRK_DATA_EDIROL_UAXX(1) }, ++ { QUIRK_DATA_EDIROL_UAXX(2) }, ++ QUIRK_COMPOSITE_END + } + } + }, + { + /* Edirol M-16DX */ + USB_DEVICE(0x0582, 0x00c4), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(0) }, ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -1567,37 +1162,22 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * offers only 16-bit PCM at 44.1 kHz and no MIDI. + */ + USB_DEVICE_VENDOR_SPEC(0x0582, 0x00e6), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "UA-25EX", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_EDIROL_UAXX +- }, +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_EDIROL_UAXX +- }, +- { +- .ifnum = 2, +- .type = QUIRK_AUDIO_EDIROL_UAXX +- }, +- { +- .ifnum = -1 +- } ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_EDIROL_UAXX(0) }, ++ { QUIRK_DATA_EDIROL_UAXX(1) }, ++ { QUIRK_DATA_EDIROL_UAXX(2) }, ++ QUIRK_COMPOSITE_END + } + } + }, + { + /* Edirol UM-3G */ + USB_DEVICE_VENDOR_SPEC(0x0582, 0x0108), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x0007, + .in_cables = 0x0007 + } +@@ -1606,45 +1186,29 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* BOSS ME-25 */ + USB_DEVICE(0x0582, 0x0113), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(0) }, ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, + { + /* only 44.1 kHz works at the moment */ + USB_DEVICE(0x0582, 0x0120), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + /* .vendor_name = "Roland", */ + /* .product_name = "OCTO-CAPTURE", */ +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DATA_COMPOSITE { + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = & (const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels = 10, + .iface = 0, +@@ -1660,9 +1224,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 1, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = & (const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(1) { + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels = 12, + .iface = 1, +@@ -1678,40 +1240,26 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 2, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, +- { +- .ifnum = 3, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 4, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = -1 +- } ++ { QUIRK_DATA_IGNORE(3) }, ++ { QUIRK_DATA_IGNORE(4) }, ++ QUIRK_COMPOSITE_END + } + } + }, + { + /* only 44.1 kHz works at the moment */ + USB_DEVICE(0x0582, 0x012f), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + /* .vendor_name = "Roland", */ + /* .product_name = "QUAD-CAPTURE", */ +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DATA_COMPOSITE { + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = & (const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels = 4, + .iface = 0, +@@ -1727,9 +1275,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 1, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = & (const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(1) { + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels = 6, + .iface = 1, +@@ -1745,54 +1291,32 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 2, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, +- { +- .ifnum = 3, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 4, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = -1 +- } ++ { QUIRK_DATA_IGNORE(3) }, ++ { QUIRK_DATA_IGNORE(4) }, ++ QUIRK_COMPOSITE_END + } + } + }, + { + USB_DEVICE(0x0582, 0x0159), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + /* .vendor_name = "Roland", */ + /* .product_name = "UA-22", */ +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(0) }, ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, + { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -1800,19 +1324,19 @@ YAMAHA_DEVICE(0x7010, "UB99"), + /* UA101 and co are supported by another driver */ + { + USB_DEVICE(0x0582, 0x0044), /* UA-1000 high speed */ +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .ifnum = QUIRK_NODEV_INTERFACE + }, + }, + { + USB_DEVICE(0x0582, 0x007d), /* UA-101 high speed */ +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .ifnum = QUIRK_NODEV_INTERFACE + }, + }, + { + USB_DEVICE(0x0582, 0x008d), /* UA-101 full speed */ +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .ifnum = QUIRK_NODEV_INTERFACE + }, + }, +@@ -1823,7 +1347,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + USB_DEVICE_ID_MATCH_INT_CLASS, + .idVendor = 0x0582, + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_AUTODETECT + } +@@ -1838,12 +1362,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * compliant USB MIDI ports for external MIDI and controls. + */ + USB_DEVICE_VENDOR_SPEC(0x06f8, 0xb000), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Hercules", + .product_name = "DJ Console (WE)", +- .ifnum = 4, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(4) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } +@@ -1853,12 +1375,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + /* Midiman/M-Audio devices */ + { + USB_DEVICE_VENDOR_SPEC(0x0763, 0x1002), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "M-Audio", + .product_name = "MidiSport 2x2", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_MIDI_MIDIMAN, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_MIDIMAN(QUIRK_ANY_INTERFACE) { + .out_cables = 0x0003, + .in_cables = 0x0003 + } +@@ -1866,12 +1386,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + { + USB_DEVICE_VENDOR_SPEC(0x0763, 0x1011), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "M-Audio", + .product_name = "MidiSport 1x1", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_MIDI_MIDIMAN, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_MIDIMAN(QUIRK_ANY_INTERFACE) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } +@@ -1879,12 +1397,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + { + USB_DEVICE_VENDOR_SPEC(0x0763, 0x1015), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "M-Audio", + .product_name = "Keystation", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_MIDI_MIDIMAN, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_MIDIMAN(QUIRK_ANY_INTERFACE) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } +@@ -1892,12 +1408,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + { + USB_DEVICE_VENDOR_SPEC(0x0763, 0x1021), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "M-Audio", + .product_name = "MidiSport 4x4", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_MIDI_MIDIMAN, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_MIDIMAN(QUIRK_ANY_INTERFACE) { + .out_cables = 0x000f, + .in_cables = 0x000f + } +@@ -1910,12 +1424,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * Thanks to Olaf Giesbrecht + */ + USB_DEVICE_VER(0x0763, 0x1031, 0x0100, 0x0109), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "M-Audio", + .product_name = "MidiSport 8x8", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_MIDI_MIDIMAN, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_MIDIMAN(QUIRK_ANY_INTERFACE) { + .out_cables = 0x01ff, + .in_cables = 0x01ff + } +@@ -1923,12 +1435,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + { + USB_DEVICE_VENDOR_SPEC(0x0763, 0x1033), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "M-Audio", + .product_name = "MidiSport 8x8", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_MIDI_MIDIMAN, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_MIDIMAN(QUIRK_ANY_INTERFACE) { + .out_cables = 0x01ff, + .in_cables = 0x01ff + } +@@ -1936,12 +1446,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + { + USB_DEVICE_VENDOR_SPEC(0x0763, 0x1041), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "M-Audio", + .product_name = "MidiSport 2x4", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_MIDI_MIDIMAN, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_MIDIMAN(QUIRK_ANY_INTERFACE) { + .out_cables = 0x000f, + .in_cables = 0x0003 + } +@@ -1949,76 +1457,41 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + { + USB_DEVICE_VENDOR_SPEC(0x0763, 0x2001), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "M-Audio", + .product_name = "Quattro", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = & (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DATA_COMPOSITE { + /* + * Interfaces 0-2 are "Windows-compatible", 16-bit only, + * and share endpoints with the other interfaces. + * Ignore them. The other interfaces can do 24 bits, + * but captured samples are big-endian (see usbaudio.c). + */ +- { +- .ifnum = 0, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 1, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 3, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 4, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 5, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 6, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 7, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 8, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 9, +- .type = QUIRK_MIDI_MIDIMAN, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ { QUIRK_DATA_IGNORE(0) }, ++ { QUIRK_DATA_IGNORE(1) }, ++ { QUIRK_DATA_IGNORE(2) }, ++ { QUIRK_DATA_IGNORE(3) }, ++ { QUIRK_DATA_STANDARD_AUDIO(4) }, ++ { QUIRK_DATA_STANDARD_AUDIO(5) }, ++ { QUIRK_DATA_IGNORE(6) }, ++ { QUIRK_DATA_STANDARD_AUDIO(7) }, ++ { QUIRK_DATA_STANDARD_AUDIO(8) }, ++ { ++ QUIRK_DATA_MIDI_MIDIMAN(9) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, + { + USB_DEVICE_VENDOR_SPEC(0x0763, 0x2003), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "M-Audio", + .product_name = "AudioPhile", +- .ifnum = 6, +- .type = QUIRK_MIDI_MIDIMAN, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_MIDIMAN(6) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } +@@ -2026,12 +1499,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + { + USB_DEVICE_VENDOR_SPEC(0x0763, 0x2008), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "M-Audio", + .product_name = "Ozone", +- .ifnum = 3, +- .type = QUIRK_MIDI_MIDIMAN, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_MIDIMAN(3) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } +@@ -2039,93 +1510,45 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + { + USB_DEVICE_VENDOR_SPEC(0x0763, 0x200d), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "M-Audio", + .product_name = "OmniStudio", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = & (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 1, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 3, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 4, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 5, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 6, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 7, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 8, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 9, +- .type = QUIRK_MIDI_MIDIMAN, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_IGNORE(0) }, ++ { QUIRK_DATA_IGNORE(1) }, ++ { QUIRK_DATA_IGNORE(2) }, ++ { QUIRK_DATA_IGNORE(3) }, ++ { QUIRK_DATA_STANDARD_AUDIO(4) }, ++ { QUIRK_DATA_STANDARD_AUDIO(5) }, ++ { QUIRK_DATA_IGNORE(6) }, ++ { QUIRK_DATA_STANDARD_AUDIO(7) }, ++ { QUIRK_DATA_STANDARD_AUDIO(8) }, ++ { ++ QUIRK_DATA_MIDI_MIDIMAN(9) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, + { + USB_DEVICE(0x0763, 0x2019), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + /* .vendor_name = "M-Audio", */ + /* .product_name = "Ozone Academic", */ +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = & (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(0) }, ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, ++ { QUIRK_DATA_STANDARD_AUDIO(2) }, + { +- .ifnum = 2, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 3, +- .type = QUIRK_MIDI_MIDIMAN, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_MIDIMAN(3) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -2135,21 +1558,14 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + { + USB_DEVICE_VENDOR_SPEC(0x0763, 0x2030), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + /* .vendor_name = "M-Audio", */ + /* .product_name = "Fast Track C400", */ +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = &(const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_MIXER, +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_MIXER(1) }, + /* Playback */ + { +- .ifnum = 2, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(2) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 6, + .iface = 2, +@@ -2173,9 +1589,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + /* Capture */ + { +- .ifnum = 3, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(3) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 4, + .iface = 3, +@@ -2197,30 +1611,21 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .clock = 0x80, + } + }, +- /* MIDI */ +- { +- .ifnum = -1 /* Interface = 4 */ +- } ++ /* MIDI: Interface = 4*/ ++ QUIRK_COMPOSITE_END + } + } + }, + { + USB_DEVICE_VENDOR_SPEC(0x0763, 0x2031), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + /* .vendor_name = "M-Audio", */ + /* .product_name = "Fast Track C600", */ +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = &(const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_MIXER, +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_MIXER(1) }, + /* Playback */ + { +- .ifnum = 2, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(2) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, + .iface = 2, +@@ -2244,9 +1649,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + /* Capture */ + { +- .ifnum = 3, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(3) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 6, + .iface = 3, +@@ -2268,29 +1671,20 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .clock = 0x80, + } + }, +- /* MIDI */ +- { +- .ifnum = -1 /* Interface = 4 */ +- } ++ /* MIDI: Interface = 4 */ ++ QUIRK_COMPOSITE_END + } + } + }, + { + USB_DEVICE_VENDOR_SPEC(0x0763, 0x2080), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + /* .vendor_name = "M-Audio", */ + /* .product_name = "Fast Track Ultra", */ +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = & (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_MIXER, +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_MIXER(0) }, + { +- .ifnum = 1, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = & (const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(1) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, + .iface = 1, +@@ -2312,9 +1706,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 2, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = & (const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(2) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, + .iface = 2, +@@ -2336,28 +1728,19 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + /* interface 3 (MIDI) is standard compliant */ +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, + { + USB_DEVICE_VENDOR_SPEC(0x0763, 0x2081), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + /* .vendor_name = "M-Audio", */ + /* .product_name = "Fast Track Ultra 8R", */ +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = & (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_MIXER, +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_MIXER(0) }, + { +- .ifnum = 1, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = & (const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(1) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, + .iface = 1, +@@ -2379,9 +1762,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 2, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = & (const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(2) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, + .iface = 2, +@@ -2403,9 +1784,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + /* interface 3 (MIDI) is standard compliant */ +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -2413,21 +1792,19 @@ YAMAHA_DEVICE(0x7010, "UB99"), + /* Casio devices */ + { + USB_DEVICE(0x07cf, 0x6801), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Casio", + .product_name = "PL-40R", +- .ifnum = 0, +- .type = QUIRK_MIDI_YAMAHA ++ QUIRK_DATA_MIDI_YAMAHA(0) + } + }, + { + /* this ID is used by several devices without a product ID */ + USB_DEVICE(0x07cf, 0x6802), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Casio", + .product_name = "Keyboard", +- .ifnum = 0, +- .type = QUIRK_MIDI_YAMAHA ++ QUIRK_DATA_MIDI_YAMAHA(0) + } + }, + +@@ -2440,23 +1817,13 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .idVendor = 0x07fd, + .idProduct = 0x0001, + .bDeviceSubClass = 2, +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "MOTU", + .product_name = "Fastlane", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = & (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_MIDI_RAW_BYTES +- }, +- { +- .ifnum = 1, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = -1 +- } ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_RAW_BYTES(0) }, ++ { QUIRK_DATA_IGNORE(1) }, ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -2464,12 +1831,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + /* Emagic devices */ + { + USB_DEVICE(0x086a, 0x0001), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Emagic", + .product_name = "Unitor8", +- .ifnum = 2, +- .type = QUIRK_MIDI_EMAGIC, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_EMAGIC(2) { + .out_cables = 0x80ff, + .in_cables = 0x80ff + } +@@ -2477,12 +1842,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + { + USB_DEVICE(0x086a, 0x0002), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Emagic", + /* .product_name = "AMT8", */ +- .ifnum = 2, +- .type = QUIRK_MIDI_EMAGIC, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_EMAGIC(2) { + .out_cables = 0x80ff, + .in_cables = 0x80ff + } +@@ -2490,12 +1853,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + { + USB_DEVICE(0x086a, 0x0003), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Emagic", + /* .product_name = "MT4", */ +- .ifnum = 2, +- .type = QUIRK_MIDI_EMAGIC, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_EMAGIC(2) { + .out_cables = 0x800f, + .in_cables = 0x8003 + } +@@ -2505,38 +1866,35 @@ YAMAHA_DEVICE(0x7010, "UB99"), + /* KORG devices */ + { + USB_DEVICE_VENDOR_SPEC(0x0944, 0x0200), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "KORG, Inc.", + /* .product_name = "PANDORA PX5D", */ +- .ifnum = 3, +- .type = QUIRK_MIDI_STANDARD_INTERFACE, ++ QUIRK_DATA_STANDARD_MIDI(3) + } + }, + + { + USB_DEVICE_VENDOR_SPEC(0x0944, 0x0201), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "KORG, Inc.", + /* .product_name = "ToneLab ST", */ +- .ifnum = 3, +- .type = QUIRK_MIDI_STANDARD_INTERFACE, ++ QUIRK_DATA_STANDARD_MIDI(3) + } + }, + + { + USB_DEVICE_VENDOR_SPEC(0x0944, 0x0204), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "KORG, Inc.", + /* .product_name = "ToneLab EX", */ +- .ifnum = 3, +- .type = QUIRK_MIDI_STANDARD_INTERFACE, ++ QUIRK_DATA_STANDARD_MIDI(3) + } + }, + + /* AKAI devices */ + { + USB_DEVICE(0x09e8, 0x0062), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "AKAI", + .product_name = "MPD16", + .ifnum = 0, +@@ -2547,21 +1905,11 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* Akai MPC Element */ + USB_DEVICE(0x09e8, 0x0021), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = & (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 1, +- .type = QUIRK_MIDI_STANDARD_INTERFACE +- }, +- { +- .ifnum = -1 +- } ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_IGNORE(0) }, ++ { QUIRK_DATA_STANDARD_MIDI(1) }, ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -2570,66 +1918,36 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* Steinberg MI2 */ + USB_DEVICE_VENDOR_SPEC(0x0a4e, 0x2040), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = & (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(0) }, ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, ++ { QUIRK_DATA_STANDARD_AUDIO(2) }, + { +- .ifnum = 3, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = &(const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(3) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, + { + /* Steinberg MI4 */ + USB_DEVICE_VENDOR_SPEC(0x0a4e, 0x4040), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = & (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(0) }, ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, ++ { QUIRK_DATA_STANDARD_AUDIO(2) }, + { +- .ifnum = 3, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = &(const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(3) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -2637,34 +1955,31 @@ YAMAHA_DEVICE(0x7010, "UB99"), + /* TerraTec devices */ + { + USB_DEVICE_VENDOR_SPEC(0x0ccd, 0x0012), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "TerraTec", + .product_name = "PHASE 26", +- .ifnum = 3, +- .type = QUIRK_MIDI_STANDARD_INTERFACE ++ QUIRK_DATA_STANDARD_MIDI(3) + } + }, + { + USB_DEVICE_VENDOR_SPEC(0x0ccd, 0x0013), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "TerraTec", + .product_name = "PHASE 26", +- .ifnum = 3, +- .type = QUIRK_MIDI_STANDARD_INTERFACE ++ QUIRK_DATA_STANDARD_MIDI(3) + } + }, + { + USB_DEVICE_VENDOR_SPEC(0x0ccd, 0x0014), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "TerraTec", + .product_name = "PHASE 26", +- .ifnum = 3, +- .type = QUIRK_MIDI_STANDARD_INTERFACE ++ QUIRK_DATA_STANDARD_MIDI(3) + } + }, + { + USB_DEVICE(0x0ccd, 0x0035), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Miditech", + .product_name = "Play'n Roll", + .ifnum = 0, +@@ -2679,7 +1994,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + /* Novation EMS devices */ + { + USB_DEVICE_VENDOR_SPEC(0x1235, 0x0001), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Novation", + .product_name = "ReMOTE Audio/XStation", + .ifnum = 4, +@@ -2688,7 +2003,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + { + USB_DEVICE_VENDOR_SPEC(0x1235, 0x0002), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Novation", + .product_name = "Speedio", + .ifnum = 3, +@@ -2697,38 +2012,29 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + { + USB_DEVICE(0x1235, 0x000a), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + /* .vendor_name = "Novation", */ + /* .product_name = "Nocturn", */ +- .ifnum = 0, +- .type = QUIRK_MIDI_RAW_BYTES ++ QUIRK_DATA_RAW_BYTES(0) + } + }, + { + USB_DEVICE(0x1235, 0x000e), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + /* .vendor_name = "Novation", */ + /* .product_name = "Launchpad", */ +- .ifnum = 0, +- .type = QUIRK_MIDI_RAW_BYTES ++ QUIRK_DATA_RAW_BYTES(0) + } + }, + { + USB_DEVICE(0x1235, 0x0010), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Focusrite", + .product_name = "Saffire 6 USB", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_MIXER(0) }, + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_MIXER, +- }, +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 4, + .iface = 0, +@@ -2755,9 +2061,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 2, + .iface = 0, +@@ -2779,28 +2083,19 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + } + }, +- { +- .ifnum = 1, +- .type = QUIRK_MIDI_RAW_BYTES +- }, +- { +- .ifnum = -1 +- } ++ { QUIRK_DATA_RAW_BYTES(1) }, ++ QUIRK_COMPOSITE_END + } + } + }, + { + USB_DEVICE(0x1235, 0x0018), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Novation", + .product_name = "Twitch", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DATA_COMPOSITE { + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = & (const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 4, + .iface = 0, +@@ -2819,19 +2114,14 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + } + }, +- { +- .ifnum = 1, +- .type = QUIRK_MIDI_RAW_BYTES +- }, +- { +- .ifnum = -1 +- } ++ { QUIRK_DATA_RAW_BYTES(1) }, ++ QUIRK_COMPOSITE_END + } + } + }, + { + USB_DEVICE_VENDOR_SPEC(0x1235, 0x4661), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Novation", + .product_name = "ReMOTE25", + .ifnum = 0, +@@ -2843,25 +2133,16 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* VirusTI Desktop */ + USB_DEVICE_VENDOR_SPEC(0x133e, 0x0815), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = &(const struct snd_usb_audio_quirk[]) { ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { + { +- .ifnum = 3, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = &(const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(3) { + .out_cables = 0x0003, + .in_cables = 0x0003 + } + }, +- { +- .ifnum = 4, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = -1 +- } ++ { QUIRK_DATA_IGNORE(4) }, ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -2889,7 +2170,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + /* QinHeng devices */ + { + USB_DEVICE(0x1a86, 0x752d), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "QinHeng", + .product_name = "CH345", + .ifnum = 1, +@@ -2903,7 +2184,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + /* Miditech devices */ + { + USB_DEVICE(0x4752, 0x0011), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Miditech", + .product_name = "Midistart-2", + .ifnum = 0, +@@ -2915,7 +2196,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* this ID used by both Miditech MidiStudio-2 and CME UF-x */ + USB_DEVICE(0x7104, 0x2202), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .ifnum = 0, + .type = QUIRK_MIDI_CME + } +@@ -2925,20 +2206,13 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* Thanks to Clemens Ladisch */ + USB_DEVICE(0x0dba, 0x1000), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Digidesign", + .product_name = "MBox", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]){ +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_MIXER, +- }, ++ QUIRK_DATA_COMPOSITE{ ++ { QUIRK_DATA_STANDARD_MIXER(0) }, + { +- .ifnum = 1, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(1) { + .formats = SNDRV_PCM_FMTBIT_S24_3BE, + .channels = 2, + .iface = 1, +@@ -2959,9 +2233,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 1, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(1) { + .formats = SNDRV_PCM_FMTBIT_S24_3BE, + .channels = 2, + .iface = 1, +@@ -2982,9 +2254,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -2992,24 +2262,14 @@ YAMAHA_DEVICE(0x7010, "UB99"), + /* DIGIDESIGN MBOX 2 */ + { + USB_DEVICE(0x0dba, 0x3000), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Digidesign", + .product_name = "Mbox 2", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 1, +- .type = QUIRK_IGNORE_INTERFACE +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_IGNORE(0) }, ++ { QUIRK_DATA_IGNORE(1) }, + { +- .ifnum = 2, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(2) { + .formats = SNDRV_PCM_FMTBIT_S24_3BE, + .channels = 2, + .iface = 2, +@@ -3027,15 +2287,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + } + }, ++ { QUIRK_DATA_IGNORE(3) }, + { +- .ifnum = 3, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 4, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { +- .formats = SNDRV_PCM_FMTBIT_S24_3BE, ++ QUIRK_DATA_AUDIOFORMAT(4) { ++ .formats = SNDRV_PCM_FMTBIT_S24_3BE, + .channels = 2, + .iface = 4, + .altsetting = 2, +@@ -3052,14 +2307,9 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + } + }, ++ { QUIRK_DATA_IGNORE(5) }, + { +- .ifnum = 5, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 6, +- .type = QUIRK_MIDI_MIDIMAN, +- .data = &(const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_MIDIMAN(6) { + .out_ep = 0x02, + .out_cables = 0x0001, + .in_ep = 0x81, +@@ -3067,33 +2317,21 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .in_cables = 0x0001 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, + /* DIGIDESIGN MBOX 3 */ + { + USB_DEVICE(0x0dba, 0x5000), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Digidesign", + .product_name = "Mbox 3", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_IGNORE_INTERFACE +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_IGNORE(0) }, ++ { QUIRK_DATA_IGNORE(1) }, + { +- .ifnum = 1, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(2) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .fmt_bits = 24, + .channels = 4, +@@ -3120,9 +2358,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 3, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(3) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .fmt_bits = 24, + .channels = 4, +@@ -3146,36 +2382,25 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 4, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = &(const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(4) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, + { + /* Tascam US122 MKII - playback-only support */ + USB_DEVICE_VENDOR_SPEC(0x0644, 0x8021), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "TASCAM", + .product_name = "US122 MKII", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_IGNORE(0) }, + { +- .ifnum = 0, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(1) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 2, + .iface = 1, +@@ -3196,9 +2421,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3206,20 +2429,13 @@ YAMAHA_DEVICE(0x7010, "UB99"), + /* Denon DN-X1600 */ + { + USB_AUDIO_DEVICE(0x154e, 0x500e), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Denon", + .product_name = "DN-X1600", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]){ ++ QUIRK_DATA_COMPOSITE{ ++ { QUIRK_DATA_IGNORE(0) }, + { +- .ifnum = 0, +- .type = QUIRK_IGNORE_INTERFACE, +- }, +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(1) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, + .iface = 1, +@@ -3240,9 +2456,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 2, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(2) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, + .iface = 2, +@@ -3262,13 +2476,8 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + } + }, +- { +- .ifnum = 4, +- .type = QUIRK_MIDI_STANDARD_INTERFACE, +- }, +- { +- .ifnum = -1 +- } ++ { QUIRK_DATA_STANDARD_MIDI(4) }, ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3277,17 +2486,13 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + USB_DEVICE(0x045e, 0x0283), + .bInterfaceClass = USB_CLASS_PER_INTERFACE, +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Microsoft", + .product_name = "XboxLive Headset/Xbox Communicator", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = &(const struct snd_usb_audio_quirk[]) { ++ QUIRK_DATA_COMPOSITE { + { + /* playback */ +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .channels = 1, + .iface = 0, +@@ -3303,9 +2508,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + { + /* capture */ +- .ifnum = 1, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(1) { + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .channels = 1, + .iface = 1, +@@ -3319,9 +2522,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_max = 16000 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3330,18 +2531,11 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + USB_DEVICE(0x200c, 0x100b), + .bInterfaceClass = USB_CLASS_PER_INTERFACE, +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = &(const struct snd_usb_audio_quirk[]) { ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_MIXER(0) }, + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_MIXER, +- }, +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(1) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 4, + .iface = 1, +@@ -3360,9 +2554,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3375,28 +2567,12 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * enabled in create_standard_audio_quirk(). + */ + USB_DEVICE(0x1686, 0x00dd), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- /* Playback */ +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE, +- }, +- { +- /* Capture */ +- .ifnum = 2, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE, +- }, +- { +- /* Midi */ +- .ifnum = 3, +- .type = QUIRK_MIDI_STANDARD_INTERFACE +- }, +- { +- .ifnum = -1 +- }, ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, /* Playback */ ++ { QUIRK_DATA_STANDARD_AUDIO(2) }, /* Capture */ ++ { QUIRK_DATA_STANDARD_MIDI(3) }, /* Midi */ ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3410,18 +2586,16 @@ YAMAHA_DEVICE(0x7010, "UB99"), + USB_DEVICE_ID_MATCH_INT_SUBCLASS, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_MIDISTREAMING, +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_MIDI_STANDARD_INTERFACE ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_STANDARD_MIDI(QUIRK_ANY_INTERFACE) + } + }, + + /* Rane SL-1 */ + { + USB_DEVICE(0x13e5, 0x0001), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_STANDARD_AUDIO(QUIRK_ANY_INTERFACE) + } + }, + +@@ -3437,24 +2611,13 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * and only the 48 kHz sample rate works for the playback interface. + */ + USB_DEVICE(0x0a12, 0x1243), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_MIXER, +- }, +- /* Capture */ +- { +- .ifnum = 1, +- .type = QUIRK_IGNORE_INTERFACE, +- }, ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_MIXER(0) }, ++ { QUIRK_DATA_IGNORE(1) }, /* Capture */ + /* Playback */ + { +- .ifnum = 2, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(2) { + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .channels = 2, + .iface = 2, +@@ -3473,9 +2636,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + } + }, +- { +- .ifnum = -1 +- }, ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3488,19 +2649,12 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * even on windows. + */ + USB_DEVICE(0x19b5, 0x0021), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_MIXER, +- }, ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_MIXER(0) }, + /* Playback */ + { +- .ifnum = 1, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(1) { + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .channels = 2, + .iface = 1, +@@ -3519,29 +2673,20 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + } + }, +- { +- .ifnum = -1 +- }, ++ QUIRK_COMPOSITE_END + } + } + }, + /* MOTU Microbook II */ + { + USB_DEVICE_VENDOR_SPEC(0x07fd, 0x0004), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "MOTU", + .product_name = "MicroBookII", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_MIXER, +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_MIXER(0) }, + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3BE, + .channels = 6, + .iface = 0, +@@ -3562,9 +2707,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3BE, + .channels = 8, + .iface = 0, +@@ -3585,9 +2728,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3599,14 +2740,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * The feedback for the output is the input. + */ + USB_DEVICE_VENDOR_SPEC(0x2b73, 0x0023), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels = 12, + .iface = 0, +@@ -3623,9 +2760,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels = 10, + .iface = 0, +@@ -3643,9 +2778,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_table = (unsigned int[]) { 44100 } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3688,14 +2821,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * but not for DVS (Digital Vinyl Systems) like in Mixxx. + */ + USB_DEVICE_VENDOR_SPEC(0x2b73, 0x0017), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, // outputs + .iface = 0, +@@ -3712,9 +2841,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, // inputs + .iface = 0, +@@ -3732,9 +2859,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_table = (unsigned int[]) { 48000 } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3745,14 +2870,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * The feedback for the output is the dummy input. + */ + USB_DEVICE_VENDOR_SPEC(0x2b73, 0x000e), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 4, + .iface = 0, +@@ -3769,9 +2890,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 2, + .iface = 0, +@@ -3789,9 +2908,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_table = (unsigned int[]) { 44100 } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3802,14 +2919,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * PCM is 6 channels out & 4 channels in @ 44.1 fixed + */ + USB_DEVICE_VENDOR_SPEC(0x2b73, 0x000d), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 6, //Master, Headphones & Booth + .iface = 0, +@@ -3826,9 +2939,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 4, //2x RCA inputs (CH1 & CH2) + .iface = 0, +@@ -3846,9 +2957,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_table = (unsigned int[]) { 44100 } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3860,14 +2969,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * The Feedback for the output is the input + */ + USB_DEVICE_VENDOR_SPEC(0x2b73, 0x001e), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 4, + .iface = 0, +@@ -3884,9 +2989,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 6, + .iface = 0, +@@ -3904,9 +3007,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_table = (unsigned int[]) { 44100 } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3917,14 +3018,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * 10 channels playback & 12 channels capture @ 44.1/48/96kHz S24LE + */ + USB_DEVICE_VENDOR_SPEC(0x2b73, 0x000a), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 10, + .iface = 0, +@@ -3945,9 +3042,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 12, + .iface = 0, +@@ -3969,9 +3064,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3983,14 +3076,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * The Feedback for the output is the input + */ + USB_DEVICE_VENDOR_SPEC(0x2b73, 0x0029), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 6, + .iface = 0, +@@ -4007,9 +3096,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 6, + .iface = 0, +@@ -4027,9 +3114,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_table = (unsigned int[]) { 44100 } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -4047,20 +3132,13 @@ YAMAHA_DEVICE(0x7010, "UB99"), + */ + { + USB_AUDIO_DEVICE(0x534d, 0x0021), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "MacroSilicon", + .product_name = "MS210x", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = &(const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 2, +- .type = QUIRK_AUDIO_STANDARD_MIXER, +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_MIXER(2) }, + { +- .ifnum = 3, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(3) { + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .channels = 2, + .iface = 3, +@@ -4075,9 +3153,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_max = 48000, + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -4095,20 +3171,13 @@ YAMAHA_DEVICE(0x7010, "UB99"), + */ + { + USB_AUDIO_DEVICE(0x534d, 0x2109), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "MacroSilicon", + .product_name = "MS2109", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = &(const struct snd_usb_audio_quirk[]) { ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_MIXER(2) }, + { +- .ifnum = 2, +- .type = QUIRK_AUDIO_STANDARD_MIXER, +- }, +- { +- .ifnum = 3, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(3) { + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .channels = 2, + .iface = 3, +@@ -4123,9 +3192,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_max = 48000, + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -4135,14 +3202,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * 8 channels playback & 8 channels capture @ 44.1/48/96kHz S24LE + */ + USB_DEVICE_VENDOR_SPEC(0x08e4, 0x017f), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, + .iface = 0, +@@ -4161,9 +3224,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, + .iface = 0, +@@ -4183,9 +3244,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_table = (unsigned int[]) { 44100, 48000, 96000 } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -4195,14 +3254,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * 10 channels playback & 12 channels capture @ 48kHz S24LE + */ + USB_DEVICE_VENDOR_SPEC(0x2b73, 0x001b), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 10, + .iface = 0, +@@ -4221,9 +3276,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 12, + .iface = 0, +@@ -4241,9 +3294,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_table = (unsigned int[]) { 48000 } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -4255,14 +3306,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * Capture on EP 0x86 + */ + USB_DEVICE_VENDOR_SPEC(0x08e4, 0x0163), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, + .iface = 0, +@@ -4282,9 +3329,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, + .iface = 0, +@@ -4304,9 +3349,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_table = (unsigned int[]) { 44100, 48000, 96000 } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -4317,14 +3360,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * and 8 channels in @ 48 fixed (endpoint 0x82). + */ + USB_DEVICE_VENDOR_SPEC(0x2b73, 0x0013), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, // outputs + .iface = 0, +@@ -4341,9 +3380,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, // inputs + .iface = 0, +@@ -4361,9 +3398,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_table = (unsigned int[]) { 48000 } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -4374,28 +3409,15 @@ YAMAHA_DEVICE(0x7010, "UB99"), + */ + USB_DEVICE(0x1395, 0x0300), + .bInterfaceClass = USB_CLASS_PER_INTERFACE, +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = &(const struct snd_usb_audio_quirk[]) { ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { + // Communication +- { +- .ifnum = 3, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, ++ { QUIRK_DATA_STANDARD_AUDIO(3) }, + // Recording +- { +- .ifnum = 4, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, ++ { QUIRK_DATA_STANDARD_AUDIO(4) }, + // Main +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = -1 +- } ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -4404,21 +3426,14 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * Fiero SC-01 (firmware v1.0.0 @ 48 kHz) + */ + USB_DEVICE(0x2b53, 0x0023), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Fiero", + .product_name = "SC-01", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = &(const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(0) }, + /* Playback */ + { +- .ifnum = 1, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(1) { + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels = 2, + .fmt_bits = 24, +@@ -4438,9 +3453,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + /* Capture */ + { +- .ifnum = 2, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(2) { + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels = 2, + .fmt_bits = 24, +@@ -4459,9 +3472,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .clock = 0x29 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -4470,21 +3481,14 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * Fiero SC-01 (firmware v1.0.0 @ 96 kHz) + */ + USB_DEVICE(0x2b53, 0x0024), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Fiero", + .product_name = "SC-01", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = &(const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(0) }, + /* Playback */ + { +- .ifnum = 1, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(1) { + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels = 2, + .fmt_bits = 24, +@@ -4504,9 +3508,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + /* Capture */ + { +- .ifnum = 2, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(2) { + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels = 2, + .fmt_bits = 24, +@@ -4525,9 +3527,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .clock = 0x29 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -4536,21 +3536,14 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * Fiero SC-01 (firmware v1.1.0) + */ + USB_DEVICE(0x2b53, 0x0031), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Fiero", + .product_name = "SC-01", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = &(const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(0) }, + /* Playback */ + { +- .ifnum = 1, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(1) { + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels = 2, + .fmt_bits = 24, +@@ -4571,9 +3564,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + /* Capture */ + { +- .ifnum = 2, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(2) { + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels = 2, + .fmt_bits = 24, +@@ -4593,9 +3584,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .clock = 0x29 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -4604,27 +3593,14 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * For the standard mode, Mythware XA001AU has ID ffad:a001 + */ + USB_DEVICE_VENDOR_SPEC(0xffad, 0xa001), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Mythware", + .product_name = "XA001AU", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_IGNORE_INTERFACE, +- }, +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE, +- }, +- { +- .ifnum = 2, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE, +- }, +- { +- .ifnum = -1 +- } ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_IGNORE(0) }, ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, ++ { QUIRK_DATA_STANDARD_AUDIO(2) }, ++ QUIRK_COMPOSITE_END + } + } + }, +-- +2.43.0 + diff --git a/queue-6.10/alsa-usb-audio-support-multiple-control-interfaces.patch b/queue-6.10/alsa-usb-audio-support-multiple-control-interfaces.patch new file mode 100644 index 00000000000..03d755c27b8 --- /dev/null +++ b/queue-6.10/alsa-usb-audio-support-multiple-control-interfaces.patch @@ -0,0 +1,659 @@ +From 1900d66454dede84d5e1cdca46b1443b272293a3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 11 Aug 2024 17:29:56 -0700 +Subject: ALSA: usb-audio: Support multiple control interfaces + +From: Karol Kosik + +[ Upstream commit 6aa8700150f7dc62f60b4cf5b1624e2e3d9ed78e ] + +Registering Numark Party Mix II fails with error 'bogus bTerminalLink 1'. +The problem stems from the driver not being able to find input/output +terminals required to configure audio streaming. The information about +those terminals is stored in AudioControl Interface. Numark device +contains 2 AudioControl Interfaces and the driver checks only one of them. + +According to the USB standard, a device can have multiple audio functions, +each represented by Audio Interface Collection. Every audio function is +considered to be closed box and will contain unique AudioControl Interface +and zero or more AudioStreaming and MIDIStreaming Interfaces. + +The Numark device adheres to the standard and defines two audio functions: +- MIDIStreaming function +- AudioStreaming function +It starts with MIDI function, followed by the audio function. The driver +saves the first AudioControl Interface in `snd_usb_audio` structure +associated with the entire device. It then attempts to use this interface +to query for terminals and clocks. However, this fails because the correct +information is stored in the second AudioControl Interface, defined in the +second Audio Interface Collection. + +This patch introduces a structure holding association between each +MIDI/Audio Interface and its corresponding AudioControl Interface, +instead of relying on AudioControl Interface defined for the entire +device. This structure is populated during usb probing phase and leveraged +later when querying for terminals and when sending USB requests. + +Alternative solutions considered include: +- defining a quirk for Numark where the order of interface is manually +changed, or terminals are hardcoded in the driver. This solution would +have fixed only this model, though it seems that device is USB compliant, +and it also seems that other devices from this company may be affected. +What's more, it looks like products from other manufacturers have similar +problems, i.e. Rane One DJ console +- keeping a list of all AudioControl Interfaces and querying all of them +to find required information. That would have solved my problem and have +low probability of breaking other devices, as we would always start with +the same logic of querying first AudioControl Interface. This solution +would not have followed the standard though. + +This patch preserves the `snd_usb_audio.ctrl_intf` variable, which holds +the first AudioControl Interface, and uses it as a fallback when some +interfaces are not parsed correctly and lack an associated AudioControl +Interface, i.e., when configured via quirks. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=217865 +Signed-off-by: Karol Kosik +Link: https://patch.msgid.link/AS8P190MB1285893F4735C8B32AD3886BEC852@AS8P190MB1285.EURP190.PROD.OUTLOOK.COM +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/card.c | 2 ++ + sound/usb/clock.c | 62 ++++++++++++++++++++++++-------------- + sound/usb/format.c | 6 ++-- + sound/usb/helper.c | 34 +++++++++++++++++++++ + sound/usb/helper.h | 10 ++++-- + sound/usb/mixer.c | 2 +- + sound/usb/mixer_quirks.c | 17 ++++++----- + sound/usb/mixer_scarlett.c | 4 +-- + sound/usb/power.c | 3 +- + sound/usb/power.h | 1 + + sound/usb/stream.c | 21 ++++++++----- + sound/usb/usbaudio.h | 12 ++++++++ + 12 files changed, 127 insertions(+), 47 deletions(-) + +diff --git a/sound/usb/card.c b/sound/usb/card.c +index bdb04fa37a71d..778de9244f1e7 100644 +--- a/sound/usb/card.c ++++ b/sound/usb/card.c +@@ -206,6 +206,8 @@ static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int int + return -EINVAL; + } + ++ snd_usb_add_ctrl_interface_link(chip, interface, ctrlif); ++ + if (! snd_usb_parse_audio_interface(chip, interface)) { + usb_set_interface(dev, interface, 0); /* reset the current interface */ + return usb_driver_claim_interface(&usb_audio_driver, iface, +diff --git a/sound/usb/clock.c b/sound/usb/clock.c +index 60fcb872a80b6..8f85200292f3f 100644 +--- a/sound/usb/clock.c ++++ b/sound/usb/clock.c +@@ -76,11 +76,14 @@ static bool validate_clock_multiplier(void *p, int id, int proto) + } + + #define DEFINE_FIND_HELPER(name, obj, validator, type2, type3) \ +-static obj *name(struct snd_usb_audio *chip, int id, int proto) \ ++static obj *name(struct snd_usb_audio *chip, int id, \ ++ const struct audioformat *fmt) \ + { \ +- return find_uac_clock_desc(chip->ctrl_intf, id, validator, \ +- proto == UAC_VERSION_3 ? (type3) : (type2), \ +- proto); \ ++ struct usb_host_interface *ctrl_intf = \ ++ snd_usb_find_ctrl_interface(chip, fmt->iface); \ ++ return find_uac_clock_desc(ctrl_intf, id, validator, \ ++ fmt->protocol == UAC_VERSION_3 ? (type3) : (type2), \ ++ fmt->protocol); \ + } + + DEFINE_FIND_HELPER(snd_usb_find_clock_source, +@@ -93,16 +96,19 @@ DEFINE_FIND_HELPER(snd_usb_find_clock_multiplier, + union uac23_clock_multiplier_desc, validate_clock_multiplier, + UAC2_CLOCK_MULTIPLIER, UAC3_CLOCK_MULTIPLIER); + +-static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_id) ++static int uac_clock_selector_get_val(struct snd_usb_audio *chip, ++ int selector_id, int iface_no) + { ++ struct usb_host_interface *ctrl_intf; + unsigned char buf; + int ret; + ++ ctrl_intf = snd_usb_find_ctrl_interface(chip, iface_no); + ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), + UAC2_CS_CUR, + USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, + UAC2_CX_CLOCK_SELECTOR << 8, +- snd_usb_ctrl_intf(chip) | (selector_id << 8), ++ snd_usb_ctrl_intf(ctrl_intf) | (selector_id << 8), + &buf, sizeof(buf)); + + if (ret < 0) +@@ -111,16 +117,18 @@ static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_i + return buf; + } + +-static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_id, +- unsigned char pin) ++static int uac_clock_selector_set_val(struct snd_usb_audio *chip, ++ int selector_id, unsigned char pin, int iface_no) + { ++ struct usb_host_interface *ctrl_intf; + int ret; + ++ ctrl_intf = snd_usb_find_ctrl_interface(chip, iface_no); + ret = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), + UAC2_CS_CUR, + USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, + UAC2_CX_CLOCK_SELECTOR << 8, +- snd_usb_ctrl_intf(chip) | (selector_id << 8), ++ snd_usb_ctrl_intf(ctrl_intf) | (selector_id << 8), + &pin, sizeof(pin)); + if (ret < 0) + return ret; +@@ -132,7 +140,7 @@ static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_i + return -EINVAL; + } + +- ret = uac_clock_selector_get_val(chip, selector_id); ++ ret = uac_clock_selector_get_val(chip, selector_id, iface_no); + if (ret < 0) + return ret; + +@@ -155,8 +163,10 @@ static bool uac_clock_source_is_valid_quirk(struct snd_usb_audio *chip, + unsigned char data; + struct usb_device *dev = chip->dev; + union uac23_clock_source_desc *cs_desc; ++ struct usb_host_interface *ctrl_intf; + +- cs_desc = snd_usb_find_clock_source(chip, source_id, fmt->protocol); ++ ctrl_intf = snd_usb_find_ctrl_interface(chip, fmt->iface); ++ cs_desc = snd_usb_find_clock_source(chip, source_id, fmt); + if (!cs_desc) + return false; + +@@ -191,7 +201,7 @@ static bool uac_clock_source_is_valid_quirk(struct snd_usb_audio *chip, + err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, + UAC2_CS_CONTROL_CLOCK_VALID << 8, +- snd_usb_ctrl_intf(chip) | (source_id << 8), ++ snd_usb_ctrl_intf(ctrl_intf) | (source_id << 8), + &data, sizeof(data)); + if (err < 0) { + dev_warn(&dev->dev, +@@ -217,8 +227,10 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, + struct usb_device *dev = chip->dev; + u32 bmControls; + union uac23_clock_source_desc *cs_desc; ++ struct usb_host_interface *ctrl_intf; + +- cs_desc = snd_usb_find_clock_source(chip, source_id, fmt->protocol); ++ ctrl_intf = snd_usb_find_ctrl_interface(chip, fmt->iface); ++ cs_desc = snd_usb_find_clock_source(chip, source_id, fmt); + if (!cs_desc) + return false; + +@@ -235,7 +247,7 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, + err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, + UAC2_CS_CONTROL_CLOCK_VALID << 8, +- snd_usb_ctrl_intf(chip) | (source_id << 8), ++ snd_usb_ctrl_intf(ctrl_intf) | (source_id << 8), + &data, sizeof(data)); + + if (err < 0) { +@@ -274,7 +286,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, + } + + /* first, see if the ID we're looking at is a clock source already */ +- source = snd_usb_find_clock_source(chip, entity_id, proto); ++ source = snd_usb_find_clock_source(chip, entity_id, fmt); + if (source) { + entity_id = GET_VAL(source, proto, bClockID); + if (validate && !uac_clock_source_is_valid(chip, fmt, +@@ -287,7 +299,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, + return entity_id; + } + +- selector = snd_usb_find_clock_selector(chip, entity_id, proto); ++ selector = snd_usb_find_clock_selector(chip, entity_id, fmt); + if (selector) { + pins = GET_VAL(selector, proto, bNrInPins); + clock_id = GET_VAL(selector, proto, bClockID); +@@ -317,7 +329,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, + + /* the entity ID we are looking at is a selector. + * find out what it currently selects */ +- ret = uac_clock_selector_get_val(chip, clock_id); ++ ret = uac_clock_selector_get_val(chip, clock_id, fmt->iface); + if (ret < 0) { + if (!chip->autoclock) + return ret; +@@ -346,7 +358,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, + if (chip->quirk_flags & QUIRK_FLAG_SKIP_CLOCK_SELECTOR || + !writeable) + return ret; +- err = uac_clock_selector_set_val(chip, entity_id, cur); ++ err = uac_clock_selector_set_val(chip, entity_id, cur, fmt->iface); + if (err < 0) { + if (pins == 1) { + usb_audio_dbg(chip, +@@ -377,7 +389,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, + if (ret < 0) + continue; + +- err = uac_clock_selector_set_val(chip, entity_id, i); ++ err = uac_clock_selector_set_val(chip, entity_id, i, fmt->iface); + if (err < 0) + continue; + +@@ -391,7 +403,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, + } + + /* FIXME: multipliers only act as pass-thru element for now */ +- multiplier = snd_usb_find_clock_multiplier(chip, entity_id, proto); ++ multiplier = snd_usb_find_clock_multiplier(chip, entity_id, fmt); + if (multiplier) + return __uac_clock_find_source(chip, fmt, + GET_VAL(multiplier, proto, bCSourceID), +@@ -491,11 +503,13 @@ static int get_sample_rate_v2v3(struct snd_usb_audio *chip, int iface, + struct usb_device *dev = chip->dev; + __le32 data; + int err; ++ struct usb_host_interface *ctrl_intf; + ++ ctrl_intf = snd_usb_find_ctrl_interface(chip, iface); + err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, + UAC2_CS_CONTROL_SAM_FREQ << 8, +- snd_usb_ctrl_intf(chip) | (clock << 8), ++ snd_usb_ctrl_intf(ctrl_intf) | (clock << 8), + &data, sizeof(data)); + if (err < 0) { + dev_warn(&dev->dev, "%d:%d: cannot get freq (v2/v3): err %d\n", +@@ -524,8 +538,10 @@ int snd_usb_set_sample_rate_v2v3(struct snd_usb_audio *chip, + __le32 data; + int err; + union uac23_clock_source_desc *cs_desc; ++ struct usb_host_interface *ctrl_intf; + +- cs_desc = snd_usb_find_clock_source(chip, clock, fmt->protocol); ++ ctrl_intf = snd_usb_find_ctrl_interface(chip, fmt->iface); ++ cs_desc = snd_usb_find_clock_source(chip, clock, fmt); + + if (!cs_desc) + return 0; +@@ -544,7 +560,7 @@ int snd_usb_set_sample_rate_v2v3(struct snd_usb_audio *chip, + err = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), UAC2_CS_CUR, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, + UAC2_CS_CONTROL_SAM_FREQ << 8, +- snd_usb_ctrl_intf(chip) | (clock << 8), ++ snd_usb_ctrl_intf(ctrl_intf) | (clock << 8), + &data, sizeof(data)); + if (err < 0) + return err; +diff --git a/sound/usb/format.c b/sound/usb/format.c +index 3b45d0ee76938..61c4aca8be09e 100644 +--- a/sound/usb/format.c ++++ b/sound/usb/format.c +@@ -548,7 +548,9 @@ static int parse_audio_format_rates_v2v3(struct snd_usb_audio *chip, + unsigned char tmp[2], *data; + int nr_triplets, data_size, ret = 0, ret_l6; + int clock = snd_usb_clock_find_source(chip, fp, false); ++ struct usb_host_interface *ctrl_intf; + ++ ctrl_intf = snd_usb_find_ctrl_interface(chip, fp->iface); + if (clock < 0) { + dev_err(&dev->dev, + "%s(): unable to find clock source (clock %d)\n", +@@ -560,7 +562,7 @@ static int parse_audio_format_rates_v2v3(struct snd_usb_audio *chip, + ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, + UAC2_CS_CONTROL_SAM_FREQ << 8, +- snd_usb_ctrl_intf(chip) | (clock << 8), ++ snd_usb_ctrl_intf(ctrl_intf) | (clock << 8), + tmp, sizeof(tmp)); + + if (ret < 0) { +@@ -595,7 +597,7 @@ static int parse_audio_format_rates_v2v3(struct snd_usb_audio *chip, + ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, + UAC2_CS_CONTROL_SAM_FREQ << 8, +- snd_usb_ctrl_intf(chip) | (clock << 8), ++ snd_usb_ctrl_intf(ctrl_intf) | (clock << 8), + data, data_size); + + if (ret < 0) { +diff --git a/sound/usb/helper.c b/sound/usb/helper.c +index bf80e55d013a8..72b671fb2c84c 100644 +--- a/sound/usb/helper.c ++++ b/sound/usb/helper.c +@@ -130,3 +130,37 @@ snd_usb_get_host_interface(struct snd_usb_audio *chip, int ifnum, int altsetting + return NULL; + return usb_altnum_to_altsetting(iface, altsetting); + } ++ ++int snd_usb_add_ctrl_interface_link(struct snd_usb_audio *chip, int ifnum, ++ int ctrlif) ++{ ++ struct usb_device *dev = chip->dev; ++ struct usb_host_interface *host_iface; ++ ++ if (chip->num_intf_to_ctrl >= MAX_CARD_INTERFACES) { ++ dev_info(&dev->dev, "Too many interfaces assigned to the single USB-audio card\n"); ++ return -EINVAL; ++ } ++ ++ /* find audiocontrol interface */ ++ host_iface = &usb_ifnum_to_if(dev, ctrlif)->altsetting[0]; ++ ++ chip->intf_to_ctrl[chip->num_intf_to_ctrl].interface = ifnum; ++ chip->intf_to_ctrl[chip->num_intf_to_ctrl].ctrl_intf = host_iface; ++ chip->num_intf_to_ctrl++; ++ ++ return 0; ++} ++ ++struct usb_host_interface *snd_usb_find_ctrl_interface(struct snd_usb_audio *chip, ++ int ifnum) ++{ ++ int i; ++ ++ for (i = 0; i < chip->num_intf_to_ctrl; ++i) ++ if (chip->intf_to_ctrl[i].interface == ifnum) ++ return chip->intf_to_ctrl[i].ctrl_intf; ++ ++ /* Fallback to first audiocontrol interface */ ++ return chip->ctrl_intf; ++} +diff --git a/sound/usb/helper.h b/sound/usb/helper.h +index e2b51ec96ec62..0372e050b3dc4 100644 +--- a/sound/usb/helper.h ++++ b/sound/usb/helper.h +@@ -17,6 +17,12 @@ unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip, + struct usb_host_interface * + snd_usb_get_host_interface(struct snd_usb_audio *chip, int ifnum, int altsetting); + ++int snd_usb_add_ctrl_interface_link(struct snd_usb_audio *chip, int ifnum, ++ int ctrlif); ++ ++struct usb_host_interface *snd_usb_find_ctrl_interface(struct snd_usb_audio *chip, ++ int ifnum); ++ + /* + * retrieve usb_interface descriptor from the host interface + * (conditional for compatibility with the older API) +@@ -28,9 +34,9 @@ snd_usb_get_host_interface(struct snd_usb_audio *chip, int ifnum, int altsetting + + #define snd_usb_get_speed(dev) ((dev)->speed) + +-static inline int snd_usb_ctrl_intf(struct snd_usb_audio *chip) ++static inline int snd_usb_ctrl_intf(struct usb_host_interface *ctrl_intf) + { +- return get_iface_desc(chip->ctrl_intf)->bInterfaceNumber; ++ return get_iface_desc(ctrl_intf)->bInterfaceNumber; + } + + /* in validate.c */ +diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c +index 197fd07e69edd..017b50322d88f 100644 +--- a/sound/usb/mixer.c ++++ b/sound/usb/mixer.c +@@ -728,7 +728,7 @@ static int get_cluster_channels_v3(struct mixer_build *state, unsigned int clust + UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR, + USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, + cluster_id, +- snd_usb_ctrl_intf(state->chip), ++ snd_usb_ctrl_intf(state->mixer->hostif), + &c_header, sizeof(c_header)); + if (err < 0) + goto error; +diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c +index 212b5e6443d88..1d8bf1ecfed44 100644 +--- a/sound/usb/mixer_quirks.c ++++ b/sound/usb/mixer_quirks.c +@@ -1043,7 +1043,7 @@ static int snd_ftu_eff_switch_init(struct usb_mixer_interface *mixer, + err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR, + USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, + pval & 0xff00, +- snd_usb_ctrl_intf(mixer->chip) | ((pval & 0xff) << 8), ++ snd_usb_ctrl_intf(mixer->hostif) | ((pval & 0xff) << 8), + value, 2); + if (err < 0) + return err; +@@ -1077,7 +1077,7 @@ static int snd_ftu_eff_switch_update(struct usb_mixer_elem_list *list) + UAC_SET_CUR, + USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, + pval & 0xff00, +- snd_usb_ctrl_intf(chip) | ((pval & 0xff) << 8), ++ snd_usb_ctrl_intf(list->mixer->hostif) | ((pval & 0xff) << 8), + value, 2); + snd_usb_unlock_shutdown(chip); + return err; +@@ -2115,24 +2115,25 @@ static int dell_dock_mixer_create(struct usb_mixer_interface *mixer) + return 0; + } + +-static void dell_dock_init_vol(struct snd_usb_audio *chip, int ch, int id) ++static void dell_dock_init_vol(struct usb_mixer_interface *mixer, int ch, int id) + { ++ struct snd_usb_audio *chip = mixer->chip; + u16 buf = 0; + + snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR, + USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, + (UAC_FU_VOLUME << 8) | ch, +- snd_usb_ctrl_intf(chip) | (id << 8), ++ snd_usb_ctrl_intf(mixer->hostif) | (id << 8), + &buf, 2); + } + + static int dell_dock_mixer_init(struct usb_mixer_interface *mixer) + { + /* fix to 0dB playback volumes */ +- dell_dock_init_vol(mixer->chip, 1, 16); +- dell_dock_init_vol(mixer->chip, 2, 16); +- dell_dock_init_vol(mixer->chip, 1, 19); +- dell_dock_init_vol(mixer->chip, 2, 19); ++ dell_dock_init_vol(mixer, 1, 16); ++ dell_dock_init_vol(mixer, 2, 16); ++ dell_dock_init_vol(mixer, 1, 19); ++ dell_dock_init_vol(mixer, 2, 19); + return 0; + } + +diff --git a/sound/usb/mixer_scarlett.c b/sound/usb/mixer_scarlett.c +index 0d6e4f15bf77c..ff548041679bb 100644 +--- a/sound/usb/mixer_scarlett.c ++++ b/sound/usb/mixer_scarlett.c +@@ -460,7 +460,7 @@ static int scarlett_ctl_meter_get(struct snd_kcontrol *kctl, + struct snd_usb_audio *chip = elem->head.mixer->chip; + unsigned char buf[2 * MAX_CHANNELS] = {0, }; + int wValue = (elem->control << 8) | elem->idx_off; +- int idx = snd_usb_ctrl_intf(chip) | (elem->head.id << 8); ++ int idx = snd_usb_ctrl_intf(elem->head.mixer->hostif) | (elem->head.id << 8); + int err; + + err = snd_usb_ctl_msg(chip->dev, +@@ -1002,7 +1002,7 @@ int snd_scarlett_controls_create(struct usb_mixer_interface *mixer) + err = snd_usb_ctl_msg(mixer->chip->dev, + usb_sndctrlpipe(mixer->chip->dev, 0), UAC2_CS_CUR, + USB_RECIP_INTERFACE | USB_TYPE_CLASS | +- USB_DIR_OUT, 0x0100, snd_usb_ctrl_intf(mixer->chip) | ++ USB_DIR_OUT, 0x0100, snd_usb_ctrl_intf(mixer->hostif) | + (0x29 << 8), sample_rate_buffer, 4); + if (err < 0) + return err; +diff --git a/sound/usb/power.c b/sound/usb/power.c +index 606a2cb23eab6..66bd4daa68fd5 100644 +--- a/sound/usb/power.c ++++ b/sound/usb/power.c +@@ -40,6 +40,7 @@ snd_usb_find_power_domain(struct usb_host_interface *ctrl_iface, + le16_to_cpu(pd_desc->waRecoveryTime1); + pd->pd_d2d0_rec = + le16_to_cpu(pd_desc->waRecoveryTime2); ++ pd->ctrl_iface = ctrl_iface; + return pd; + } + } +@@ -57,7 +58,7 @@ int snd_usb_power_domain_set(struct snd_usb_audio *chip, + unsigned char current_state; + int err, idx; + +- idx = snd_usb_ctrl_intf(chip) | (pd->pd_id << 8); ++ idx = snd_usb_ctrl_intf(pd->ctrl_iface) | (pd->pd_id << 8); + + err = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), + UAC2_CS_CUR, +diff --git a/sound/usb/power.h b/sound/usb/power.h +index 396e3e51440a7..1fa92ad0ca925 100644 +--- a/sound/usb/power.h ++++ b/sound/usb/power.h +@@ -6,6 +6,7 @@ struct snd_usb_power_domain { + int pd_id; /* UAC3 Power Domain ID */ + int pd_d1d0_rec; /* D1 to D0 recovery time */ + int pd_d2d0_rec; /* D2 to D0 recovery time */ ++ struct usb_host_interface *ctrl_iface; /* Control interface */ + }; + + enum { +diff --git a/sound/usb/stream.c b/sound/usb/stream.c +index e14c725acebf2..d70c140813d68 100644 +--- a/sound/usb/stream.c ++++ b/sound/usb/stream.c +@@ -713,10 +713,13 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip, + struct usb_device *dev = chip->dev; + struct uac_format_type_i_continuous_descriptor *fmt; + unsigned int num_channels = 0, chconfig = 0; ++ struct usb_host_interface *ctrl_intf; + struct audioformat *fp; + int clock = 0; + u64 format; + ++ ctrl_intf = snd_usb_find_ctrl_interface(chip, iface_no); ++ + /* get audio formats */ + if (protocol == UAC_VERSION_1) { + struct uac1_as_header_descriptor *as = +@@ -740,7 +743,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip, + + format = le16_to_cpu(as->wFormatTag); /* remember the format value */ + +- iterm = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, ++ iterm = snd_usb_find_input_terminal_descriptor(ctrl_intf, + as->bTerminalLink, + protocol); + if (iterm) { +@@ -776,7 +779,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip, + * lookup the terminal associated to this interface + * to extract the clock + */ +- input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, ++ input_term = snd_usb_find_input_terminal_descriptor(ctrl_intf, + as->bTerminalLink, + protocol); + if (input_term) { +@@ -786,7 +789,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip, + goto found_clock; + } + +- output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf, ++ output_term = snd_usb_find_output_terminal_descriptor(ctrl_intf, + as->bTerminalLink, + protocol); + if (output_term) { +@@ -870,6 +873,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, + struct uac3_cluster_header_descriptor *cluster; + struct uac3_as_header_descriptor *as = NULL; + struct uac3_hc_descriptor_header hc_header; ++ struct usb_host_interface *ctrl_intf; + struct snd_pcm_chmap_elem *chmap; + struct snd_usb_power_domain *pd; + unsigned char badd_profile; +@@ -881,6 +885,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, + int err; + + badd_profile = chip->badd_profile; ++ ctrl_intf = snd_usb_find_ctrl_interface(chip, iface_no); + + if (badd_profile >= UAC3_FUNCTION_SUBCLASS_GENERIC_IO) { + unsigned int maxpacksize = +@@ -966,7 +971,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, + UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR, + USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, + cluster_id, +- snd_usb_ctrl_intf(chip), ++ snd_usb_ctrl_intf(ctrl_intf), + &hc_header, sizeof(hc_header)); + if (err < 0) + return ERR_PTR(err); +@@ -990,7 +995,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, + UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR, + USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, + cluster_id, +- snd_usb_ctrl_intf(chip), ++ snd_usb_ctrl_intf(ctrl_intf), + cluster, wLength); + if (err < 0) { + kfree(cluster); +@@ -1011,7 +1016,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, + * lookup the terminal associated to this interface + * to extract the clock + */ +- input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, ++ input_term = snd_usb_find_input_terminal_descriptor(ctrl_intf, + as->bTerminalLink, + UAC_VERSION_3); + if (input_term) { +@@ -1019,7 +1024,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, + goto found_clock; + } + +- output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf, ++ output_term = snd_usb_find_output_terminal_descriptor(ctrl_intf, + as->bTerminalLink, + UAC_VERSION_3); + if (output_term) { +@@ -1068,7 +1073,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, + UAC_VERSION_3, + iface_no); + +- pd = snd_usb_find_power_domain(chip->ctrl_intf, ++ pd = snd_usb_find_power_domain(ctrl_intf, + as->bTerminalLink); + + /* ok, let's parse further... */ +diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h +index 43d4029edab46..b0f042c996087 100644 +--- a/sound/usb/usbaudio.h ++++ b/sound/usb/usbaudio.h +@@ -21,6 +21,15 @@ struct media_intf_devnode; + + #define MAX_CARD_INTERFACES 16 + ++/* ++ * Structure holding assosiation between Audio Control Interface ++ * and given Streaming or Midi Interface. ++ */ ++struct snd_intf_to_ctrl { ++ u8 interface; ++ struct usb_host_interface *ctrl_intf; ++}; ++ + struct snd_usb_audio { + int index; + struct usb_device *dev; +@@ -63,6 +72,9 @@ struct snd_usb_audio { + struct usb_host_interface *ctrl_intf; /* the audio control interface */ + struct media_device *media_dev; + struct media_intf_devnode *ctl_intf_media_devnode; ++ ++ unsigned int num_intf_to_ctrl; ++ struct snd_intf_to_ctrl intf_to_ctrl[MAX_CARD_INTERFACES]; + }; + + #define USB_AUDIO_IFACE_UNUSED ((void *)-1L) +-- +2.43.0 + diff --git a/queue-6.10/arm64-trans_pgd-mark-ptes-entries-as-valid-to-avoid-.patch b/queue-6.10/arm64-trans_pgd-mark-ptes-entries-as-valid-to-avoid-.patch new file mode 100644 index 00000000000..49ef0c86a35 --- /dev/null +++ b/queue-6.10/arm64-trans_pgd-mark-ptes-entries-as-valid-to-avoid-.patch @@ -0,0 +1,62 @@ +From ef4df77fdc02e20156f224327fa9c6bef48c8477 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Fares Mehanna +Link: https://lore.kernel.org/r/20240902163309.97113-1-faresx@amazon.de +Signed-off-by: Will Deacon +Signed-off-by: Sasha Levin +--- + arch/arm64/mm/trans_pgd.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/mm/trans_pgd.c b/arch/arm64/mm/trans_pgd.c +index 5139a28130c08..0f7b484cb2ff2 100644 +--- a/arch/arm64/mm/trans_pgd.c ++++ b/arch/arm64/mm/trans_pgd.c +@@ -42,14 +42,16 @@ static void _copy_pte(pte_t *dst_ptep, pte_t *src_ptep, unsigned long addr) + * the temporary mappings we use during restore. + */ + __set_pte(dst_ptep, pte_mkwrite_novma(pte)); +- } else if ((debug_pagealloc_enabled() || +- is_kfence_address((void *)addr)) && !pte_none(pte)) { ++ } else if (!pte_none(pte)) { + /* + * debug_pagealloc will removed the PTE_VALID bit if + * the page isn't in use by the resume kernel. It may have + * been in use by the original kernel, in which case we need + * to put it back in our copy to do the restore. + * ++ * Other cases include kfence / vmalloc / memfd_secret which ++ * may call `set_direct_map_invalid_noflush()`. ++ * + * Before marking this entry valid, check the pfn should + * be mapped. + */ +-- +2.43.0 + diff --git a/queue-6.10/asoc-codecs-wsa883x-handle-reading-version-failure.patch b/queue-6.10/asoc-codecs-wsa883x-handle-reading-version-failure.patch new file mode 100644 index 00000000000..9a6892b13c7 --- /dev/null +++ b/queue-6.10/asoc-codecs-wsa883x-handle-reading-version-failure.patch @@ -0,0 +1,72 @@ +From 09cce4885acc9400a4036e876167f112d26277a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 10 Jul 2024 15:52:31 +0200 +Subject: ASoC: codecs: wsa883x: Handle reading version failure + +From: Krzysztof Kozlowski + +[ Upstream commit 2fbf16992e5aa14acf0441320033a01a32309ded ] + +If reading version and variant from registers fails (which is unlikely +but possible, because it is a read over bus), the driver will proceed +and perform device configuration based on uninitialized stack variables. +Handle it a bit better - bail out without doing any init and failing the +update status Soundwire callback. + +Signed-off-by: Krzysztof Kozlowski +Link: https://patch.msgid.link/20240710-asoc-wsa88xx-version-v1-2-f1c54966ccde@linaro.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/wsa883x.c | 16 +++++++++++----- + 1 file changed, 11 insertions(+), 5 deletions(-) + +diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c +index 2169d93989841..1831d4487ba9d 100644 +--- a/sound/soc/codecs/wsa883x.c ++++ b/sound/soc/codecs/wsa883x.c +@@ -998,15 +998,19 @@ static const struct reg_sequence reg_init[] = { + {WSA883X_GMAMP_SUP1, 0xE2}, + }; + +-static void wsa883x_init(struct wsa883x_priv *wsa883x) ++static int wsa883x_init(struct wsa883x_priv *wsa883x) + { + struct regmap *regmap = wsa883x->regmap; +- int variant, version; ++ int variant, version, ret; + +- regmap_read(regmap, WSA883X_OTP_REG_0, &variant); ++ ret = regmap_read(regmap, WSA883X_OTP_REG_0, &variant); ++ if (ret) ++ return ret; + wsa883x->variant = variant & WSA883X_ID_MASK; + +- regmap_read(regmap, WSA883X_CHIP_ID0, &version); ++ ret = regmap_read(regmap, WSA883X_CHIP_ID0, &version); ++ if (ret) ++ return ret; + wsa883x->version = version; + + switch (wsa883x->variant) { +@@ -1041,6 +1045,8 @@ static void wsa883x_init(struct wsa883x_priv *wsa883x) + WSA883X_DRE_OFFSET_MASK, + wsa883x->comp_offset); + } ++ ++ return 0; + } + + static int wsa883x_update_status(struct sdw_slave *slave, +@@ -1049,7 +1055,7 @@ static int wsa883x_update_status(struct sdw_slave *slave, + struct wsa883x_priv *wsa883x = dev_get_drvdata(&slave->dev); + + if (status == SDW_SLAVE_ATTACHED && slave->dev_num > 0) +- wsa883x_init(wsa883x); ++ return wsa883x_init(wsa883x); + + return 0; + } +-- +2.43.0 + diff --git a/queue-6.10/asoc-intel-boards-always-check-the-result-of-acpi_de.patch b/queue-6.10/asoc-intel-boards-always-check-the-result-of-acpi_de.patch new file mode 100644 index 00000000000..1756f032bbd --- /dev/null +++ b/queue-6.10/asoc-intel-boards-always-check-the-result-of-acpi_de.patch @@ -0,0 +1,174 @@ +From cee6740c36aaef52bf86b3e1691b4ec8aceed96c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Closes: https://lore.kernel.org/alsa-devel/918944d2-3d00-465e-a9d1-5d57fc966113@stanley.mountain/T/#u +Signed-off-by: Pierre-Louis Bossart +Reviewed-by: Péter Ujfalusi +Signed-off-by: Bard Liao +Link: https://patch.msgid.link/20240827123215.258859-4-yung-chuan.liao@linux.intel.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/intel/boards/bytcht_cx2072x.c | 4 ++++ + sound/soc/intel/boards/bytcht_da7213.c | 4 ++++ + sound/soc/intel/boards/bytcht_es8316.c | 2 +- + sound/soc/intel/boards/bytcr_rt5640.c | 2 +- + sound/soc/intel/boards/bytcr_rt5651.c | 2 +- + sound/soc/intel/boards/cht_bsw_rt5645.c | 4 ++++ + sound/soc/intel/boards/cht_bsw_rt5672.c | 4 ++++ + sound/soc/intel/boards/sof_es8336.c | 2 +- + sound/soc/intel/boards/sof_wm8804.c | 4 ++++ + 9 files changed, 24 insertions(+), 4 deletions(-) + +diff --git a/sound/soc/intel/boards/bytcht_cx2072x.c b/sound/soc/intel/boards/bytcht_cx2072x.c +index df3c2a7b64d23..8c2b4ab764bba 100644 +--- a/sound/soc/intel/boards/bytcht_cx2072x.c ++++ b/sound/soc/intel/boards/bytcht_cx2072x.c +@@ -255,7 +255,11 @@ static int snd_byt_cht_cx2072x_probe(struct platform_device *pdev) + snprintf(codec_name, sizeof(codec_name), "i2c-%s", + acpi_dev_name(adev)); + byt_cht_cx2072x_dais[dai_index].codecs->name = codec_name; ++ } else { ++ dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id); ++ return -ENOENT; + } ++ + acpi_dev_put(adev); + + /* override platform name, if required */ +diff --git a/sound/soc/intel/boards/bytcht_da7213.c b/sound/soc/intel/boards/bytcht_da7213.c +index 08c598b7e1eee..9178bbe8d9950 100644 +--- a/sound/soc/intel/boards/bytcht_da7213.c ++++ b/sound/soc/intel/boards/bytcht_da7213.c +@@ -258,7 +258,11 @@ static int bytcht_da7213_probe(struct platform_device *pdev) + snprintf(codec_name, sizeof(codec_name), + "i2c-%s", acpi_dev_name(adev)); + dailink[dai_index].codecs->name = codec_name; ++ } else { ++ dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id); ++ return -ENOENT; + } ++ + acpi_dev_put(adev); + + /* override platform name, if required */ +diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c +index 77b91ea4dc32c..3539c9ff0fd2c 100644 +--- a/sound/soc/intel/boards/bytcht_es8316.c ++++ b/sound/soc/intel/boards/bytcht_es8316.c +@@ -562,7 +562,7 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) + byt_cht_es8316_dais[dai_index].codecs->name = codec_name; + } else { + dev_err(dev, "Error cannot find '%s' dev\n", mach->id); +- return -ENXIO; ++ return -ENOENT; + } + + codec_dev = acpi_get_first_physical_node(adev); +diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c +index db4a33680d948..4479825c08b5e 100644 +--- a/sound/soc/intel/boards/bytcr_rt5640.c ++++ b/sound/soc/intel/boards/bytcr_rt5640.c +@@ -1693,7 +1693,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) + byt_rt5640_dais[dai_index].codecs->name = byt_rt5640_codec_name; + } else { + dev_err(dev, "Error cannot find '%s' dev\n", mach->id); +- return -ENXIO; ++ return -ENOENT; + } + + codec_dev = acpi_get_first_physical_node(adev); +diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c +index 8514b79f389bb..1f54da98aacf4 100644 +--- a/sound/soc/intel/boards/bytcr_rt5651.c ++++ b/sound/soc/intel/boards/bytcr_rt5651.c +@@ -926,7 +926,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) + byt_rt5651_dais[dai_index].codecs->name = byt_rt5651_codec_name; + } else { + dev_err(dev, "Error cannot find '%s' dev\n", mach->id); +- return -ENXIO; ++ return -ENOENT; + } + + codec_dev = acpi_get_first_physical_node(adev); +diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c +index 1da9ceee4d593..ac23a8b7cafca 100644 +--- a/sound/soc/intel/boards/cht_bsw_rt5645.c ++++ b/sound/soc/intel/boards/cht_bsw_rt5645.c +@@ -582,7 +582,11 @@ static int snd_cht_mc_probe(struct platform_device *pdev) + snprintf(cht_rt5645_codec_name, sizeof(cht_rt5645_codec_name), + "i2c-%s", acpi_dev_name(adev)); + cht_dailink[dai_index].codecs->name = cht_rt5645_codec_name; ++ } else { ++ dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id); ++ return -ENOENT; + } ++ + /* acpi_get_first_physical_node() returns a borrowed ref, no need to deref */ + codec_dev = acpi_get_first_physical_node(adev); + acpi_dev_put(adev); +diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c +index d68e5bc755dee..c6c469d51243e 100644 +--- a/sound/soc/intel/boards/cht_bsw_rt5672.c ++++ b/sound/soc/intel/boards/cht_bsw_rt5672.c +@@ -479,7 +479,11 @@ static int snd_cht_mc_probe(struct platform_device *pdev) + snprintf(drv->codec_name, sizeof(drv->codec_name), + "i2c-%s", acpi_dev_name(adev)); + cht_dailink[dai_index].codecs->name = drv->codec_name; ++ } else { ++ dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id); ++ return -ENOENT; + } ++ + acpi_dev_put(adev); + + /* Use SSP0 on Bay Trail CR devices */ +diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c +index c1fcc156a5752..809532238c44f 100644 +--- a/sound/soc/intel/boards/sof_es8336.c ++++ b/sound/soc/intel/boards/sof_es8336.c +@@ -681,7 +681,7 @@ static int sof_es8336_probe(struct platform_device *pdev) + dai_links[0].codecs->dai_name = "ES8326 HiFi"; + } else { + dev_err(dev, "Error cannot find '%s' dev\n", mach->id); +- return -ENXIO; ++ return -ENOENT; + } + + codec_dev = acpi_get_first_physical_node(adev); +diff --git a/sound/soc/intel/boards/sof_wm8804.c b/sound/soc/intel/boards/sof_wm8804.c +index 4cb0d463bf404..9c5b3f8f09f36 100644 +--- a/sound/soc/intel/boards/sof_wm8804.c ++++ b/sound/soc/intel/boards/sof_wm8804.c +@@ -270,7 +270,11 @@ static int sof_wm8804_probe(struct platform_device *pdev) + snprintf(codec_name, sizeof(codec_name), + "%s%s", "i2c-", acpi_dev_name(adev)); + dailink[dai_index].codecs->name = codec_name; ++ } else { ++ dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id); ++ return -ENOENT; + } ++ + acpi_dev_put(adev); + + snd_soc_card_set_drvdata(card, ctx); +-- +2.43.0 + diff --git a/queue-6.10/ata-pata_serverworks-do-not-use-the-term-blacklist.patch b/queue-6.10/ata-pata_serverworks-do-not-use-the-term-blacklist.patch new file mode 100644 index 00000000000..572b57e186a --- /dev/null +++ b/queue-6.10/ata-pata_serverworks-do-not-use-the-term-blacklist.patch @@ -0,0 +1,65 @@ +From 893be2b55594d369e87cf9e3dea8fc26ec0cc178 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Jul 2024 10:58:36 +0900 +Subject: ata: pata_serverworks: Do not use the term blacklist + +From: Damien Le Moal + +[ Upstream commit 858048568c9e3887d8b19e101ee72f129d65cb15 ] + +Let's not use the term blacklist in the function +serverworks_osb4_filter() documentation comment and rather simply refer +to what that function looks at: the list of devices with groken UDMA5. + +While at it, also constify the values of the csb_bad_ata100 array. + +Of note is that all of this should probably be handled using libata +quirk mechanism but it is unclear if these UDMA5 quirks are specific +to this controller only. + +Signed-off-by: Damien Le Moal +Reviewed-by: Niklas Cassel +Reviewed-by: Igor Pylypiv +Signed-off-by: Sasha Levin +--- + drivers/ata/pata_serverworks.c | 16 +++++++++------- + 1 file changed, 9 insertions(+), 7 deletions(-) + +diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c +index 549ff24a98231..4edddf6bcc150 100644 +--- a/drivers/ata/pata_serverworks.c ++++ b/drivers/ata/pata_serverworks.c +@@ -46,10 +46,11 @@ + #define SVWKS_CSB5_REVISION_NEW 0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */ + #define SVWKS_CSB6_REVISION 0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */ + +-/* Seagate Barracuda ATA IV Family drives in UDMA mode 5 +- * can overrun their FIFOs when used with the CSB5 */ +- +-static const char *csb_bad_ata100[] = { ++/* ++ * Seagate Barracuda ATA IV Family drives in UDMA mode 5 ++ * can overrun their FIFOs when used with the CSB5. ++ */ ++static const char * const csb_bad_ata100[] = { + "ST320011A", + "ST340016A", + "ST360021A", +@@ -163,10 +164,11 @@ static unsigned int serverworks_osb4_filter(struct ata_device *adev, unsigned in + * @adev: ATA device + * @mask: Mask of proposed modes + * +- * Check the blacklist and disable UDMA5 if matched ++ * Check the list of devices with broken UDMA5 and ++ * disable UDMA5 if matched. + */ +- +-static unsigned int serverworks_csb_filter(struct ata_device *adev, unsigned int mask) ++static unsigned int serverworks_csb_filter(struct ata_device *adev, ++ unsigned int mask) + { + const char *p; + char model_num[ATA_ID_PROD_LEN + 1]; +-- +2.43.0 + diff --git a/queue-6.10/ata-sata_sil-rename-sil_blacklist-to-sil_quirks.patch b/queue-6.10/ata-sata_sil-rename-sil_blacklist-to-sil_quirks.patch new file mode 100644 index 00000000000..48e55d223dd --- /dev/null +++ b/queue-6.10/ata-sata_sil-rename-sil_blacklist-to-sil_quirks.patch @@ -0,0 +1,61 @@ +From 62ee2a44cced011ddb078e8b2c363a85b5be5662 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Jul 2024 11:14:11 +0900 +Subject: ata: sata_sil: Rename sil_blacklist to sil_quirks + +From: Damien Le Moal + +[ Upstream commit 93b0f9e11ce511353c65b7f924cf5f95bd9c3aba ] + +Rename the array sil_blacklist to sil_quirks as this name is more +neutral and is also consistent with how this driver define quirks with +the SIL_QUIRK_XXX flags. + +Signed-off-by: Damien Le Moal +Reviewed-by: Niklas Cassel +Reviewed-by: Igor Pylypiv +Signed-off-by: Sasha Levin +--- + drivers/ata/sata_sil.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c +index cc77c02482843..df095659bae0f 100644 +--- a/drivers/ata/sata_sil.c ++++ b/drivers/ata/sata_sil.c +@@ -128,7 +128,7 @@ static const struct pci_device_id sil_pci_tbl[] = { + static const struct sil_drivelist { + const char *product; + unsigned int quirk; +-} sil_blacklist [] = { ++} sil_quirks[] = { + { "ST320012AS", SIL_QUIRK_MOD15WRITE }, + { "ST330013AS", SIL_QUIRK_MOD15WRITE }, + { "ST340017AS", SIL_QUIRK_MOD15WRITE }, +@@ -600,8 +600,8 @@ static void sil_thaw(struct ata_port *ap) + * list, and apply the fixups to only the specific + * devices/hosts/firmwares that need it. + * +- * 20040111 - Seagate drives affected by the Mod15Write bug are blacklisted +- * The Maxtor quirk is in the blacklist, but I'm keeping the original ++ * 20040111 - Seagate drives affected by the Mod15Write bug are quirked ++ * The Maxtor quirk is in sil_quirks, but I'm keeping the original + * pessimistic fix for the following reasons... + * - There seems to be less info on it, only one device gleaned off the + * Windows driver, maybe only one is affected. More info would be greatly +@@ -620,9 +620,9 @@ static void sil_dev_config(struct ata_device *dev) + + ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num)); + +- for (n = 0; sil_blacklist[n].product; n++) +- if (!strcmp(sil_blacklist[n].product, model_num)) { +- quirks = sil_blacklist[n].quirk; ++ for (n = 0; sil_quirks[n].product; n++) ++ if (!strcmp(sil_quirks[n].product, model_num)) { ++ quirks = sil_quirks[n].quirk; + break; + } + +-- +2.43.0 + diff --git a/queue-6.10/blk_iocost-fix-more-out-of-bound-shifts.patch b/queue-6.10/blk_iocost-fix-more-out-of-bound-shifts.patch new file mode 100644 index 00000000000..68802821c1e --- /dev/null +++ b/queue-6.10/blk_iocost-fix-more-out-of-bound-shifts.patch @@ -0,0 +1,80 @@ +From c82b11c13ccf00d24d38b7e229563abeb2db305e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Aug 2024 08:41:36 -0700 +Subject: blk_iocost: fix more out of bound shifts + +From: Konstantin Ovsepian + +[ Upstream commit 9bce8005ec0dcb23a58300e8522fe4a31da606fa ] + +Recently running UBSAN caught few out of bound shifts in the +ioc_forgive_debts() function: + +UBSAN: shift-out-of-bounds in block/blk-iocost.c:2142:38 +shift exponent 80 is too large for 64-bit type 'u64' (aka 'unsigned long +long') +... +UBSAN: shift-out-of-bounds in block/blk-iocost.c:2144:30 +shift exponent 80 is too large for 64-bit type 'u64' (aka 'unsigned long +long') +... +Call Trace: + +dump_stack_lvl+0xca/0x130 +__ubsan_handle_shift_out_of_bounds+0x22c/0x280 +? __lock_acquire+0x6441/0x7c10 +ioc_timer_fn+0x6cec/0x7750 +? blk_iocost_init+0x720/0x720 +? call_timer_fn+0x5d/0x470 +call_timer_fn+0xfa/0x470 +? blk_iocost_init+0x720/0x720 +__run_timer_base+0x519/0x700 +... + +Actual impact of this issue was not identified but I propose to fix the +undefined behaviour. +The proposed fix to prevent those out of bound shifts consist of +precalculating exponent before using it the shift operations by taking +min value from the actual exponent and maximum possible number of bits. + +Reported-by: Breno Leitao +Signed-off-by: Konstantin Ovsepian +Acked-by: Tejun Heo +Link: https://lore.kernel.org/r/20240822154137.2627818-1-ovs@ovs.to +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/blk-iocost.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/block/blk-iocost.c b/block/blk-iocost.c +index 690ca99dfaca6..5a6098a3db57e 100644 +--- a/block/blk-iocost.c ++++ b/block/blk-iocost.c +@@ -2076,7 +2076,7 @@ static void ioc_forgive_debts(struct ioc *ioc, u64 usage_us_sum, int nr_debtors, + struct ioc_now *now) + { + struct ioc_gq *iocg; +- u64 dur, usage_pct, nr_cycles; ++ u64 dur, usage_pct, nr_cycles, nr_cycles_shift; + + /* if no debtor, reset the cycle */ + if (!nr_debtors) { +@@ -2138,10 +2138,12 @@ static void ioc_forgive_debts(struct ioc *ioc, u64 usage_us_sum, int nr_debtors, + old_debt = iocg->abs_vdebt; + old_delay = iocg->delay; + ++ nr_cycles_shift = min_t(u64, nr_cycles, BITS_PER_LONG - 1); + if (iocg->abs_vdebt) +- iocg->abs_vdebt = iocg->abs_vdebt >> nr_cycles ?: 1; ++ iocg->abs_vdebt = iocg->abs_vdebt >> nr_cycles_shift ?: 1; ++ + if (iocg->delay) +- iocg->delay = iocg->delay >> nr_cycles ?: 1; ++ iocg->delay = iocg->delay >> nr_cycles_shift ?: 1; + + iocg_kick_waitq(iocg, true, now); + +-- +2.43.0 + diff --git a/queue-6.10/block-fix-integer-overflow-in-blksecdiscard.patch b/queue-6.10/block-fix-integer-overflow-in-blksecdiscard.patch new file mode 100644 index 00000000000..e26ad673574 --- /dev/null +++ b/queue-6.10/block-fix-integer-overflow-in-blksecdiscard.patch @@ -0,0 +1,75 @@ +From 5739969a5ed222459f95efdda581664b8b8498c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Sep 2024 22:48:19 +0300 +Subject: block: fix integer overflow in BLKSECDISCARD + +From: Alexey Dobriyan + +[ 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 +Link: https://lore.kernel.org/r/9e64057f-650a-46d1-b9f7-34af391536ef@p183 +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/ioctl.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/block/ioctl.c b/block/ioctl.c +index d570e16958961..4515d4679eefd 100644 +--- a/block/ioctl.c ++++ b/block/ioctl.c +@@ -126,7 +126,7 @@ static int blk_ioctl_discard(struct block_device *bdev, blk_mode_t mode, + return -EINVAL; + + filemap_invalidate_lock(bdev->bd_mapping); +- err = truncate_bdev_range(bdev, mode, start, start + len - 1); ++ err = truncate_bdev_range(bdev, mode, start, end - 1); + if (err) + goto fail; + +@@ -163,7 +163,7 @@ static int blk_ioctl_discard(struct block_device *bdev, blk_mode_t mode, + static int blk_ioctl_secure_erase(struct block_device *bdev, blk_mode_t mode, + void __user *argp) + { +- uint64_t start, len; ++ uint64_t start, len, end; + uint64_t range[2]; + int err; + +@@ -178,11 +178,12 @@ static int blk_ioctl_secure_erase(struct block_device *bdev, blk_mode_t mode, + len = range[1]; + if ((start & 511) || (len & 511)) + return -EINVAL; +- if (start + len > bdev_nr_bytes(bdev)) ++ if (check_add_overflow(start, len, &end) || ++ end > bdev_nr_bytes(bdev)) + return -EINVAL; + + filemap_invalidate_lock(bdev->bd_mapping); +- err = truncate_bdev_range(bdev, mode, start, start + len - 1); ++ err = truncate_bdev_range(bdev, mode, start, end - 1); + if (!err) + err = blkdev_issue_secure_erase(bdev, start >> 9, len >> 9, + GFP_KERNEL); +-- +2.43.0 + diff --git a/queue-6.10/bluetooth-btrtl-set-msft-ext-address-filter-quirk-fo.patch b/queue-6.10/bluetooth-btrtl-set-msft-ext-address-filter-quirk-fo.patch new file mode 100644 index 00000000000..b5d859cc646 --- /dev/null +++ b/queue-6.10/bluetooth-btrtl-set-msft-ext-address-filter-quirk-fo.patch @@ -0,0 +1,42 @@ +From 2fd8584d645edb1da5ff96ab4845cbbdd4abd5a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Aug 2024 16:40:05 +0800 +Subject: Bluetooth: btrtl: Set msft ext address filter quirk for RTL8852B + +From: Hilda Wu + +[ Upstream commit 9a0570948c5def5c59e588dc0e009ed850a1f5a1 ] + +For tracking multiple devices concurrently with a condition. +The patch enables the HCI_QUIRK_USE_MSFT_EXT_ADDRESS_FILTER quirk +on RTL8852B controller. + +The quirk setting is based on commit 9e14606d8f38 ("Bluetooth: msft: +Extended monitor tracking by address filter") + +With this setting, when a pattern monitor detects a device, this +feature issues an address monitor for tracking that device. Let the +original pattern monitor keep monitor new devices. + +Signed-off-by: Hilda Wu +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btrtl.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c +index bfcb41a57655f..78b5d44558d73 100644 +--- a/drivers/bluetooth/btrtl.c ++++ b/drivers/bluetooth/btrtl.c +@@ -1296,6 +1296,7 @@ void btrtl_set_quirks(struct hci_dev *hdev, struct btrtl_device_info *btrtl_dev) + btrealtek_set_flag(hdev, REALTEK_ALT6_CONTINUOUS_TX_CHIP); + + if (btrtl_dev->project_id == CHIP_ID_8852A || ++ btrtl_dev->project_id == CHIP_ID_8852B || + btrtl_dev->project_id == CHIP_ID_8852C) + set_bit(HCI_QUIRK_USE_MSFT_EXT_ADDRESS_FILTER, &hdev->quirks); + +-- +2.43.0 + diff --git a/queue-6.10/bluetooth-btusb-add-realtek-rtl8852c-support-id-0x04.patch b/queue-6.10/bluetooth-btusb-add-realtek-rtl8852c-support-id-0x04.patch new file mode 100644 index 00000000000..1c2b65ee96d --- /dev/null +++ b/queue-6.10/bluetooth-btusb-add-realtek-rtl8852c-support-id-0x04.patch @@ -0,0 +1,67 @@ +From ad42832760001ef079cda6ad2f60244dee4acf02 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Aug 2024 16:58:22 +0800 +Subject: Bluetooth: btusb: Add Realtek RTL8852C support ID 0x0489:0xe122 + +From: Hilda Wu + +[ Upstream commit bdf9557f70e7512bb2f754abf90d9e9958745316 ] + +Add the support ID (0x0489, 0xe122) to usb_device_id table for +Realtek RTL8852C. + +The device info from /sys/kernel/debug/usb/devices as below. + +T: Bus=03 Lev=01 Prnt=01 Port=02 Cnt=01 Dev#= 2 Spd=12 MxCh= 0 +D: Ver= 1.00 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 +P: Vendor=0489 ProdID=e122 Rev= 0.00 +S: Manufacturer=Realtek +S: Product=Bluetooth Radio +S: SerialNumber=00e04c000001 +C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=500mA +I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms +E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms +E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms +I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms +E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms +I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms +E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms +I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms +E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms +I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms +E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms +I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms +E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms +I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms +E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms + +Signed-off-by: Hilda Wu +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btusb.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index c41b86608ba86..dd7d9b7fd1c42 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -539,6 +539,8 @@ static const struct usb_device_id quirks_table[] = { + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x13d3, 0x3592), .driver_info = BTUSB_REALTEK | + BTUSB_WIDEBAND_SPEECH }, ++ { USB_DEVICE(0x0489, 0xe122), .driver_info = BTUSB_REALTEK | ++ BTUSB_WIDEBAND_SPEECH }, + + /* Realtek 8852BE Bluetooth devices */ + { USB_DEVICE(0x0cb8, 0xc559), .driver_info = BTUSB_REALTEK | +-- +2.43.0 + diff --git a/queue-6.10/bnxt_en-extend-maximum-length-of-version-string-by-1.patch b/queue-6.10/bnxt_en-extend-maximum-length-of-version-string-by-1.patch new file mode 100644 index 00000000000..d85fdfa6cd7 --- /dev/null +++ b/queue-6.10/bnxt_en-extend-maximum-length-of-version-string-by-1.patch @@ -0,0 +1,42 @@ +From 1b72f78b090785489e61a0e8854f5cfcdcf55b30 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Aug 2024 15:32:55 +0100 +Subject: bnxt_en: Extend maximum length of version string by 1 byte + +From: Simon Horman + +[ Upstream commit ffff7ee843c351ce71d6e0d52f0f20bea35e18c9 ] + +This corrects an out-by-one error in the maximum length of the package +version string. The size argument of snprintf includes space for the +trailing '\0' byte, so there is no need to allow extra space for it by +reducing the value of the size argument by 1. + +Found by inspection. +Compile tested only. + +Signed-off-by: Simon Horman +Reviewed-by: Michael Chan +Link: https://patch.msgid.link/20240813-bnxt-str-v2-1-872050a157e7@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +index 79c09c1cdf936..0032c4ebd7e12 100644 +--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c ++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +@@ -4146,7 +4146,7 @@ static void bnxt_get_pkgver(struct net_device *dev) + + if (!bnxt_get_pkginfo(dev, buf, sizeof(buf))) { + len = strlen(bp->fw_ver_str); +- snprintf(bp->fw_ver_str + len, FW_VER_STR_LEN - len - 1, ++ snprintf(bp->fw_ver_str + len, FW_VER_STR_LEN - len, + "/pkg %s", buf); + } + } +-- +2.43.0 + diff --git a/queue-6.10/bpf-fix-a-sdiv-overflow-issue.patch b/queue-6.10/bpf-fix-a-sdiv-overflow-issue.patch new file mode 100644 index 00000000000..792a2f21fb5 --- /dev/null +++ b/queue-6.10/bpf-fix-a-sdiv-overflow-issue.patch @@ -0,0 +1,202 @@ +From 6ec44d4fe03d8a1df90bf0c47f5655f4883bc6aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Sep 2024 08:03:26 -0700 +Subject: bpf: Fix a sdiv overflow issue + +From: Yonghong Song + +[ 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 +Signed-off-by: Yonghong Song +Acked-by: Andrii Nakryiko +Link: https://lore.kernel.org/r/20240913150326.1187788-1-yonghong.song@linux.dev +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 93 +++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 89 insertions(+), 4 deletions(-) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index 4688dc82f8b06..eb4b4f5b1284f 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -19951,13 +19951,46 @@ static int do_misc_fixups(struct bpf_verifier_env *env) + /* Convert BPF_CLASS(insn->code) == BPF_ALU64 to 32-bit ALU */ + insn->code = BPF_ALU | BPF_OP(insn->code) | BPF_SRC(insn->code); + +- /* Make divide-by-zero exceptions impossible. */ ++ /* Make sdiv/smod divide-by-minus-one exceptions impossible. */ ++ if ((insn->code == (BPF_ALU64 | BPF_MOD | BPF_K) || ++ insn->code == (BPF_ALU64 | BPF_DIV | BPF_K) || ++ insn->code == (BPF_ALU | BPF_MOD | BPF_K) || ++ insn->code == (BPF_ALU | BPF_DIV | BPF_K)) && ++ insn->off == 1 && insn->imm == -1) { ++ bool is64 = BPF_CLASS(insn->code) == BPF_ALU64; ++ bool isdiv = BPF_OP(insn->code) == BPF_DIV; ++ struct bpf_insn *patchlet; ++ struct bpf_insn chk_and_sdiv[] = { ++ BPF_RAW_INSN((is64 ? BPF_ALU64 : BPF_ALU) | ++ BPF_NEG | BPF_K, insn->dst_reg, ++ 0, 0, 0), ++ }; ++ struct bpf_insn chk_and_smod[] = { ++ BPF_MOV32_IMM(insn->dst_reg, 0), ++ }; ++ ++ patchlet = isdiv ? chk_and_sdiv : chk_and_smod; ++ cnt = isdiv ? ARRAY_SIZE(chk_and_sdiv) : ARRAY_SIZE(chk_and_smod); ++ ++ new_prog = bpf_patch_insn_data(env, i + delta, patchlet, cnt); ++ if (!new_prog) ++ return -ENOMEM; ++ ++ delta += cnt - 1; ++ env->prog = prog = new_prog; ++ insn = new_prog->insnsi + i + delta; ++ goto next_insn; ++ } ++ ++ /* Make divide-by-zero and divide-by-minus-one exceptions impossible. */ + if (insn->code == (BPF_ALU64 | BPF_MOD | BPF_X) || + insn->code == (BPF_ALU64 | BPF_DIV | BPF_X) || + insn->code == (BPF_ALU | BPF_MOD | BPF_X) || + insn->code == (BPF_ALU | BPF_DIV | BPF_X)) { + bool is64 = BPF_CLASS(insn->code) == BPF_ALU64; + bool isdiv = BPF_OP(insn->code) == BPF_DIV; ++ bool is_sdiv = isdiv && insn->off == 1; ++ bool is_smod = !isdiv && insn->off == 1; + struct bpf_insn *patchlet; + struct bpf_insn chk_and_div[] = { + /* [R,W]x div 0 -> 0 */ +@@ -19977,10 +20010,62 @@ static int do_misc_fixups(struct bpf_verifier_env *env) + BPF_JMP_IMM(BPF_JA, 0, 0, 1), + BPF_MOV32_REG(insn->dst_reg, insn->dst_reg), + }; ++ struct bpf_insn chk_and_sdiv[] = { ++ /* [R,W]x sdiv 0 -> 0 ++ * LLONG_MIN sdiv -1 -> LLONG_MIN ++ * INT_MIN sdiv -1 -> INT_MIN ++ */ ++ BPF_MOV64_REG(BPF_REG_AX, insn->src_reg), ++ BPF_RAW_INSN((is64 ? BPF_ALU64 : BPF_ALU) | ++ BPF_ADD | BPF_K, BPF_REG_AX, ++ 0, 0, 1), ++ BPF_RAW_INSN((is64 ? BPF_JMP : BPF_JMP32) | ++ BPF_JGT | BPF_K, BPF_REG_AX, ++ 0, 4, 1), ++ BPF_RAW_INSN((is64 ? BPF_JMP : BPF_JMP32) | ++ BPF_JEQ | BPF_K, BPF_REG_AX, ++ 0, 1, 0), ++ BPF_RAW_INSN((is64 ? BPF_ALU64 : BPF_ALU) | ++ BPF_MOV | BPF_K, insn->dst_reg, ++ 0, 0, 0), ++ /* BPF_NEG(LLONG_MIN) == -LLONG_MIN == LLONG_MIN */ ++ BPF_RAW_INSN((is64 ? BPF_ALU64 : BPF_ALU) | ++ BPF_NEG | BPF_K, insn->dst_reg, ++ 0, 0, 0), ++ BPF_JMP_IMM(BPF_JA, 0, 0, 1), ++ *insn, ++ }; ++ struct bpf_insn chk_and_smod[] = { ++ /* [R,W]x mod 0 -> [R,W]x */ ++ /* [R,W]x mod -1 -> 0 */ ++ BPF_MOV64_REG(BPF_REG_AX, insn->src_reg), ++ BPF_RAW_INSN((is64 ? BPF_ALU64 : BPF_ALU) | ++ BPF_ADD | BPF_K, BPF_REG_AX, ++ 0, 0, 1), ++ BPF_RAW_INSN((is64 ? BPF_JMP : BPF_JMP32) | ++ BPF_JGT | BPF_K, BPF_REG_AX, ++ 0, 3, 1), ++ BPF_RAW_INSN((is64 ? BPF_JMP : BPF_JMP32) | ++ BPF_JEQ | BPF_K, BPF_REG_AX, ++ 0, 3 + (is64 ? 0 : 1), 1), ++ BPF_MOV32_IMM(insn->dst_reg, 0), ++ BPF_JMP_IMM(BPF_JA, 0, 0, 1), ++ *insn, ++ BPF_JMP_IMM(BPF_JA, 0, 0, 1), ++ BPF_MOV32_REG(insn->dst_reg, insn->dst_reg), ++ }; + +- patchlet = isdiv ? chk_and_div : chk_and_mod; +- cnt = isdiv ? ARRAY_SIZE(chk_and_div) : +- ARRAY_SIZE(chk_and_mod) - (is64 ? 2 : 0); ++ if (is_sdiv) { ++ patchlet = chk_and_sdiv; ++ cnt = ARRAY_SIZE(chk_and_sdiv); ++ } else if (is_smod) { ++ patchlet = chk_and_smod; ++ cnt = ARRAY_SIZE(chk_and_smod) - (is64 ? 2 : 0); ++ } else { ++ patchlet = isdiv ? chk_and_div : chk_and_mod; ++ cnt = isdiv ? ARRAY_SIZE(chk_and_div) : ++ ARRAY_SIZE(chk_and_mod) - (is64 ? 2 : 0); ++ } + + new_prog = bpf_patch_insn_data(env, i + delta, patchlet, cnt); + if (!new_prog) +-- +2.43.0 + diff --git a/queue-6.10/bpf-make-the-pointer-returned-by-iter-next-method-va.patch b/queue-6.10/bpf-make-the-pointer-returned-by-iter-next-method-va.patch new file mode 100644 index 00000000000..ebeb6e85eb3 --- /dev/null +++ b/queue-6.10/bpf-make-the-pointer-returned-by-iter-next-method-va.patch @@ -0,0 +1,108 @@ +From 0b752f35496de47b25c3d5e7487b845d566687c7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Aug 2024 21:11:17 +0100 +Subject: bpf: Make the pointer returned by iter next method valid + +From: Juntong Deng + +[ Upstream commit 4cc8c50c9abcb2646a7a4fcef3cea5dcb30c06cf ] + +Currently we cannot pass the pointer returned by iter next method as +argument to KF_TRUSTED_ARGS or KF_RCU kfuncs, because the pointer +returned by iter next method is not "valid". + +This patch sets the pointer returned by iter next method to be valid. + +This is based on the fact that if the iterator is implemented correctly, +then the pointer returned from the iter next method should be valid. + +This does not make NULL pointer valid. If the iter next method has +KF_RET_NULL flag, then the verifier will ask the ebpf program to +check NULL pointer. + +KF_RCU_PROTECTED iterator is a special case, the pointer returned by +iter next method should only be valid within RCU critical section, +so it should be with MEM_RCU, not PTR_TRUSTED. + +Another special case is bpf_iter_num_next, which returns a pointer with +base type PTR_TO_MEM. PTR_TO_MEM should not be combined with type flag +PTR_TRUSTED (PTR_TO_MEM already means the pointer is valid). + +The pointer returned by iter next method of other types of iterators +is with PTR_TRUSTED. + +In addition, this patch adds get_iter_from_state to help us get the +current iterator from the current state. + +Signed-off-by: Juntong Deng +Link: https://lore.kernel.org/r/AM6PR03MB584869F8B448EA1C87B7CDA399962@AM6PR03MB5848.eurprd03.prod.outlook.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 26 ++++++++++++++++++++++---- + 1 file changed, 22 insertions(+), 4 deletions(-) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index c821713249c81..4688dc82f8b06 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -8017,6 +8017,15 @@ static int widen_imprecise_scalars(struct bpf_verifier_env *env, + return 0; + } + ++static struct bpf_reg_state *get_iter_from_state(struct bpf_verifier_state *cur_st, ++ struct bpf_kfunc_call_arg_meta *meta) ++{ ++ int iter_frameno = meta->iter.frameno; ++ int iter_spi = meta->iter.spi; ++ ++ return &cur_st->frame[iter_frameno]->stack[iter_spi].spilled_ptr; ++} ++ + /* process_iter_next_call() is called when verifier gets to iterator's next + * "method" (e.g., bpf_iter_num_next() for numbers iterator) call. We'll refer + * to it as just "iter_next()" in comments below. +@@ -8101,12 +8110,10 @@ static int process_iter_next_call(struct bpf_verifier_env *env, int insn_idx, + struct bpf_verifier_state *cur_st = env->cur_state, *queued_st, *prev_st; + struct bpf_func_state *cur_fr = cur_st->frame[cur_st->curframe], *queued_fr; + struct bpf_reg_state *cur_iter, *queued_iter; +- int iter_frameno = meta->iter.frameno; +- int iter_spi = meta->iter.spi; + + BTF_TYPE_EMIT(struct bpf_iter); + +- cur_iter = &env->cur_state->frame[iter_frameno]->stack[iter_spi].spilled_ptr; ++ cur_iter = get_iter_from_state(cur_st, meta); + + if (cur_iter->iter.state != BPF_ITER_STATE_ACTIVE && + cur_iter->iter.state != BPF_ITER_STATE_DRAINED) { +@@ -8134,7 +8141,7 @@ static int process_iter_next_call(struct bpf_verifier_env *env, int insn_idx, + if (!queued_st) + return -ENOMEM; + +- queued_iter = &queued_st->frame[iter_frameno]->stack[iter_spi].spilled_ptr; ++ queued_iter = get_iter_from_state(queued_st, meta); + queued_iter->iter.state = BPF_ITER_STATE_ACTIVE; + queued_iter->iter.depth++; + if (prev_st) +@@ -12675,6 +12682,17 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn, + regs[BPF_REG_0].btf = desc_btf; + regs[BPF_REG_0].type = PTR_TO_BTF_ID; + regs[BPF_REG_0].btf_id = ptr_type_id; ++ ++ if (is_iter_next_kfunc(&meta)) { ++ struct bpf_reg_state *cur_iter; ++ ++ cur_iter = get_iter_from_state(env->cur_state, &meta); ++ ++ if (cur_iter->type & MEM_RCU) /* KF_RCU_PROTECTED */ ++ regs[BPF_REG_0].type |= MEM_RCU; ++ else ++ regs[BPF_REG_0].type |= PTR_TRUSTED; ++ } + } + + if (is_kfunc_ret_null(&meta)) { +-- +2.43.0 + diff --git a/queue-6.10/bpftool-fix-undefined-behavior-caused-by-shifting-in.patch b/queue-6.10/bpftool-fix-undefined-behavior-caused-by-shifting-in.patch new file mode 100644 index 00000000000..64ab0890787 --- /dev/null +++ b/queue-6.10/bpftool-fix-undefined-behavior-caused-by-shifting-in.patch @@ -0,0 +1,55 @@ +From 38c9d180fca76681259493870e8a793193c0f0cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 8 Sep 2024 22:00:09 +0800 +Subject: bpftool: Fix undefined behavior caused by shifting into the sign bit + +From: Kuan-Wei Chiu + +[ Upstream commit 4cdc0e4ce5e893bc92255f5f734d983012f2bc2e ] + +Replace shifts of '1' with '1U' in bitwise operations within +__show_dev_tc_bpf() to prevent undefined behavior caused by shifting +into the sign bit of a signed integer. By using '1U', the operations +are explicitly performed on unsigned integers, avoiding potential +integer overflow or sign-related issues. + +Signed-off-by: Kuan-Wei Chiu +Signed-off-by: Andrii Nakryiko +Acked-by: Quentin Monnet +Link: https://lore.kernel.org/bpf/20240908140009.3149781-1-visitorckw@gmail.com +Signed-off-by: Sasha Levin +--- + tools/bpf/bpftool/net.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c +index 968714b4c3d45..ad2ea6cf2db11 100644 +--- a/tools/bpf/bpftool/net.c ++++ b/tools/bpf/bpftool/net.c +@@ -482,9 +482,9 @@ static void __show_dev_tc_bpf(const struct ip_devname_ifindex *dev, + if (prog_flags[i] || json_output) { + NET_START_ARRAY("prog_flags", "%s "); + for (j = 0; prog_flags[i] && j < 32; j++) { +- if (!(prog_flags[i] & (1 << j))) ++ if (!(prog_flags[i] & (1U << j))) + continue; +- NET_DUMP_UINT_ONLY(1 << j); ++ NET_DUMP_UINT_ONLY(1U << j); + } + NET_END_ARRAY(""); + } +@@ -493,9 +493,9 @@ static void __show_dev_tc_bpf(const struct ip_devname_ifindex *dev, + if (link_flags[i] || json_output) { + NET_START_ARRAY("link_flags", "%s "); + for (j = 0; link_flags[i] && j < 32; j++) { +- if (!(link_flags[i] & (1 << j))) ++ if (!(link_flags[i] & (1U << j))) + continue; +- NET_DUMP_UINT_ONLY(1 << j); ++ NET_DUMP_UINT_ONLY(1U << j); + } + NET_END_ARRAY(""); + } +-- +2.43.0 + diff --git a/queue-6.10/bpftool-fix-undefined-behavior-in-qsort-null-0.patch b/queue-6.10/bpftool-fix-undefined-behavior-in-qsort-null-0.patch new file mode 100644 index 00000000000..606867b2cf0 --- /dev/null +++ b/queue-6.10/bpftool-fix-undefined-behavior-in-qsort-null-0.patch @@ -0,0 +1,57 @@ +From 4845ae8332bd9154325ea6e6d3166d113e9a2692 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Sep 2024 23:02:07 +0800 +Subject: bpftool: Fix undefined behavior in qsort(NULL, 0, ...) + +From: Kuan-Wei Chiu + +[ Upstream commit f04e2ad394e2755d0bb2d858ecb5598718bf00d5 ] + +When netfilter has no entry to display, qsort is called with +qsort(NULL, 0, ...). This results in undefined behavior, as UBSan +reports: + +net.c:827:2: runtime error: null pointer passed as argument 1, which is declared to never be null + +Although the C standard does not explicitly state whether calling qsort +with a NULL pointer when the size is 0 constitutes undefined behavior, +Section 7.1.4 of the C standard (Use of library functions) mentions: + +"Each of the following statements applies unless explicitly stated +otherwise in the detailed descriptions that follow: If an argument to a +function has an invalid value (such as a value outside the domain of +the function, or a pointer outside the address space of the program, or +a null pointer, or a pointer to non-modifiable storage when the +corresponding parameter is not const-qualified) or a type (after +promotion) not expected by a function with variable number of +arguments, the behavior is undefined." + +To avoid this, add an early return when nf_link_info is NULL to prevent +calling qsort with a NULL pointer. + +Signed-off-by: Kuan-Wei Chiu +Signed-off-by: Andrii Nakryiko +Reviewed-by: Quentin Monnet +Link: https://lore.kernel.org/bpf/20240910150207.3179306-1-visitorckw@gmail.com +Signed-off-by: Sasha Levin +--- + tools/bpf/bpftool/net.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c +index ad2ea6cf2db11..0f2106218e1f0 100644 +--- a/tools/bpf/bpftool/net.c ++++ b/tools/bpf/bpftool/net.c +@@ -824,6 +824,9 @@ static void show_link_netfilter(void) + nf_link_count++; + } + ++ if (!nf_link_info) ++ return; ++ + qsort(nf_link_info, nf_link_count, sizeof(*nf_link_info), netfilter_link_compar); + + for (id = 0; id < nf_link_count; id++) { +-- +2.43.0 + diff --git a/queue-6.10/can-netlink-avoid-call-to-do_set_data_bittiming-call.patch b/queue-6.10/can-netlink-avoid-call-to-do_set_data_bittiming-call.patch new file mode 100644 index 00000000000..5120a451ccd --- /dev/null +++ b/queue-6.10/can-netlink-avoid-call-to-do_set_data_bittiming-call.patch @@ -0,0 +1,173 @@ +From bff7fc8c8d969fbd15ecfc8750f2bc232d1dda48 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Aug 2024 18:42:24 +0200 +Subject: can: netlink: avoid call to do_set_data_bittiming callback with stale + can_priv::ctrlmode +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Stefan Mätje + +[ Upstream commit 2423cc20087ae9a7b7af575aa62304ef67cad7b6 ] + +This patch moves the evaluation of data[IFLA_CAN_CTRLMODE] in function +can_changelink in front of the evaluation of data[IFLA_CAN_BITTIMING]. + +This avoids a call to do_set_data_bittiming providing a stale +can_priv::ctrlmode with a CAN_CTRLMODE_FD flag not matching the +requested state when switching between a CAN Classic and CAN-FD bitrate. + +In the same manner the evaluation of data[IFLA_CAN_CTRLMODE] in function +can_validate is also moved in front of the evaluation of +data[IFLA_CAN_BITTIMING]. + +This is a preparation for patches where the nominal and data bittiming +may have interdependencies on the driver side depending on the +CAN_CTRLMODE_FD flag state. + +Signed-off-by: Stefan Mätje +Link: https://patch.msgid.link/20240808164224.213522-1-stefan.maetje@esd.eu +Signed-off-by: Marc Kleine-Budde +Signed-off-by: Sasha Levin +--- + drivers/net/can/dev/netlink.c | 102 +++++++++++++++++----------------- + 1 file changed, 51 insertions(+), 51 deletions(-) + +diff --git a/drivers/net/can/dev/netlink.c b/drivers/net/can/dev/netlink.c +index dfdc039d92a6c..01aacdcda2606 100644 +--- a/drivers/net/can/dev/netlink.c ++++ b/drivers/net/can/dev/netlink.c +@@ -65,15 +65,6 @@ static int can_validate(struct nlattr *tb[], struct nlattr *data[], + if (!data) + return 0; + +- if (data[IFLA_CAN_BITTIMING]) { +- struct can_bittiming bt; +- +- memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt)); +- err = can_validate_bittiming(&bt, extack); +- if (err) +- return err; +- } +- + if (data[IFLA_CAN_CTRLMODE]) { + struct can_ctrlmode *cm = nla_data(data[IFLA_CAN_CTRLMODE]); + u32 tdc_flags = cm->flags & CAN_CTRLMODE_TDC_MASK; +@@ -114,6 +105,15 @@ static int can_validate(struct nlattr *tb[], struct nlattr *data[], + } + } + ++ if (data[IFLA_CAN_BITTIMING]) { ++ struct can_bittiming bt; ++ ++ memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt)); ++ err = can_validate_bittiming(&bt, extack); ++ if (err) ++ return err; ++ } ++ + if (is_can_fd) { + if (!data[IFLA_CAN_BITTIMING] || !data[IFLA_CAN_DATA_BITTIMING]) + return -EOPNOTSUPP; +@@ -195,48 +195,6 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[], + /* We need synchronization with dev->stop() */ + ASSERT_RTNL(); + +- if (data[IFLA_CAN_BITTIMING]) { +- struct can_bittiming bt; +- +- /* Do not allow changing bittiming while running */ +- if (dev->flags & IFF_UP) +- return -EBUSY; +- +- /* Calculate bittiming parameters based on +- * bittiming_const if set, otherwise pass bitrate +- * directly via do_set_bitrate(). Bail out if neither +- * is given. +- */ +- if (!priv->bittiming_const && !priv->do_set_bittiming && +- !priv->bitrate_const) +- return -EOPNOTSUPP; +- +- memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt)); +- err = can_get_bittiming(dev, &bt, +- priv->bittiming_const, +- priv->bitrate_const, +- priv->bitrate_const_cnt, +- extack); +- if (err) +- return err; +- +- if (priv->bitrate_max && bt.bitrate > priv->bitrate_max) { +- NL_SET_ERR_MSG_FMT(extack, +- "arbitration bitrate %u bps surpasses transceiver capabilities of %u bps", +- bt.bitrate, priv->bitrate_max); +- return -EINVAL; +- } +- +- memcpy(&priv->bittiming, &bt, sizeof(bt)); +- +- if (priv->do_set_bittiming) { +- /* Finally, set the bit-timing registers */ +- err = priv->do_set_bittiming(dev); +- if (err) +- return err; +- } +- } +- + if (data[IFLA_CAN_CTRLMODE]) { + struct can_ctrlmode *cm; + u32 ctrlstatic; +@@ -284,6 +242,48 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[], + priv->ctrlmode &= cm->flags | ~CAN_CTRLMODE_TDC_MASK; + } + ++ if (data[IFLA_CAN_BITTIMING]) { ++ struct can_bittiming bt; ++ ++ /* Do not allow changing bittiming while running */ ++ if (dev->flags & IFF_UP) ++ return -EBUSY; ++ ++ /* Calculate bittiming parameters based on ++ * bittiming_const if set, otherwise pass bitrate ++ * directly via do_set_bitrate(). Bail out if neither ++ * is given. ++ */ ++ if (!priv->bittiming_const && !priv->do_set_bittiming && ++ !priv->bitrate_const) ++ return -EOPNOTSUPP; ++ ++ memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt)); ++ err = can_get_bittiming(dev, &bt, ++ priv->bittiming_const, ++ priv->bitrate_const, ++ priv->bitrate_const_cnt, ++ extack); ++ if (err) ++ return err; ++ ++ if (priv->bitrate_max && bt.bitrate > priv->bitrate_max) { ++ NL_SET_ERR_MSG_FMT(extack, ++ "arbitration bitrate %u bps surpasses transceiver capabilities of %u bps", ++ bt.bitrate, priv->bitrate_max); ++ return -EINVAL; ++ } ++ ++ memcpy(&priv->bittiming, &bt, sizeof(bt)); ++ ++ if (priv->do_set_bittiming) { ++ /* Finally, set the bit-timing registers */ ++ err = priv->do_set_bittiming(dev); ++ if (err) ++ return err; ++ } ++ } ++ + if (data[IFLA_CAN_RESTART_MS]) { + /* Do not allow changing restart delay while running */ + if (dev->flags & IFF_UP) +-- +2.43.0 + diff --git a/queue-6.10/cgroup-disallow-mounting-v1-hierarchies-without-cont.patch b/queue-6.10/cgroup-disallow-mounting-v1-hierarchies-without-cont.patch new file mode 100644 index 00000000000..90011fba4d7 --- /dev/null +++ b/queue-6.10/cgroup-disallow-mounting-v1-hierarchies-without-cont.patch @@ -0,0 +1,71 @@ +From f9571e8ad38d9421f6495a889213df68eaebc9ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Sep 2024 18:32:22 +0200 +Subject: cgroup: Disallow mounting v1 hierarchies without controller + implementation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Michal Koutný + +[ Upstream commit 3c41382e920f1dd5c9f432948fe799c07af1cced ] + +The configs that disable some v1 controllers would still allow mounting +them but with no controller-specific files. (Making such hierarchies +equivalent to named v1 hierarchies.) To achieve behavior consistent with +actual out-compilation of a whole controller, the mounts should treat +respective controllers as non-existent. + +Wrap implementation into a helper function, leverage legacy_files to +detect compiled out controllers. The effect is that mounts on v1 would +fail and produce a message like: + [ 1543.999081] cgroup: Unknown subsys name 'memory' + +Signed-off-by: Michal Koutný +Signed-off-by: Tejun Heo +Signed-off-by: Sasha Levin +--- + kernel/cgroup/cgroup-v1.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/kernel/cgroup/cgroup-v1.c b/kernel/cgroup/cgroup-v1.c +index b9dbf6bf2779d..784337694a4be 100644 +--- a/kernel/cgroup/cgroup-v1.c ++++ b/kernel/cgroup/cgroup-v1.c +@@ -46,6 +46,12 @@ bool cgroup1_ssid_disabled(int ssid) + return cgroup_no_v1_mask & (1 << ssid); + } + ++static bool cgroup1_subsys_absent(struct cgroup_subsys *ss) ++{ ++ /* Check also dfl_cftypes for file-less controllers, i.e. perf_event */ ++ return ss->legacy_cftypes == NULL && ss->dfl_cftypes; ++} ++ + /** + * cgroup_attach_task_all - attach task 'tsk' to all cgroups of task 'from' + * @from: attach to all cgroups of a given task +@@ -932,7 +938,8 @@ int cgroup1_parse_param(struct fs_context *fc, struct fs_parameter *param) + if (ret != -ENOPARAM) + return ret; + for_each_subsys(ss, i) { +- if (strcmp(param->key, ss->legacy_name)) ++ if (strcmp(param->key, ss->legacy_name) || ++ cgroup1_subsys_absent(ss)) + continue; + if (!cgroup_ssid_enabled(i) || cgroup1_ssid_disabled(i)) + return invalfc(fc, "Disabled controller '%s'", +@@ -1024,7 +1031,8 @@ static int check_cgroupfs_options(struct fs_context *fc) + mask = ~((u16)1 << cpuset_cgrp_id); + #endif + for_each_subsys(ss, i) +- if (cgroup_ssid_enabled(i) && !cgroup1_ssid_disabled(i)) ++ if (cgroup_ssid_enabled(i) && !cgroup1_ssid_disabled(i) && ++ !cgroup1_subsys_absent(ss)) + enabled |= 1 << i; + + ctx->subsys_mask &= enabled; +-- +2.43.0 + diff --git a/queue-6.10/coredump-standartize-and-fix-logging.patch b/queue-6.10/coredump-standartize-and-fix-logging.patch new file mode 100644 index 00000000000..a91cbc56f48 --- /dev/null +++ b/queue-6.10/coredump-standartize-and-fix-logging.patch @@ -0,0 +1,178 @@ +From f0a5649db30d6ff2509281ace680db9cc08ce258 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Jul 2024 11:27:24 -0700 +Subject: coredump: Standartize and fix logging + +From: Roman Kisel + +[ Upstream commit c114e9948c2b6a0b400266e59cc656b59e795bca ] + +The coredump code does not log the process ID and the comm +consistently, logs unescaped comm when it does log it, and +does not always use the ratelimited logging. That makes it +harder to analyze logs and puts the system at the risk of +spamming the system log incase something crashes many times +over and over again. + +Fix that by logging TGID and comm (escaped) consistently and +using the ratelimited logging always. + +Signed-off-by: Roman Kisel +Tested-by: Allen Pais +Link: https://lore.kernel.org/r/20240718182743.1959160-2-romank@linux.microsoft.com +Signed-off-by: Kees Cook +Signed-off-by: Sasha Levin +--- + fs/coredump.c | 43 +++++++++++++++------------------------- + include/linux/coredump.h | 22 ++++++++++++++++++++ + 2 files changed, 38 insertions(+), 27 deletions(-) + +diff --git a/fs/coredump.c b/fs/coredump.c +index a57a06b80f571..19d3343b93c6b 100644 +--- a/fs/coredump.c ++++ b/fs/coredump.c +@@ -586,8 +586,7 @@ void do_coredump(const kernel_siginfo_t *siginfo) + struct subprocess_info *sub_info; + + if (ispipe < 0) { +- printk(KERN_WARNING "format_corename failed\n"); +- printk(KERN_WARNING "Aborting core\n"); ++ coredump_report_failure("format_corename failed, aborting core"); + goto fail_unlock; + } + +@@ -607,27 +606,21 @@ void do_coredump(const kernel_siginfo_t *siginfo) + * right pid if a thread in a multi-threaded + * core_pattern process dies. + */ +- printk(KERN_WARNING +- "Process %d(%s) has RLIMIT_CORE set to 1\n", +- task_tgid_vnr(current), current->comm); +- printk(KERN_WARNING "Aborting core\n"); ++ coredump_report_failure("RLIMIT_CORE is set to 1, aborting core"); + goto fail_unlock; + } + cprm.limit = RLIM_INFINITY; + + dump_count = atomic_inc_return(&core_dump_count); + if (core_pipe_limit && (core_pipe_limit < dump_count)) { +- printk(KERN_WARNING "Pid %d(%s) over core_pipe_limit\n", +- task_tgid_vnr(current), current->comm); +- printk(KERN_WARNING "Skipping core dump\n"); ++ coredump_report_failure("over core_pipe_limit, skipping core dump"); + goto fail_dropcount; + } + + helper_argv = kmalloc_array(argc + 1, sizeof(*helper_argv), + GFP_KERNEL); + if (!helper_argv) { +- printk(KERN_WARNING "%s failed to allocate memory\n", +- __func__); ++ coredump_report_failure("%s failed to allocate memory", __func__); + goto fail_dropcount; + } + for (argi = 0; argi < argc; argi++) +@@ -644,8 +637,7 @@ void do_coredump(const kernel_siginfo_t *siginfo) + + kfree(helper_argv); + if (retval) { +- printk(KERN_INFO "Core dump to |%s pipe failed\n", +- cn.corename); ++ coredump_report_failure("|%s pipe failed", cn.corename); + goto close_fail; + } + } else { +@@ -658,10 +650,8 @@ void do_coredump(const kernel_siginfo_t *siginfo) + goto fail_unlock; + + if (need_suid_safe && cn.corename[0] != '/') { +- printk(KERN_WARNING "Pid %d(%s) can only dump core "\ +- "to fully qualified path!\n", +- task_tgid_vnr(current), current->comm); +- printk(KERN_WARNING "Skipping core dump\n"); ++ coredump_report_failure( ++ "this process can only dump core to a fully qualified path, skipping core dump"); + goto fail_unlock; + } + +@@ -730,13 +720,13 @@ void do_coredump(const kernel_siginfo_t *siginfo) + idmap = file_mnt_idmap(cprm.file); + if (!vfsuid_eq_kuid(i_uid_into_vfsuid(idmap, inode), + current_fsuid())) { +- pr_info_ratelimited("Core dump to %s aborted: cannot preserve file owner\n", +- cn.corename); ++ coredump_report_failure("Core dump to %s aborted: " ++ "cannot preserve file owner", cn.corename); + goto close_fail; + } + if ((inode->i_mode & 0677) != 0600) { +- pr_info_ratelimited("Core dump to %s aborted: cannot preserve file permissions\n", +- cn.corename); ++ coredump_report_failure("Core dump to %s aborted: " ++ "cannot preserve file permissions", cn.corename); + goto close_fail; + } + if (!(cprm.file->f_mode & FMODE_CAN_WRITE)) +@@ -757,7 +747,7 @@ void do_coredump(const kernel_siginfo_t *siginfo) + * have this set to NULL. + */ + if (!cprm.file) { +- pr_info("Core dump to |%s disabled\n", cn.corename); ++ coredump_report_failure("Core dump to |%s disabled", cn.corename); + goto close_fail; + } + if (!dump_vma_snapshot(&cprm)) +@@ -983,11 +973,10 @@ void validate_coredump_safety(void) + { + if (suid_dumpable == SUID_DUMP_ROOT && + core_pattern[0] != '/' && core_pattern[0] != '|') { +- pr_warn( +-"Unsafe core_pattern used with fs.suid_dumpable=2.\n" +-"Pipe handler or fully qualified core dump path required.\n" +-"Set kernel.core_pattern before fs.suid_dumpable.\n" +- ); ++ ++ coredump_report_failure("Unsafe core_pattern used with fs.suid_dumpable=2: " ++ "pipe handler or fully qualified core dump path required. " ++ "Set kernel.core_pattern before fs.suid_dumpable."); + } + } + +diff --git a/include/linux/coredump.h b/include/linux/coredump.h +index 0904ba010341a..45e598fe34766 100644 +--- a/include/linux/coredump.h ++++ b/include/linux/coredump.h +@@ -43,8 +43,30 @@ extern int dump_align(struct coredump_params *cprm, int align); + int dump_user_range(struct coredump_params *cprm, unsigned long start, + unsigned long len); + extern void do_coredump(const kernel_siginfo_t *siginfo); ++ ++/* ++ * Logging for the coredump code, ratelimited. ++ * The TGID and comm fields are added to the message. ++ */ ++ ++#define __COREDUMP_PRINTK(Level, Format, ...) \ ++ do { \ ++ char comm[TASK_COMM_LEN]; \ ++ \ ++ get_task_comm(comm, current); \ ++ printk_ratelimited(Level "coredump: %d(%*pE): " Format "\n", \ ++ task_tgid_vnr(current), (int)strlen(comm), comm, ##__VA_ARGS__); \ ++ } while (0) \ ++ ++#define coredump_report(fmt, ...) __COREDUMP_PRINTK(KERN_INFO, fmt, ##__VA_ARGS__) ++#define coredump_report_failure(fmt, ...) __COREDUMP_PRINTK(KERN_WARNING, fmt, ##__VA_ARGS__) ++ + #else + static inline void do_coredump(const kernel_siginfo_t *siginfo) {} ++ ++#define coredump_report(...) ++#define coredump_report_failure(...) ++ + #endif + + #if defined(CONFIG_COREDUMP) && defined(CONFIG_SYSCTL) +-- +2.43.0 + diff --git a/queue-6.10/crypto-hisilicon-fix-missed-error-branch.patch b/queue-6.10/crypto-hisilicon-fix-missed-error-branch.patch new file mode 100644 index 00000000000..4a5939a0e84 --- /dev/null +++ b/queue-6.10/crypto-hisilicon-fix-missed-error-branch.patch @@ -0,0 +1,69 @@ +From 0141cf80196a1bcd3a305dc815841fa3c23708d9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Aug 2024 17:50:07 +0800 +Subject: crypto: hisilicon - fix missed error branch + +From: Yang Shen + +[ 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 +Signed-off-by: Chenghai Huang +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/sgl.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/drivers/crypto/hisilicon/sgl.c b/drivers/crypto/hisilicon/sgl.c +index 568acd0aee3fa..c974f95cd126f 100644 +--- a/drivers/crypto/hisilicon/sgl.c ++++ b/drivers/crypto/hisilicon/sgl.c +@@ -225,7 +225,7 @@ hisi_acc_sg_buf_map_to_hw_sgl(struct device *dev, + dma_addr_t curr_sgl_dma = 0; + struct acc_hw_sge *curr_hw_sge; + struct scatterlist *sg; +- int sg_n; ++ int sg_n, ret; + + if (!dev || !sgl || !pool || !hw_sgl_dma || index >= pool->count) + return ERR_PTR(-EINVAL); +@@ -240,14 +240,15 @@ hisi_acc_sg_buf_map_to_hw_sgl(struct device *dev, + + if (sg_n_mapped > pool->sge_nr) { + dev_err(dev, "the number of entries in input scatterlist is bigger than SGL pool setting.\n"); +- return ERR_PTR(-EINVAL); ++ ret = -EINVAL; ++ goto err_unmap; + } + + curr_hw_sgl = acc_get_sgl(pool, index, &curr_sgl_dma); + if (IS_ERR(curr_hw_sgl)) { + dev_err(dev, "Get SGL error!\n"); +- dma_unmap_sg(dev, sgl, sg_n, DMA_BIDIRECTIONAL); +- return ERR_PTR(-ENOMEM); ++ ret = -ENOMEM; ++ goto err_unmap; + } + curr_hw_sgl->entry_length_in_sgl = cpu_to_le16(pool->sge_nr); + curr_hw_sge = curr_hw_sgl->sge_entries; +@@ -262,6 +263,11 @@ hisi_acc_sg_buf_map_to_hw_sgl(struct device *dev, + *hw_sgl_dma = curr_sgl_dma; + + return curr_hw_sgl; ++ ++err_unmap: ++ dma_unmap_sg(dev, sgl, sg_n, DMA_BIDIRECTIONAL); ++ ++ return ERR_PTR(ret); + } + EXPORT_SYMBOL_GPL(hisi_acc_sg_buf_map_to_hw_sgl); + +-- +2.43.0 + diff --git a/queue-6.10/crypto-octeontx-fix-authenc-setkey.patch b/queue-6.10/crypto-octeontx-fix-authenc-setkey.patch new file mode 100644 index 00000000000..b0e8714ac87 --- /dev/null +++ b/queue-6.10/crypto-octeontx-fix-authenc-setkey.patch @@ -0,0 +1,408 @@ +From f9b0de8781f1488819b6a7ebeff5759c18e4a7f1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 17 Aug 2024 12:13:23 +0800 +Subject: crypto: octeontx - Fix authenc setkey + +From: Herbert Xu + +[ Upstream commit 311eea7e37c4c0b44b557d0c100860a03b4eab65 ] + +Use the generic crypto_authenc_extractkeys helper instead of custom +parsing code that is slightly broken. Also fix a number of memory +leaks by moving memory allocation from setkey to init_tfm (setkey +can be called multiple times over the life of a tfm). + +Finally accept all hash key lengths by running the digest over +extra-long keys. + +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + .../crypto/marvell/octeontx/otx_cptvf_algs.c | 261 +++++++----------- + 1 file changed, 93 insertions(+), 168 deletions(-) + +diff --git a/drivers/crypto/marvell/octeontx/otx_cptvf_algs.c b/drivers/crypto/marvell/octeontx/otx_cptvf_algs.c +index 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 + #include + #include +-#include + #include + #include + #include "otx_cptvf.h" +@@ -66,6 +65,8 @@ static struct cpt_device_table ae_devices = { + .count = ATOMIC_INIT(0) + }; + ++static struct otx_cpt_sdesc *alloc_sdesc(struct crypto_shash *alg); ++ + static inline int get_se_device(struct pci_dev **pdev, int *cpu_num) + { + int count, ret = 0; +@@ -509,44 +510,61 @@ static int cpt_aead_init(struct crypto_aead *tfm, u8 cipher_type, u8 mac_type) + ctx->cipher_type = cipher_type; + ctx->mac_type = mac_type; + ++ switch (ctx->mac_type) { ++ case OTX_CPT_SHA1: ++ ctx->hashalg = crypto_alloc_shash("sha1", 0, 0); ++ break; ++ ++ case OTX_CPT_SHA256: ++ ctx->hashalg = crypto_alloc_shash("sha256", 0, 0); ++ break; ++ ++ case OTX_CPT_SHA384: ++ ctx->hashalg = crypto_alloc_shash("sha384", 0, 0); ++ break; ++ ++ case OTX_CPT_SHA512: ++ ctx->hashalg = crypto_alloc_shash("sha512", 0, 0); ++ break; ++ } ++ ++ if (IS_ERR(ctx->hashalg)) ++ return PTR_ERR(ctx->hashalg); ++ ++ crypto_aead_set_reqsize_dma(tfm, sizeof(struct otx_cpt_req_ctx)); ++ ++ if (!ctx->hashalg) ++ return 0; ++ + /* + * When selected cipher is NULL we use HMAC opcode instead of + * FLEXICRYPTO opcode therefore we don't need to use HASH algorithms + * for calculating ipad and opad + */ + if (ctx->cipher_type != OTX_CPT_CIPHER_NULL) { +- switch (ctx->mac_type) { +- case OTX_CPT_SHA1: +- ctx->hashalg = crypto_alloc_shash("sha1", 0, +- CRYPTO_ALG_ASYNC); +- if (IS_ERR(ctx->hashalg)) +- return PTR_ERR(ctx->hashalg); +- break; +- +- case OTX_CPT_SHA256: +- ctx->hashalg = crypto_alloc_shash("sha256", 0, +- CRYPTO_ALG_ASYNC); +- if (IS_ERR(ctx->hashalg)) +- return PTR_ERR(ctx->hashalg); +- break; ++ int ss = crypto_shash_statesize(ctx->hashalg); + +- case OTX_CPT_SHA384: +- ctx->hashalg = crypto_alloc_shash("sha384", 0, +- CRYPTO_ALG_ASYNC); +- if (IS_ERR(ctx->hashalg)) +- return PTR_ERR(ctx->hashalg); +- break; ++ ctx->ipad = kzalloc(ss, GFP_KERNEL); ++ if (!ctx->ipad) { ++ crypto_free_shash(ctx->hashalg); ++ return -ENOMEM; ++ } + +- case OTX_CPT_SHA512: +- ctx->hashalg = crypto_alloc_shash("sha512", 0, +- CRYPTO_ALG_ASYNC); +- if (IS_ERR(ctx->hashalg)) +- return PTR_ERR(ctx->hashalg); +- break; ++ ctx->opad = kzalloc(ss, GFP_KERNEL); ++ if (!ctx->opad) { ++ kfree(ctx->ipad); ++ crypto_free_shash(ctx->hashalg); ++ return -ENOMEM; + } + } + +- crypto_aead_set_reqsize_dma(tfm, sizeof(struct otx_cpt_req_ctx)); ++ ctx->sdesc = alloc_sdesc(ctx->hashalg); ++ if (!ctx->sdesc) { ++ kfree(ctx->opad); ++ kfree(ctx->ipad); ++ crypto_free_shash(ctx->hashalg); ++ return -ENOMEM; ++ } + + return 0; + } +@@ -602,8 +620,7 @@ static void otx_cpt_aead_exit(struct crypto_aead *tfm) + + kfree(ctx->ipad); + kfree(ctx->opad); +- if (ctx->hashalg) +- crypto_free_shash(ctx->hashalg); ++ crypto_free_shash(ctx->hashalg); + kfree(ctx->sdesc); + } + +@@ -699,7 +716,7 @@ static inline void swap_data64(void *buf, u32 len) + *dst = cpu_to_be64p(src); + } + +-static int copy_pad(u8 mac_type, u8 *out_pad, u8 *in_pad) ++static int swap_pad(u8 mac_type, u8 *pad) + { + struct sha512_state *sha512; + struct sha256_state *sha256; +@@ -707,22 +724,19 @@ static int copy_pad(u8 mac_type, u8 *out_pad, u8 *in_pad) + + switch (mac_type) { + case OTX_CPT_SHA1: +- sha1 = (struct sha1_state *) in_pad; ++ sha1 = (struct sha1_state *)pad; + swap_data32(sha1->state, SHA1_DIGEST_SIZE); +- memcpy(out_pad, &sha1->state, SHA1_DIGEST_SIZE); + break; + + case OTX_CPT_SHA256: +- sha256 = (struct sha256_state *) in_pad; ++ sha256 = (struct sha256_state *)pad; + swap_data32(sha256->state, SHA256_DIGEST_SIZE); +- memcpy(out_pad, &sha256->state, SHA256_DIGEST_SIZE); + break; + + case OTX_CPT_SHA384: + case OTX_CPT_SHA512: +- sha512 = (struct sha512_state *) in_pad; ++ sha512 = (struct sha512_state *)pad; + swap_data64(sha512->state, SHA512_DIGEST_SIZE); +- memcpy(out_pad, &sha512->state, SHA512_DIGEST_SIZE); + break; + + default: +@@ -732,55 +746,53 @@ static int copy_pad(u8 mac_type, u8 *out_pad, u8 *in_pad) + return 0; + } + +-static int aead_hmac_init(struct crypto_aead *cipher) ++static int aead_hmac_init(struct crypto_aead *cipher, ++ struct crypto_authenc_keys *keys) + { + struct otx_cpt_aead_ctx *ctx = crypto_aead_ctx_dma(cipher); +- int state_size = crypto_shash_statesize(ctx->hashalg); + int ds = crypto_shash_digestsize(ctx->hashalg); + int bs = crypto_shash_blocksize(ctx->hashalg); +- int authkeylen = ctx->auth_key_len; ++ int authkeylen = keys->authkeylen; + u8 *ipad = NULL, *opad = NULL; +- int ret = 0, icount = 0; ++ int icount = 0; ++ int ret; + +- ctx->sdesc = alloc_sdesc(ctx->hashalg); +- if (!ctx->sdesc) +- return -ENOMEM; ++ if (authkeylen > bs) { ++ ret = crypto_shash_digest(&ctx->sdesc->shash, keys->authkey, ++ authkeylen, ctx->key); ++ if (ret) ++ return ret; ++ authkeylen = ds; ++ } else ++ memcpy(ctx->key, keys->authkey, authkeylen); + +- ctx->ipad = kzalloc(bs, GFP_KERNEL); +- if (!ctx->ipad) { +- ret = -ENOMEM; +- goto calc_fail; +- } ++ ctx->enc_key_len = keys->enckeylen; ++ ctx->auth_key_len = authkeylen; + +- ctx->opad = kzalloc(bs, GFP_KERNEL); +- if (!ctx->opad) { +- ret = -ENOMEM; +- goto calc_fail; +- } ++ if (ctx->cipher_type == OTX_CPT_CIPHER_NULL) ++ return keys->enckeylen ? -EINVAL : 0; + +- ipad = kzalloc(state_size, GFP_KERNEL); +- if (!ipad) { +- ret = -ENOMEM; +- goto calc_fail; ++ switch (keys->enckeylen) { ++ case AES_KEYSIZE_128: ++ ctx->key_type = OTX_CPT_AES_128_BIT; ++ break; ++ case AES_KEYSIZE_192: ++ ctx->key_type = OTX_CPT_AES_192_BIT; ++ break; ++ case AES_KEYSIZE_256: ++ ctx->key_type = OTX_CPT_AES_256_BIT; ++ break; ++ default: ++ /* Invalid key length */ ++ return -EINVAL; + } + +- opad = kzalloc(state_size, GFP_KERNEL); +- if (!opad) { +- ret = -ENOMEM; +- goto calc_fail; +- } ++ memcpy(ctx->key + authkeylen, keys->enckey, keys->enckeylen); + +- if (authkeylen > bs) { +- ret = crypto_shash_digest(&ctx->sdesc->shash, ctx->key, +- authkeylen, ipad); +- if (ret) +- goto calc_fail; +- +- authkeylen = ds; +- } else { +- memcpy(ipad, ctx->key, authkeylen); +- } ++ ipad = ctx->ipad; ++ opad = ctx->opad; + ++ memcpy(ipad, ctx->key, authkeylen); + memset(ipad + authkeylen, 0, bs - authkeylen); + memcpy(opad, ipad, bs); + +@@ -798,7 +810,7 @@ static int aead_hmac_init(struct crypto_aead *cipher) + crypto_shash_init(&ctx->sdesc->shash); + crypto_shash_update(&ctx->sdesc->shash, ipad, bs); + crypto_shash_export(&ctx->sdesc->shash, ipad); +- ret = copy_pad(ctx->mac_type, ctx->ipad, ipad); ++ ret = swap_pad(ctx->mac_type, ipad); + if (ret) + goto calc_fail; + +@@ -806,25 +818,9 @@ static int aead_hmac_init(struct crypto_aead *cipher) + crypto_shash_init(&ctx->sdesc->shash); + crypto_shash_update(&ctx->sdesc->shash, opad, bs); + crypto_shash_export(&ctx->sdesc->shash, opad); +- ret = copy_pad(ctx->mac_type, ctx->opad, opad); +- if (ret) +- goto calc_fail; +- +- kfree(ipad); +- kfree(opad); +- +- return 0; ++ ret = swap_pad(ctx->mac_type, opad); + + calc_fail: +- kfree(ctx->ipad); +- ctx->ipad = NULL; +- kfree(ctx->opad); +- ctx->opad = NULL; +- kfree(ipad); +- kfree(opad); +- kfree(ctx->sdesc); +- ctx->sdesc = NULL; +- + return ret; + } + +@@ -832,57 +828,15 @@ static int otx_cpt_aead_cbc_aes_sha_setkey(struct crypto_aead *cipher, + const unsigned char *key, + unsigned int keylen) + { +- struct otx_cpt_aead_ctx *ctx = crypto_aead_ctx_dma(cipher); +- struct crypto_authenc_key_param *param; +- int enckeylen = 0, authkeylen = 0; +- struct rtattr *rta = (void *)key; +- int status = -EINVAL; +- +- if (!RTA_OK(rta, keylen)) +- goto badkey; +- +- if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM) +- goto badkey; +- +- if (RTA_PAYLOAD(rta) < sizeof(*param)) +- goto badkey; +- +- param = RTA_DATA(rta); +- enckeylen = be32_to_cpu(param->enckeylen); +- key += RTA_ALIGN(rta->rta_len); +- keylen -= RTA_ALIGN(rta->rta_len); +- if (keylen < enckeylen) +- goto badkey; ++ struct crypto_authenc_keys authenc_keys; ++ int status; + +- if (keylen > OTX_CPT_MAX_KEY_SIZE) +- goto badkey; +- +- authkeylen = keylen - enckeylen; +- memcpy(ctx->key, key, keylen); +- +- switch (enckeylen) { +- case AES_KEYSIZE_128: +- ctx->key_type = OTX_CPT_AES_128_BIT; +- break; +- case AES_KEYSIZE_192: +- ctx->key_type = OTX_CPT_AES_192_BIT; +- break; +- case AES_KEYSIZE_256: +- ctx->key_type = OTX_CPT_AES_256_BIT; +- break; +- default: +- /* Invalid key length */ +- goto badkey; +- } +- +- ctx->enc_key_len = enckeylen; +- ctx->auth_key_len = authkeylen; +- +- status = aead_hmac_init(cipher); ++ status = crypto_authenc_extractkeys(&authenc_keys, key, keylen); + if (status) + goto badkey; + +- return 0; ++ status = aead_hmac_init(cipher, &authenc_keys); ++ + badkey: + return status; + } +@@ -891,36 +845,7 @@ static int otx_cpt_aead_ecb_null_sha_setkey(struct crypto_aead *cipher, + const unsigned char *key, + unsigned int keylen) + { +- struct otx_cpt_aead_ctx *ctx = crypto_aead_ctx_dma(cipher); +- struct crypto_authenc_key_param *param; +- struct rtattr *rta = (void *)key; +- int enckeylen = 0; +- +- if (!RTA_OK(rta, keylen)) +- goto badkey; +- +- if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM) +- goto badkey; +- +- if (RTA_PAYLOAD(rta) < sizeof(*param)) +- goto badkey; +- +- param = RTA_DATA(rta); +- enckeylen = be32_to_cpu(param->enckeylen); +- key += RTA_ALIGN(rta->rta_len); +- keylen -= RTA_ALIGN(rta->rta_len); +- if (enckeylen != 0) +- goto badkey; +- +- if (keylen > OTX_CPT_MAX_KEY_SIZE) +- goto badkey; +- +- memcpy(ctx->key, key, keylen); +- ctx->enc_key_len = enckeylen; +- ctx->auth_key_len = keylen; +- return 0; +-badkey: +- return -EINVAL; ++ return otx_cpt_aead_cbc_aes_sha_setkey(cipher, key, keylen); + } + + static int otx_cpt_aead_gcm_aes_setkey(struct crypto_aead *cipher, +-- +2.43.0 + diff --git a/queue-6.10/crypto-octeontx2-fix-authenc-setkey.patch b/queue-6.10/crypto-octeontx2-fix-authenc-setkey.patch new file mode 100644 index 00000000000..fc8b60df2db --- /dev/null +++ b/queue-6.10/crypto-octeontx2-fix-authenc-setkey.patch @@ -0,0 +1,394 @@ +From 52307b37bb13b345c675f270db9d59b939d939f9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 17 Aug 2024 12:36:19 +0800 +Subject: crypto: octeontx2 - Fix authenc setkey + +From: Herbert Xu + +[ Upstream commit 7ccb750dcac8abbfc7743aab0db6a72c1c3703c7 ] + +Use the generic crypto_authenc_extractkeys helper instead of custom +parsing code that is slightly broken. Also fix a number of memory +leaks by moving memory allocation from setkey to init_tfm (setkey +can be called multiple times over the life of a tfm). + +Finally accept all hash key lengths by running the digest over +extra-long keys. + +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + .../marvell/octeontx2/otx2_cptvf_algs.c | 254 +++++++----------- + 1 file changed, 90 insertions(+), 164 deletions(-) + +diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c b/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c +index 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 + #include + #include +-#include + #include + #include + #include "otx2_cptvf.h" +@@ -55,6 +54,8 @@ static struct cpt_device_table se_devices = { + .count = ATOMIC_INIT(0) + }; + ++static struct otx2_cpt_sdesc *alloc_sdesc(struct crypto_shash *alg); ++ + static inline int get_se_device(struct pci_dev **pdev, int *cpu_num) + { + int count; +@@ -598,40 +599,56 @@ static int cpt_aead_init(struct crypto_aead *atfm, u8 cipher_type, u8 mac_type) + ctx->cipher_type = cipher_type; + ctx->mac_type = mac_type; + ++ switch (ctx->mac_type) { ++ case OTX2_CPT_SHA1: ++ ctx->hashalg = crypto_alloc_shash("sha1", 0, 0); ++ break; ++ ++ case OTX2_CPT_SHA256: ++ ctx->hashalg = crypto_alloc_shash("sha256", 0, 0); ++ break; ++ ++ case OTX2_CPT_SHA384: ++ ctx->hashalg = crypto_alloc_shash("sha384", 0, 0); ++ break; ++ ++ case OTX2_CPT_SHA512: ++ ctx->hashalg = crypto_alloc_shash("sha512", 0, 0); ++ break; ++ } ++ ++ if (IS_ERR(ctx->hashalg)) ++ return PTR_ERR(ctx->hashalg); ++ ++ if (ctx->hashalg) { ++ ctx->sdesc = alloc_sdesc(ctx->hashalg); ++ if (!ctx->sdesc) { ++ crypto_free_shash(ctx->hashalg); ++ return -ENOMEM; ++ } ++ } ++ + /* + * When selected cipher is NULL we use HMAC opcode instead of + * FLEXICRYPTO opcode therefore we don't need to use HASH algorithms + * for calculating ipad and opad + */ +- if (ctx->cipher_type != OTX2_CPT_CIPHER_NULL) { +- switch (ctx->mac_type) { +- case OTX2_CPT_SHA1: +- ctx->hashalg = crypto_alloc_shash("sha1", 0, +- CRYPTO_ALG_ASYNC); +- if (IS_ERR(ctx->hashalg)) +- return PTR_ERR(ctx->hashalg); +- break; +- +- case OTX2_CPT_SHA256: +- ctx->hashalg = crypto_alloc_shash("sha256", 0, +- CRYPTO_ALG_ASYNC); +- if (IS_ERR(ctx->hashalg)) +- return PTR_ERR(ctx->hashalg); +- break; ++ if (ctx->cipher_type != OTX2_CPT_CIPHER_NULL && ctx->hashalg) { ++ int ss = crypto_shash_statesize(ctx->hashalg); + +- case OTX2_CPT_SHA384: +- ctx->hashalg = crypto_alloc_shash("sha384", 0, +- CRYPTO_ALG_ASYNC); +- if (IS_ERR(ctx->hashalg)) +- return PTR_ERR(ctx->hashalg); +- break; ++ ctx->ipad = kzalloc(ss, GFP_KERNEL); ++ if (!ctx->ipad) { ++ kfree(ctx->sdesc); ++ crypto_free_shash(ctx->hashalg); ++ return -ENOMEM; ++ } + +- case OTX2_CPT_SHA512: +- ctx->hashalg = crypto_alloc_shash("sha512", 0, +- CRYPTO_ALG_ASYNC); +- if (IS_ERR(ctx->hashalg)) +- return PTR_ERR(ctx->hashalg); +- break; ++ ctx->opad = kzalloc(ss, GFP_KERNEL); ++ if (!ctx->opad) { ++ kfree(ctx->ipad); ++ kfree(ctx->sdesc); ++ crypto_free_shash(ctx->hashalg); ++ return -ENOMEM; + } + } + switch (ctx->cipher_type) { +@@ -713,8 +730,7 @@ static void otx2_cpt_aead_exit(struct crypto_aead *tfm) + + kfree(ctx->ipad); + kfree(ctx->opad); +- if (ctx->hashalg) +- crypto_free_shash(ctx->hashalg); ++ crypto_free_shash(ctx->hashalg); + kfree(ctx->sdesc); + + if (ctx->fbk_cipher) { +@@ -788,7 +804,7 @@ static inline void swap_data64(void *buf, u32 len) + cpu_to_be64s(src); + } + +-static int copy_pad(u8 mac_type, u8 *out_pad, u8 *in_pad) ++static int swap_pad(u8 mac_type, u8 *pad) + { + struct sha512_state *sha512; + struct sha256_state *sha256; +@@ -796,22 +812,19 @@ static int copy_pad(u8 mac_type, u8 *out_pad, u8 *in_pad) + + switch (mac_type) { + case OTX2_CPT_SHA1: +- sha1 = (struct sha1_state *) in_pad; ++ sha1 = (struct sha1_state *)pad; + swap_data32(sha1->state, SHA1_DIGEST_SIZE); +- memcpy(out_pad, &sha1->state, SHA1_DIGEST_SIZE); + break; + + case OTX2_CPT_SHA256: +- sha256 = (struct sha256_state *) in_pad; ++ sha256 = (struct sha256_state *)pad; + swap_data32(sha256->state, SHA256_DIGEST_SIZE); +- memcpy(out_pad, &sha256->state, SHA256_DIGEST_SIZE); + break; + + case OTX2_CPT_SHA384: + case OTX2_CPT_SHA512: +- sha512 = (struct sha512_state *) in_pad; ++ sha512 = (struct sha512_state *)pad; + swap_data64(sha512->state, SHA512_DIGEST_SIZE); +- memcpy(out_pad, &sha512->state, SHA512_DIGEST_SIZE); + break; + + default: +@@ -821,55 +834,54 @@ static int copy_pad(u8 mac_type, u8 *out_pad, u8 *in_pad) + return 0; + } + +-static int aead_hmac_init(struct crypto_aead *cipher) ++static int aead_hmac_init(struct crypto_aead *cipher, ++ struct crypto_authenc_keys *keys) + { + struct otx2_cpt_aead_ctx *ctx = crypto_aead_ctx_dma(cipher); +- int state_size = crypto_shash_statesize(ctx->hashalg); + int ds = crypto_shash_digestsize(ctx->hashalg); + int bs = crypto_shash_blocksize(ctx->hashalg); +- int authkeylen = ctx->auth_key_len; ++ int authkeylen = keys->authkeylen; + u8 *ipad = NULL, *opad = NULL; +- int ret = 0, icount = 0; ++ int icount = 0; ++ int ret; + +- ctx->sdesc = alloc_sdesc(ctx->hashalg); +- if (!ctx->sdesc) +- return -ENOMEM; ++ if (authkeylen > bs) { ++ ret = crypto_shash_digest(&ctx->sdesc->shash, keys->authkey, ++ authkeylen, ctx->key); ++ if (ret) ++ goto calc_fail; + +- ctx->ipad = kzalloc(bs, GFP_KERNEL); +- if (!ctx->ipad) { +- ret = -ENOMEM; +- goto calc_fail; +- } ++ authkeylen = ds; ++ } else ++ memcpy(ctx->key, keys->authkey, authkeylen); + +- ctx->opad = kzalloc(bs, GFP_KERNEL); +- if (!ctx->opad) { +- ret = -ENOMEM; +- goto calc_fail; +- } ++ ctx->enc_key_len = keys->enckeylen; ++ ctx->auth_key_len = authkeylen; + +- ipad = kzalloc(state_size, GFP_KERNEL); +- if (!ipad) { +- ret = -ENOMEM; +- goto calc_fail; +- } ++ if (ctx->cipher_type == OTX2_CPT_CIPHER_NULL) ++ return keys->enckeylen ? -EINVAL : 0; + +- opad = kzalloc(state_size, GFP_KERNEL); +- if (!opad) { +- ret = -ENOMEM; +- goto calc_fail; ++ switch (keys->enckeylen) { ++ case AES_KEYSIZE_128: ++ ctx->key_type = OTX2_CPT_AES_128_BIT; ++ break; ++ case AES_KEYSIZE_192: ++ ctx->key_type = OTX2_CPT_AES_192_BIT; ++ break; ++ case AES_KEYSIZE_256: ++ ctx->key_type = OTX2_CPT_AES_256_BIT; ++ break; ++ default: ++ /* Invalid key length */ ++ return -EINVAL; + } + +- if (authkeylen > bs) { +- ret = crypto_shash_digest(&ctx->sdesc->shash, ctx->key, +- authkeylen, ipad); +- if (ret) +- goto calc_fail; ++ memcpy(ctx->key + authkeylen, keys->enckey, keys->enckeylen); + +- authkeylen = ds; +- } else { +- memcpy(ipad, ctx->key, authkeylen); +- } ++ ipad = ctx->ipad; ++ opad = ctx->opad; + ++ memcpy(ipad, ctx->key, authkeylen); + memset(ipad + authkeylen, 0, bs - authkeylen); + memcpy(opad, ipad, bs); + +@@ -887,7 +899,7 @@ static int aead_hmac_init(struct crypto_aead *cipher) + crypto_shash_init(&ctx->sdesc->shash); + crypto_shash_update(&ctx->sdesc->shash, ipad, bs); + crypto_shash_export(&ctx->sdesc->shash, ipad); +- ret = copy_pad(ctx->mac_type, ctx->ipad, ipad); ++ ret = swap_pad(ctx->mac_type, ipad); + if (ret) + goto calc_fail; + +@@ -895,25 +907,9 @@ static int aead_hmac_init(struct crypto_aead *cipher) + crypto_shash_init(&ctx->sdesc->shash); + crypto_shash_update(&ctx->sdesc->shash, opad, bs); + crypto_shash_export(&ctx->sdesc->shash, opad); +- ret = copy_pad(ctx->mac_type, ctx->opad, opad); +- if (ret) +- goto calc_fail; +- +- kfree(ipad); +- kfree(opad); +- +- return 0; ++ ret = swap_pad(ctx->mac_type, opad); + + calc_fail: +- kfree(ctx->ipad); +- ctx->ipad = NULL; +- kfree(ctx->opad); +- ctx->opad = NULL; +- kfree(ipad); +- kfree(opad); +- kfree(ctx->sdesc); +- ctx->sdesc = NULL; +- + return ret; + } + +@@ -921,87 +917,17 @@ static int otx2_cpt_aead_cbc_aes_sha_setkey(struct crypto_aead *cipher, + const unsigned char *key, + unsigned int keylen) + { +- struct otx2_cpt_aead_ctx *ctx = crypto_aead_ctx_dma(cipher); +- struct crypto_authenc_key_param *param; +- int enckeylen = 0, authkeylen = 0; +- struct rtattr *rta = (void *)key; +- +- if (!RTA_OK(rta, keylen)) +- return -EINVAL; ++ struct crypto_authenc_keys authenc_keys; + +- if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM) +- return -EINVAL; +- +- if (RTA_PAYLOAD(rta) < sizeof(*param)) +- return -EINVAL; +- +- param = RTA_DATA(rta); +- enckeylen = be32_to_cpu(param->enckeylen); +- key += RTA_ALIGN(rta->rta_len); +- keylen -= RTA_ALIGN(rta->rta_len); +- if (keylen < enckeylen) +- return -EINVAL; +- +- if (keylen > OTX2_CPT_MAX_KEY_SIZE) +- return -EINVAL; +- +- authkeylen = keylen - enckeylen; +- memcpy(ctx->key, key, keylen); +- +- switch (enckeylen) { +- case AES_KEYSIZE_128: +- ctx->key_type = OTX2_CPT_AES_128_BIT; +- break; +- case AES_KEYSIZE_192: +- ctx->key_type = OTX2_CPT_AES_192_BIT; +- break; +- case AES_KEYSIZE_256: +- ctx->key_type = OTX2_CPT_AES_256_BIT; +- break; +- default: +- /* Invalid key length */ +- return -EINVAL; +- } +- +- ctx->enc_key_len = enckeylen; +- ctx->auth_key_len = authkeylen; +- +- return aead_hmac_init(cipher); ++ return crypto_authenc_extractkeys(&authenc_keys, key, keylen) ?: ++ aead_hmac_init(cipher, &authenc_keys); + } + + static int otx2_cpt_aead_ecb_null_sha_setkey(struct crypto_aead *cipher, + const unsigned char *key, + unsigned int keylen) + { +- struct otx2_cpt_aead_ctx *ctx = crypto_aead_ctx_dma(cipher); +- struct crypto_authenc_key_param *param; +- struct rtattr *rta = (void *)key; +- int enckeylen = 0; +- +- if (!RTA_OK(rta, keylen)) +- return -EINVAL; +- +- if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM) +- return -EINVAL; +- +- if (RTA_PAYLOAD(rta) < sizeof(*param)) +- return -EINVAL; +- +- param = RTA_DATA(rta); +- enckeylen = be32_to_cpu(param->enckeylen); +- key += RTA_ALIGN(rta->rta_len); +- keylen -= RTA_ALIGN(rta->rta_len); +- if (enckeylen != 0) +- return -EINVAL; +- +- if (keylen > OTX2_CPT_MAX_KEY_SIZE) +- return -EINVAL; +- +- memcpy(ctx->key, key, keylen); +- ctx->enc_key_len = enckeylen; +- ctx->auth_key_len = keylen; +- +- return 0; ++ return otx2_cpt_aead_cbc_aes_sha_setkey(cipher, key, keylen); + } + + static int otx2_cpt_aead_gcm_aes_setkey(struct crypto_aead *cipher, +-- +2.43.0 + diff --git a/queue-6.10/crypto-simd-do-not-call-crypto_alloc_tfm-during-regi.patch b/queue-6.10/crypto-simd-do-not-call-crypto_alloc_tfm-during-regi.patch new file mode 100644 index 00000000000..568826f4112 --- /dev/null +++ b/queue-6.10/crypto-simd-do-not-call-crypto_alloc_tfm-during-regi.patch @@ -0,0 +1,249 @@ +From 647614c471b886f98a09d70bcdd4ae44bcf6dcc8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 17 Aug 2024 14:58:35 +0800 +Subject: crypto: simd - Do not call crypto_alloc_tfm during registration + +From: Herbert Xu + +[ Upstream commit 3c44d31cb34ce4eb8311a2e73634d57702948230 ] + +Algorithm registration is usually carried out during module init, +where as little work as possible should be carried out. The SIMD +code violated this rule by allocating a tfm, this then triggers a +full test of the algorithm which may dead-lock in certain cases. + +SIMD is only allocating the tfm to get at the alg object, which is +in fact already available as it is what we are registering. Use +that directly and remove the crypto_alloc_tfm call. + +Also remove some obsolete and unused SIMD API. + +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + arch/arm/crypto/aes-ce-glue.c | 2 +- + arch/arm/crypto/aes-neonbs-glue.c | 2 +- + crypto/simd.c | 76 ++++++------------------------- + include/crypto/internal/simd.h | 12 +---- + 4 files changed, 19 insertions(+), 73 deletions(-) + +diff --git a/arch/arm/crypto/aes-ce-glue.c b/arch/arm/crypto/aes-ce-glue.c +index b668c97663ec0..f5b66f4cf45d9 100644 +--- a/arch/arm/crypto/aes-ce-glue.c ++++ b/arch/arm/crypto/aes-ce-glue.c +@@ -711,7 +711,7 @@ static int __init aes_init(void) + algname = aes_algs[i].base.cra_name + 2; + drvname = aes_algs[i].base.cra_driver_name + 2; + basename = aes_algs[i].base.cra_driver_name; +- simd = simd_skcipher_create_compat(algname, drvname, basename); ++ simd = simd_skcipher_create_compat(aes_algs + i, algname, drvname, basename); + err = PTR_ERR(simd); + if (IS_ERR(simd)) + goto unregister_simds; +diff --git a/arch/arm/crypto/aes-neonbs-glue.c b/arch/arm/crypto/aes-neonbs-glue.c +index f00f042ef3570..0ca94b90bc4ec 100644 +--- a/arch/arm/crypto/aes-neonbs-glue.c ++++ b/arch/arm/crypto/aes-neonbs-glue.c +@@ -539,7 +539,7 @@ static int __init aes_init(void) + algname = aes_algs[i].base.cra_name + 2; + drvname = aes_algs[i].base.cra_driver_name + 2; + basename = aes_algs[i].base.cra_driver_name; +- simd = simd_skcipher_create_compat(algname, drvname, basename); ++ simd = simd_skcipher_create_compat(aes_algs + i, algname, drvname, basename); + err = PTR_ERR(simd); + if (IS_ERR(simd)) + goto unregister_simds; +diff --git a/crypto/simd.c b/crypto/simd.c +index edaa479a1ec5e..d109866641a26 100644 +--- a/crypto/simd.c ++++ b/crypto/simd.c +@@ -136,27 +136,19 @@ static int simd_skcipher_init(struct crypto_skcipher *tfm) + return 0; + } + +-struct simd_skcipher_alg *simd_skcipher_create_compat(const char *algname, ++struct simd_skcipher_alg *simd_skcipher_create_compat(struct skcipher_alg *ialg, ++ const char *algname, + const char *drvname, + const char *basename) + { + struct simd_skcipher_alg *salg; +- struct crypto_skcipher *tfm; +- struct skcipher_alg *ialg; + struct skcipher_alg *alg; + int err; + +- tfm = crypto_alloc_skcipher(basename, CRYPTO_ALG_INTERNAL, +- CRYPTO_ALG_INTERNAL | CRYPTO_ALG_ASYNC); +- if (IS_ERR(tfm)) +- return ERR_CAST(tfm); +- +- ialg = crypto_skcipher_alg(tfm); +- + salg = kzalloc(sizeof(*salg), GFP_KERNEL); + if (!salg) { + salg = ERR_PTR(-ENOMEM); +- goto out_put_tfm; ++ goto out; + } + + salg->ialg_name = basename; +@@ -195,30 +187,16 @@ struct simd_skcipher_alg *simd_skcipher_create_compat(const char *algname, + if (err) + goto out_free_salg; + +-out_put_tfm: +- crypto_free_skcipher(tfm); ++out: + return salg; + + out_free_salg: + kfree(salg); + salg = ERR_PTR(err); +- goto out_put_tfm; ++ goto out; + } + EXPORT_SYMBOL_GPL(simd_skcipher_create_compat); + +-struct simd_skcipher_alg *simd_skcipher_create(const char *algname, +- const char *basename) +-{ +- char drvname[CRYPTO_MAX_ALG_NAME]; +- +- if (snprintf(drvname, CRYPTO_MAX_ALG_NAME, "simd-%s", basename) >= +- CRYPTO_MAX_ALG_NAME) +- return ERR_PTR(-ENAMETOOLONG); +- +- return simd_skcipher_create_compat(algname, drvname, basename); +-} +-EXPORT_SYMBOL_GPL(simd_skcipher_create); +- + void simd_skcipher_free(struct simd_skcipher_alg *salg) + { + crypto_unregister_skcipher(&salg->alg); +@@ -246,7 +224,7 @@ int simd_register_skciphers_compat(struct skcipher_alg *algs, int count, + algname = algs[i].base.cra_name + 2; + drvname = algs[i].base.cra_driver_name + 2; + basename = algs[i].base.cra_driver_name; +- simd = simd_skcipher_create_compat(algname, drvname, basename); ++ simd = simd_skcipher_create_compat(algs + i, algname, drvname, basename); + err = PTR_ERR(simd); + if (IS_ERR(simd)) + goto err_unregister; +@@ -383,27 +361,19 @@ static int simd_aead_init(struct crypto_aead *tfm) + return 0; + } + +-struct simd_aead_alg *simd_aead_create_compat(const char *algname, +- const char *drvname, +- const char *basename) ++static struct simd_aead_alg *simd_aead_create_compat(struct aead_alg *ialg, ++ const char *algname, ++ const char *drvname, ++ const char *basename) + { + struct simd_aead_alg *salg; +- struct crypto_aead *tfm; +- struct aead_alg *ialg; + struct aead_alg *alg; + int err; + +- tfm = crypto_alloc_aead(basename, CRYPTO_ALG_INTERNAL, +- CRYPTO_ALG_INTERNAL | CRYPTO_ALG_ASYNC); +- if (IS_ERR(tfm)) +- return ERR_CAST(tfm); +- +- ialg = crypto_aead_alg(tfm); +- + salg = kzalloc(sizeof(*salg), GFP_KERNEL); + if (!salg) { + salg = ERR_PTR(-ENOMEM); +- goto out_put_tfm; ++ goto out; + } + + salg->ialg_name = basename; +@@ -442,36 +412,20 @@ struct simd_aead_alg *simd_aead_create_compat(const char *algname, + if (err) + goto out_free_salg; + +-out_put_tfm: +- crypto_free_aead(tfm); ++out: + return salg; + + out_free_salg: + kfree(salg); + salg = ERR_PTR(err); +- goto out_put_tfm; +-} +-EXPORT_SYMBOL_GPL(simd_aead_create_compat); +- +-struct simd_aead_alg *simd_aead_create(const char *algname, +- const char *basename) +-{ +- char drvname[CRYPTO_MAX_ALG_NAME]; +- +- if (snprintf(drvname, CRYPTO_MAX_ALG_NAME, "simd-%s", basename) >= +- CRYPTO_MAX_ALG_NAME) +- return ERR_PTR(-ENAMETOOLONG); +- +- return simd_aead_create_compat(algname, drvname, basename); ++ goto out; + } +-EXPORT_SYMBOL_GPL(simd_aead_create); + +-void simd_aead_free(struct simd_aead_alg *salg) ++static void simd_aead_free(struct simd_aead_alg *salg) + { + crypto_unregister_aead(&salg->alg); + kfree(salg); + } +-EXPORT_SYMBOL_GPL(simd_aead_free); + + int simd_register_aeads_compat(struct aead_alg *algs, int count, + struct simd_aead_alg **simd_algs) +@@ -493,7 +447,7 @@ int simd_register_aeads_compat(struct aead_alg *algs, int count, + algname = algs[i].base.cra_name + 2; + drvname = algs[i].base.cra_driver_name + 2; + basename = algs[i].base.cra_driver_name; +- simd = simd_aead_create_compat(algname, drvname, basename); ++ simd = simd_aead_create_compat(algs + i, algname, drvname, basename); + err = PTR_ERR(simd); + if (IS_ERR(simd)) + goto err_unregister; +diff --git a/include/crypto/internal/simd.h b/include/crypto/internal/simd.h +index d2316242a9884..be97b97a75dd2 100644 +--- a/include/crypto/internal/simd.h ++++ b/include/crypto/internal/simd.h +@@ -14,11 +14,10 @@ + struct simd_skcipher_alg; + struct skcipher_alg; + +-struct simd_skcipher_alg *simd_skcipher_create_compat(const char *algname, ++struct simd_skcipher_alg *simd_skcipher_create_compat(struct skcipher_alg *ialg, ++ const char *algname, + const char *drvname, + const char *basename); +-struct simd_skcipher_alg *simd_skcipher_create(const char *algname, +- const char *basename); + void simd_skcipher_free(struct simd_skcipher_alg *alg); + + int simd_register_skciphers_compat(struct skcipher_alg *algs, int count, +@@ -32,13 +31,6 @@ void simd_unregister_skciphers(struct skcipher_alg *algs, int count, + struct simd_aead_alg; + struct aead_alg; + +-struct simd_aead_alg *simd_aead_create_compat(const char *algname, +- const char *drvname, +- const char *basename); +-struct simd_aead_alg *simd_aead_create(const char *algname, +- const char *basename); +-void simd_aead_free(struct simd_aead_alg *alg); +- + int simd_register_aeads_compat(struct aead_alg *algs, int count, + struct simd_aead_alg **simd_algs); + +-- +2.43.0 + diff --git a/queue-6.10/crypto-x86-sha256-add-parentheses-around-macros-sing.patch b/queue-6.10/crypto-x86-sha256-add-parentheses-around-macros-sing.patch new file mode 100644 index 00000000000..6f308f97b05 --- /dev/null +++ b/queue-6.10/crypto-x86-sha256-add-parentheses-around-macros-sing.patch @@ -0,0 +1,92 @@ +From d0305bdd838b5c6a7f732265840a33791e7ca8fc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Aug 2024 21:48:02 -0700 +Subject: crypto: x86/sha256 - Add parentheses around macros' single arguments + +From: Fangrui Song + +[ Upstream commit 3363c460ef726ba693704dbcd73b7e7214ccc788 ] + +The macros FOUR_ROUNDS_AND_SCHED and DO_4ROUNDS rely on an +unexpected/undocumented behavior of the GNU assembler, which might +change in the future +(https://sourceware.org/bugzilla/show_bug.cgi?id=32073). + + M (1) (2) // 1 arg !? Future: 2 args + M 1 + 2 // 1 arg !? Future: 3 args + + M 1 2 // 2 args + +Add parentheses around the single arguments to support future GNU +assembler and LLVM integrated assembler (when the IsOperator hack from +the following link is dropped). + +Link: https://github.com/llvm/llvm-project/commit/055006475e22014b28a070db1bff41ca15f322f0 +Signed-off-by: Fangrui Song +Reviewed-by: Jan Beulich +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + arch/x86/crypto/sha256-avx2-asm.S | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/arch/x86/crypto/sha256-avx2-asm.S b/arch/x86/crypto/sha256-avx2-asm.S +index 0ffb072be9561..0bbec1c75cd0b 100644 +--- a/arch/x86/crypto/sha256-avx2-asm.S ++++ b/arch/x86/crypto/sha256-avx2-asm.S +@@ -592,22 +592,22 @@ SYM_TYPED_FUNC_START(sha256_transform_rorx) + leaq K256+0*32(%rip), INP ## reuse INP as scratch reg + vpaddd (INP, SRND), X0, XFER + vmovdqa XFER, 0*32+_XFER(%rsp, SRND) +- FOUR_ROUNDS_AND_SCHED _XFER + 0*32 ++ FOUR_ROUNDS_AND_SCHED (_XFER + 0*32) + + leaq K256+1*32(%rip), INP + vpaddd (INP, SRND), X0, XFER + vmovdqa XFER, 1*32+_XFER(%rsp, SRND) +- FOUR_ROUNDS_AND_SCHED _XFER + 1*32 ++ FOUR_ROUNDS_AND_SCHED (_XFER + 1*32) + + leaq K256+2*32(%rip), INP + vpaddd (INP, SRND), X0, XFER + vmovdqa XFER, 2*32+_XFER(%rsp, SRND) +- FOUR_ROUNDS_AND_SCHED _XFER + 2*32 ++ FOUR_ROUNDS_AND_SCHED (_XFER + 2*32) + + leaq K256+3*32(%rip), INP + vpaddd (INP, SRND), X0, XFER + vmovdqa XFER, 3*32+_XFER(%rsp, SRND) +- FOUR_ROUNDS_AND_SCHED _XFER + 3*32 ++ FOUR_ROUNDS_AND_SCHED (_XFER + 3*32) + + add $4*32, SRND + cmp $3*4*32, SRND +@@ -618,12 +618,12 @@ SYM_TYPED_FUNC_START(sha256_transform_rorx) + leaq K256+0*32(%rip), INP + vpaddd (INP, SRND), X0, XFER + vmovdqa XFER, 0*32+_XFER(%rsp, SRND) +- DO_4ROUNDS _XFER + 0*32 ++ DO_4ROUNDS (_XFER + 0*32) + + leaq K256+1*32(%rip), INP + vpaddd (INP, SRND), X1, XFER + vmovdqa XFER, 1*32+_XFER(%rsp, SRND) +- DO_4ROUNDS _XFER + 1*32 ++ DO_4ROUNDS (_XFER + 1*32) + add $2*32, SRND + + vmovdqa X2, X0 +@@ -651,8 +651,8 @@ SYM_TYPED_FUNC_START(sha256_transform_rorx) + xor SRND, SRND + .align 16 + .Lloop3: +- DO_4ROUNDS _XFER + 0*32 + 16 +- DO_4ROUNDS _XFER + 1*32 + 16 ++ DO_4ROUNDS (_XFER + 0*32 + 16) ++ DO_4ROUNDS (_XFER + 1*32 + 16) + add $2*32, SRND + cmp $4*4*32, SRND + jb .Lloop3 +-- +2.43.0 + diff --git a/queue-6.10/drivers-perf-arm_spe-use-perf_allow_kernel-for-permi.patch b/queue-6.10/drivers-perf-arm_spe-use-perf_allow_kernel-for-permi.patch new file mode 100644 index 00000000000..394b357875e --- /dev/null +++ b/queue-6.10/drivers-perf-arm_spe-use-perf_allow_kernel-for-permi.patch @@ -0,0 +1,115 @@ +From d1d69a973092a4e75c8b3caaf25d9ebb8e6babc6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Aug 2024 15:51:12 +0100 +Subject: drivers/perf: arm_spe: Use perf_allow_kernel() for permissions + +From: James Clark + +[ Upstream commit 5e9629d0ae977d6f6916d7e519724804e95f0b07 ] + +Use perf_allow_kernel() for 'pa_enable' (physical addresses), +'pct_enable' (physical timestamps) and context IDs. This means that +perf_event_paranoid is now taken into account and LSM hooks can be used, +which is more consistent with other perf_event_open calls. For example +PERF_SAMPLE_PHYS_ADDR uses perf_allow_kernel() rather than just +perfmon_capable(). + +This also indirectly fixes the following error message which is +misleading because perf_event_paranoid is not taken into account by +perfmon_capable(): + + $ perf record -e arm_spe/pa_enable/ + + Error: + Access to performance monitoring and observability operations is + limited. Consider adjusting /proc/sys/kernel/perf_event_paranoid + setting ... + +Suggested-by: Al Grant +Signed-off-by: James Clark +Link: https://lore.kernel.org/r/20240827145113.1224604-1-james.clark@linaro.org +Link: https://lore.kernel.org/all/20240807120039.GD37996@noisy.programming.kicks-ass.net/ +Signed-off-by: Will Deacon +Signed-off-by: Sasha Levin +--- + drivers/perf/arm_spe_pmu.c | 9 ++++----- + include/linux/perf_event.h | 8 +------- + kernel/events/core.c | 9 +++++++++ + 3 files changed, 14 insertions(+), 12 deletions(-) + +diff --git a/drivers/perf/arm_spe_pmu.c b/drivers/perf/arm_spe_pmu.c +index 9100d82bfabc0..3569050f9cf37 100644 +--- a/drivers/perf/arm_spe_pmu.c ++++ b/drivers/perf/arm_spe_pmu.c +@@ -41,7 +41,7 @@ + + /* + * Cache if the event is allowed to trace Context information. +- * This allows us to perform the check, i.e, perfmon_capable(), ++ * This allows us to perform the check, i.e, perf_allow_kernel(), + * in the context of the event owner, once, during the event_init(). + */ + #define SPE_PMU_HW_FLAGS_CX 0x00001 +@@ -50,7 +50,7 @@ static_assert((PERF_EVENT_FLAG_ARCH & SPE_PMU_HW_FLAGS_CX) == SPE_PMU_HW_FLAGS_C + + static void set_spe_event_has_cx(struct perf_event *event) + { +- if (IS_ENABLED(CONFIG_PID_IN_CONTEXTIDR) && perfmon_capable()) ++ if (IS_ENABLED(CONFIG_PID_IN_CONTEXTIDR) && !perf_allow_kernel(&event->attr)) + event->hw.flags |= SPE_PMU_HW_FLAGS_CX; + } + +@@ -745,9 +745,8 @@ static int arm_spe_pmu_event_init(struct perf_event *event) + + set_spe_event_has_cx(event); + reg = arm_spe_event_to_pmscr(event); +- if (!perfmon_capable() && +- (reg & (PMSCR_EL1_PA | PMSCR_EL1_PCT))) +- return -EACCES; ++ if (reg & (PMSCR_EL1_PA | PMSCR_EL1_PCT)) ++ return perf_allow_kernel(&event->attr); + + return 0; + } +diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h +index 393fb13733b02..a7f1a3a4d1dce 100644 +--- a/include/linux/perf_event.h ++++ b/include/linux/perf_event.h +@@ -1608,13 +1608,7 @@ static inline int perf_is_paranoid(void) + return sysctl_perf_event_paranoid > -1; + } + +-static inline int perf_allow_kernel(struct perf_event_attr *attr) +-{ +- if (sysctl_perf_event_paranoid > 1 && !perfmon_capable()) +- return -EACCES; +- +- return security_perf_event_open(attr, PERF_SECURITY_KERNEL); +-} ++int perf_allow_kernel(struct perf_event_attr *attr); + + static inline int perf_allow_cpu(struct perf_event_attr *attr) + { +diff --git a/kernel/events/core.c b/kernel/events/core.c +index 36191add55c37..081d9692ce747 100644 +--- a/kernel/events/core.c ++++ b/kernel/events/core.c +@@ -13362,6 +13362,15 @@ const struct perf_event_attr *perf_event_attrs(struct perf_event *event) + return &event->attr; + } + ++int perf_allow_kernel(struct perf_event_attr *attr) ++{ ++ if (sysctl_perf_event_paranoid > 1 && !perfmon_capable()) ++ return -EACCES; ++ ++ return security_perf_event_open(attr, PERF_SECURITY_KERNEL); ++} ++EXPORT_SYMBOL_GPL(perf_allow_kernel); ++ + /* + * Inherit an event from parent task to child task. + * +-- +2.43.0 + diff --git a/queue-6.10/drm-amd-display-add-null-check-for-afb-in-amdgpu_dm_.patch b/queue-6.10/drm-amd-display-add-null-check-for-afb-in-amdgpu_dm_.patch new file mode 100644 index 00000000000..db31e272b08 --- /dev/null +++ b/queue-6.10/drm-amd-display-add-null-check-for-afb-in-amdgpu_dm_.patch @@ -0,0 +1,54 @@ +From 3b3000be1d25b696bdd18e588ec59a5967cf78fa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 2 Aug 2024 12:35:13 +0530 +Subject: drm/amd/display: Add null check for 'afb' in + amdgpu_dm_plane_handle_cursor_update (v2) + +From: Srinivasan Shanmugam + +[ Upstream commit cd9e9e0852d501f169aa3bb34e4b413d2eb48c37 ] + +This commit adds a null check for the 'afb' variable in the +amdgpu_dm_plane_handle_cursor_update function. Previously, 'afb' was +assumed to be null, but was used later in the code without a null check. +This could potentially lead to a null pointer dereference. + +Changes since v1: +- Moved the null check for 'afb' to the line where 'afb' is used. (Alex) + +Fixes the below: +drivers/gpu/drm/amd/amdgpu/../display/amdgpu_dm/amdgpu_dm_plane.c:1298 amdgpu_dm_plane_handle_cursor_update() error: we previously assumed 'afb' could be null (see line 1252) + +Cc: Tom Chung +Cc: Rodrigo Siqueira +Cc: Roman Li +Cc: Alex Hung +Cc: Aurabindo Pillai +Cc: Harry Wentland +Co-developed-by: Alex Hung +Signed-off-by: Alex Hung +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Tom Chung +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +index 7d47acdd11d55..fe7a99aee47dd 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +@@ -1285,7 +1285,8 @@ void amdgpu_dm_plane_handle_cursor_update(struct drm_plane *plane, + adev->dm.dc->caps.color.dpp.gamma_corr) + attributes.attribute_flags.bits.ENABLE_CURSOR_DEGAMMA = 1; + +- attributes.pitch = afb->base.pitches[0] / afb->base.format->cpp[0]; ++ if (afb) ++ attributes.pitch = afb->base.pitches[0] / afb->base.format->cpp[0]; + + if (crtc_state->stream) { + mutex_lock(&adev->dm.dc_lock); +-- +2.43.0 + diff --git a/queue-6.10/drm-amd-display-add-null-check-for-clk_mgr-and-clk_m.patch b/queue-6.10/drm-amd-display-add-null-check-for-clk_mgr-and-clk_m.patch new file mode 100644 index 00000000000..83abc8f2379 --- /dev/null +++ b/queue-6.10/drm-amd-display-add-null-check-for-clk_mgr-and-clk_m.patch @@ -0,0 +1,67 @@ +From d832dd4067b47f8b1a95dd4eb5c0e964d13f3e57 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Cc: Rodrigo Siqueira +Cc: Roman Li +Cc: Alex Hung +Cc: Aurabindo Pillai +Cc: Harry Wentland +Cc: Hamza Mahfooz +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Alex Hung +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c +index 05c5d4f04e1bd..0f72a54e92af6 100644 +--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c ++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c +@@ -626,7 +626,7 @@ void dcn30_init_hw(struct dc *dc) + uint32_t backlight = MAX_BACKLIGHT_LEVEL; + uint32_t user_level = MAX_BACKLIGHT_LEVEL; + +- if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) ++ if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->init_clocks) + dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); + + // Initialize the dccg +@@ -787,11 +787,12 @@ void dcn30_init_hw(struct dc *dc) + if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks) + dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub); + +- if (dc->clk_mgr->funcs->notify_wm_ranges) ++ if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->notify_wm_ranges) + dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr); + + //if softmax is enabled then hardmax will be set by a different call +- if (dc->clk_mgr->funcs->set_hard_max_memclk && !dc->clk_mgr->dc_mode_softmax_enabled) ++ if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->set_hard_max_memclk && ++ !dc->clk_mgr->dc_mode_softmax_enabled) + dc->clk_mgr->funcs->set_hard_max_memclk(dc->clk_mgr); + + if (dc->res_pool->hubbub->funcs->force_pstate_change_control) +-- +2.43.0 + diff --git a/queue-6.10/drm-amd-display-add-null-check-for-clk_mgr-in-dcn32_.patch b/queue-6.10/drm-amd-display-add-null-check-for-clk_mgr-in-dcn32_.patch new file mode 100644 index 00000000000..edff9a01f3b --- /dev/null +++ b/queue-6.10/drm-amd-display-add-null-check-for-clk_mgr-in-dcn32_.patch @@ -0,0 +1,65 @@ +From 62a74751c15fea9c06713204890b9e8fde70f1d5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Cc: Rodrigo Siqueira +Cc: Roman Li +Cc: Alex Hung +Cc: Aurabindo Pillai +Cc: Harry Wentland +Cc: Hamza Mahfooz +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Alex Hung +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c +index 5fc377f51f562..aaf576f30a777 100644 +--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c ++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c +@@ -752,7 +752,7 @@ void dcn32_init_hw(struct dc *dc) + uint32_t backlight = MAX_BACKLIGHT_LEVEL; + uint32_t user_level = MAX_BACKLIGHT_LEVEL; + +- if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) ++ if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->init_clocks) + dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); + + // Initialize the dccg +@@ -931,10 +931,11 @@ void dcn32_init_hw(struct dc *dc) + if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks) + dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub); + +- if (dc->clk_mgr->funcs->notify_wm_ranges) ++ if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->notify_wm_ranges) + dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr); + +- if (dc->clk_mgr->funcs->set_hard_max_memclk && !dc->clk_mgr->dc_mode_softmax_enabled) ++ if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->set_hard_max_memclk && ++ !dc->clk_mgr->dc_mode_softmax_enabled) + dc->clk_mgr->funcs->set_hard_max_memclk(dc->clk_mgr); + + if (dc->res_pool->hubbub->funcs->force_pstate_change_control) +-- +2.43.0 + diff --git a/queue-6.10/drm-amd-display-add-null-check-for-function-pointer-.patch b/queue-6.10/drm-amd-display-add-null-check-for-function-pointer-.patch new file mode 100644 index 00000000000..7a0e771563e --- /dev/null +++ b/queue-6.10/drm-amd-display-add-null-check-for-function-pointer-.patch @@ -0,0 +1,53 @@ +From cb38ad368fde8941cd8c9be6f1062bf6c97ba182 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Cc: Rodrigo Siqueira +Cc: Roman Li +Cc: Alex Hung +Cc: Aurabindo Pillai +Cc: Harry Wentland +Cc: Hamza Mahfooz +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Tom Chung +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c +index 7d833fa6dd77c..58e8b7482f4f5 100644 +--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c ++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c +@@ -1040,7 +1040,8 @@ bool dcn20_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, + /* + * if above if is not executed then 'params' equal to 0 and set in bypass + */ +- mpc->funcs->set_output_gamma(mpc, mpcc_id, params); ++ if (mpc->funcs->set_output_gamma) ++ mpc->funcs->set_output_gamma(mpc, mpcc_id, params); + + return true; + } +-- +2.43.0 + diff --git a/queue-6.10/drm-amd-display-add-null-check-for-function-pointer-.patch-29584 b/queue-6.10/drm-amd-display-add-null-check-for-function-pointer-.patch-29584 new file mode 100644 index 00000000000..5151454df58 --- /dev/null +++ b/queue-6.10/drm-amd-display-add-null-check-for-function-pointer-.patch-29584 @@ -0,0 +1,53 @@ +From fca9b6da616d9b8b455d5aa1cd82d144df43e3bb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Cc: Rodrigo Siqueira +Cc: Roman Li +Cc: Alex Hung +Cc: Aurabindo Pillai +Cc: Harry Wentland +Cc: Hamza Mahfooz +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Tom Chung +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c +index aaf576f30a777..c050acc4ff065 100644 +--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c ++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c +@@ -581,7 +581,9 @@ bool dcn32_set_output_transfer_func(struct dc *dc, + } + } + +- mpc->funcs->set_output_gamma(mpc, mpcc_id, params); ++ if (mpc->funcs->set_output_gamma) ++ mpc->funcs->set_output_gamma(mpc, mpcc_id, params); ++ + return ret; + } + +-- +2.43.0 + diff --git a/queue-6.10/drm-amd-display-add-null-check-for-head_pipe-in-dcn2.patch b/queue-6.10/drm-amd-display-add-null-check-for-head_pipe-in-dcn2.patch new file mode 100644 index 00000000000..ec8f3028d8a --- /dev/null +++ b/queue-6.10/drm-amd-display-add-null-check-for-head_pipe-in-dcn2.patch @@ -0,0 +1,55 @@ +From 242bd6becd5cfaf0ffc77fc8b27c2e8db2c507e3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Cc: Rodrigo Siqueira +Cc: Roman Li +Cc: Alex Hung +Cc: Aurabindo Pillai +Cc: Harry Wentland +Cc: Hamza Mahfooz +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Tom Chung +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c +index 070a4efb308bd..1aeede348bd39 100644 +--- a/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c +@@ -1005,8 +1005,10 @@ static struct pipe_ctx *dcn201_acquire_free_pipe_for_layer( + struct pipe_ctx *head_pipe = resource_get_otg_master_for_stream(res_ctx, opp_head_pipe->stream); + struct pipe_ctx *idle_pipe = resource_find_free_secondary_pipe_legacy(res_ctx, pool, head_pipe); + +- if (!head_pipe) ++ if (!head_pipe) { + ASSERT(0); ++ return NULL; ++ } + + if (!idle_pipe) + return NULL; +-- +2.43.0 + diff --git a/queue-6.10/drm-amd-display-add-null-check-for-head_pipe-in-dcn3.patch b/queue-6.10/drm-amd-display-add-null-check-for-head_pipe-in-dcn3.patch new file mode 100644 index 00000000000..34e68e82235 --- /dev/null +++ b/queue-6.10/drm-amd-display-add-null-check-for-head_pipe-in-dcn3.patch @@ -0,0 +1,55 @@ +From 44d9709ea1656c2885dfaa4f08a73876aa1f1604 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Cc: Rodrigo Siqueira +Cc: Roman Li +Cc: Alex Hung +Cc: Aurabindo Pillai +Cc: Harry Wentland +Cc: Hamza Mahfooz +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Tom Chung +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c +index d84c8e0e5c2f0..9209bcad699a8 100644 +--- a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c +@@ -2664,8 +2664,10 @@ static struct pipe_ctx *dcn32_acquire_idle_pipe_for_head_pipe_in_layer( + struct resource_context *old_ctx = &stream->ctx->dc->current_state->res_ctx; + int head_index; + +- if (!head_pipe) ++ if (!head_pipe) { + ASSERT(0); ++ return NULL; ++ } + + /* + * Modified from dcn20_acquire_idle_pipe_for_layer +-- +2.43.0 + diff --git a/queue-6.10/drm-amd-display-add-null-check-for-top_pipe_to_progr.patch b/queue-6.10/drm-amd-display-add-null-check-for-top_pipe_to_progr.patch new file mode 100644 index 00000000000..297a050e948 --- /dev/null +++ b/queue-6.10/drm-amd-display-add-null-check-for-top_pipe_to_progr.patch @@ -0,0 +1,52 @@ +From 89d6ae7d67b12b481ea6f83a0c0dafb5c78f497d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 25 Jul 2024 07:23:48 +0530 +Subject: drm/amd/display: Add null check for top_pipe_to_program in + commit_planes_for_stream + +From: Srinivasan Shanmugam + +[ Upstream commit 66d71a72539e173a9b00ca0b1852cbaa5f5bf1ad ] + +This commit addresses a null pointer dereference issue in the +`commit_planes_for_stream` function at line 4140. The issue could occur +when `top_pipe_to_program` is null. + +The fix adds a check to ensure `top_pipe_to_program` is not null before +accessing its stream_res. This prevents a null pointer dereference. + +Reported by smatch: +drivers/gpu/drm/amd/amdgpu/../display/dc/core/dc.c:4140 commit_planes_for_stream() error: we previously assumed 'top_pipe_to_program' could be null (see line 3906) + +Cc: Tom Chung +Cc: Rodrigo Siqueira +Cc: Roman Li +Cc: Alex Hung +Cc: Aurabindo Pillai +Cc: Harry Wentland +Cc: Hamza Mahfooz +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Tom Chung +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/core/dc.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c +index da237f718dbdd..3bd18e862945f 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c +@@ -3970,7 +3970,8 @@ static void commit_planes_for_stream(struct dc *dc, + } + + if ((update_type != UPDATE_TYPE_FAST) && stream->update_flags.bits.dsc_changed) +- if (top_pipe_to_program->stream_res.tg->funcs->lock_doublebuffer_enable) { ++ if (top_pipe_to_program && ++ top_pipe_to_program->stream_res.tg->funcs->lock_doublebuffer_enable) { + top_pipe_to_program->stream_res.tg->funcs->wait_for_state( + top_pipe_to_program->stream_res.tg, + CRTC_STATE_VACTIVE); +-- +2.43.0 + diff --git a/queue-6.10/drm-amd-display-avoid-overflow-assignment-in-link_dp.patch b/queue-6.10/drm-amd-display-avoid-overflow-assignment-in-link_dp.patch new file mode 100644 index 00000000000..bdba7ceb384 --- /dev/null +++ b/queue-6.10/drm-amd-display-avoid-overflow-assignment-in-link_dp.patch @@ -0,0 +1,71 @@ +From 02f404fb3acce378df2c7923ee2e5976a7c854f0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 17 Jul 2024 09:17:56 -0600 +Subject: drm/amd/display: Avoid overflow assignment in link_dp_cts + +From: Alex Hung + +[ Upstream commit a15268787b79fd183dd526cc16bec9af4f4e49a1 ] + +sampling_rate is an uint8_t but is assigned an unsigned int, and thus it +can overflow. As a result, sampling_rate is changed to uint32_t. + +Similarly, LINK_QUAL_PATTERN_SET has a size of 2 bits, and it should +only be assigned to a value less or equal than 4. + +This fixes 2 INTEGER_OVERFLOW issues reported by Coverity. + +Signed-off-by: Alex Hung +Reviewed-by: Wenjing Liu +Tested-by: Daniel Wheeler +Signed-off-by: Rodrigo Siqueira +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/dc_dp_types.h | 2 +- + drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c | 3 ++- + drivers/gpu/drm/amd/display/include/dpcd_defs.h | 1 + + 3 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h +index 519c3df78ee5b..95c275bf649bd 100644 +--- a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h ++++ b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h +@@ -727,7 +727,7 @@ struct dp_audio_test_data_flags { + struct dp_audio_test_data { + + struct dp_audio_test_data_flags flags; +- uint8_t sampling_rate; ++ uint32_t sampling_rate; + uint8_t channel_count; + uint8_t pattern_type; + uint8_t pattern_period[8]; +diff --git a/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c +index 8d1a1cc94a8b3..6b27ac56f60d8 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c ++++ b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c +@@ -775,7 +775,8 @@ bool dp_set_test_pattern( + core_link_read_dpcd(link, DP_TRAINING_PATTERN_SET, + &training_pattern.raw, + sizeof(training_pattern)); +- training_pattern.v1_3.LINK_QUAL_PATTERN_SET = pattern; ++ if (pattern <= PHY_TEST_PATTERN_END_DP11) ++ training_pattern.v1_3.LINK_QUAL_PATTERN_SET = pattern; + core_link_write_dpcd(link, DP_TRAINING_PATTERN_SET, + &training_pattern.raw, + sizeof(training_pattern)); +diff --git a/drivers/gpu/drm/amd/display/include/dpcd_defs.h b/drivers/gpu/drm/amd/display/include/dpcd_defs.h +index aee5170f5fb23..c246235e4afec 100644 +--- a/drivers/gpu/drm/amd/display/include/dpcd_defs.h ++++ b/drivers/gpu/drm/amd/display/include/dpcd_defs.h +@@ -76,6 +76,7 @@ enum dpcd_phy_test_patterns { + PHY_TEST_PATTERN_D10_2, + PHY_TEST_PATTERN_SYMBOL_ERROR, + PHY_TEST_PATTERN_PRBS7, ++ PHY_TEST_PATTERN_END_DP11 = PHY_TEST_PATTERN_PRBS7, + PHY_TEST_PATTERN_80BIT_CUSTOM,/* For DP1.2 only */ + PHY_TEST_PATTERN_CP2520_1, + PHY_TEST_PATTERN_CP2520_2, +-- +2.43.0 + diff --git a/queue-6.10/drm-amd-display-check-link_res-hpo_dp_link_enc-befor.patch b/queue-6.10/drm-amd-display-check-link_res-hpo_dp_link_enc-befor.patch new file mode 100644 index 00000000000..13d59af026a --- /dev/null +++ b/queue-6.10/drm-amd-display-check-link_res-hpo_dp_link_enc-befor.patch @@ -0,0 +1,54 @@ +From 6d43441908a3563e2d5a542156fbdad58e157e7d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Jun 2024 16:45:39 -0600 +Subject: drm/amd/display: Check link_res->hpo_dp_link_enc before using it + +From: Alex Hung + +[ Upstream commit 0beca868cde8742240cd0038141c30482d2b7eb8 ] + +[WHAT & HOW] +Functions dp_enable_link_phy and dp_disable_link_phy can pass link_res +without initializing hpo_dp_link_enc and it is necessary to check for +null before dereferencing. + +This fixes 2 FORWARD_NULL issues reported by Coverity. + +Reviewed-by: Rodrigo Siqueira +Signed-off-by: Jerry Zuo +Signed-off-by: Alex Hung +Tested-by: Daniel Wheeler +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.c b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.c +index e1257404357b1..d0148f10dfc0a 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.c ++++ b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.c +@@ -28,6 +28,8 @@ + #include "dccg.h" + #include "clk_mgr.h" + ++#define DC_LOGGER link->ctx->logger ++ + void set_hpo_dp_throttled_vcp_size(struct pipe_ctx *pipe_ctx, + struct fixed31_32 throttled_vcp_size) + { +@@ -124,6 +126,11 @@ void disable_hpo_dp_link_output(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal) + { ++ if (!link_res->hpo_dp_link_enc) { ++ DC_LOG_ERROR("%s: invalid hpo_dp_link_enc\n", __func__); ++ return; ++ } ++ + link_res->hpo_dp_link_enc->funcs->link_disable(link_res->hpo_dp_link_enc); + link_res->hpo_dp_link_enc->funcs->disable_link_phy( + link_res->hpo_dp_link_enc, signal); +-- +2.43.0 + diff --git a/queue-6.10/drm-amd-display-check-null-initialized-variables.patch b/queue-6.10/drm-amd-display-check-null-initialized-variables.patch new file mode 100644 index 00000000000..7ed4821f252 --- /dev/null +++ b/queue-6.10/drm-amd-display-check-null-initialized-variables.patch @@ -0,0 +1,55 @@ +From dee3df10e147a8152d95b51c254228f0bb10367e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Jun 2024 17:34:18 -0600 +Subject: drm/amd/display: Check null-initialized variables + +From: Alex Hung + +[ 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 +Reviewed-by: Rodrigo Siqueira +Signed-off-by: Jerry Zuo +Signed-off-by: Alex Hung +Tested-by: Daniel Wheeler +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c +index ebcf5ece209a4..bf8c89fe95a7e 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c ++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c +@@ -871,8 +871,9 @@ static bool subvp_drr_schedulable(struct dc *dc, struct dc_state *context) + * for VBLANK: (VACTIVE region of the SubVP pipe can fit the MALL prefetch, VBLANK frame time, + * and the max of (VBLANK blanking time, MALL region)). + */ +- if (stretched_drr_us < (1 / (double)drr_timing->min_refresh_in_uhz) * 1000000 * 1000000 && +- subvp_active_us - prefetch_us - stretched_drr_us - max_vblank_mallregion > 0) ++ if (drr_timing && ++ stretched_drr_us < (1 / (double)drr_timing->min_refresh_in_uhz) * 1000000 * 1000000 && ++ subvp_active_us - prefetch_us - stretched_drr_us - max_vblank_mallregion > 0) + schedulable = true; + + return schedulable; +@@ -937,7 +938,7 @@ static bool subvp_vblank_schedulable(struct dc *dc, struct dc_state *context) + if (!subvp_pipe && pipe_mall_type == SUBVP_MAIN) + subvp_pipe = pipe; + } +- if (found) { ++ if (found && subvp_pipe) { + phantom_stream = dc_state_get_paired_subvp_stream(context, subvp_pipe->stream); + main_timing = &subvp_pipe->stream->timing; + phantom_timing = &phantom_stream->timing; +-- +2.43.0 + diff --git a/queue-6.10/drm-amd-display-check-null-pointers-before-using-dc-.patch b/queue-6.10/drm-amd-display-check-null-pointers-before-using-dc-.patch new file mode 100644 index 00000000000..3def87f4bbf --- /dev/null +++ b/queue-6.10/drm-amd-display-check-null-pointers-before-using-dc-.patch @@ -0,0 +1,46 @@ +From d08eb057942b3b212e05761baf51166bf77cd21f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Jul 2024 15:29:09 -0600 +Subject: drm/amd/display: Check null pointers before using dc->clk_mgr + +From: Alex Hung + +[ Upstream commit 95d9e0803e51d5a24276b7643b244c7477daf463 ] + +[WHY & HOW] +dc->clk_mgr is null checked previously in the same function, indicating +it might be null. + +Passing "dc" to "dc->hwss.apply_idle_power_optimizations", which +dereferences null "dc->clk_mgr". (The function pointer resolves to +"dcn35_apply_idle_power_optimizations".) + +This fixes 1 FORWARD_NULL issue reported by Coverity. + +Reviewed-by: Rodrigo Siqueira +Signed-off-by: Alex Hung +Signed-off-by: Tom Chung +Tested-by: Daniel Wheeler +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/core/dc.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c +index 3bd18e862945f..daeb80abf435f 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c +@@ -5211,7 +5211,8 @@ void dc_allow_idle_optimizations_internal(struct dc *dc, bool allow, char const + if (allow == dc->idle_optimizations_allowed) + return; + +- if (dc->hwss.apply_idle_power_optimizations && dc->hwss.apply_idle_power_optimizations(dc, allow)) ++ if (dc->hwss.apply_idle_power_optimizations && dc->clk_mgr != NULL && ++ dc->hwss.apply_idle_power_optimizations(dc, allow)) + dc->idle_optimizations_allowed = allow; + } + +-- +2.43.0 + diff --git a/queue-6.10/drm-amd-display-check-null-pointers-before-using-the.patch b/queue-6.10/drm-amd-display-check-null-pointers-before-using-the.patch new file mode 100644 index 00000000000..8a6ada35530 --- /dev/null +++ b/queue-6.10/drm-amd-display-check-null-pointers-before-using-the.patch @@ -0,0 +1,66 @@ +From 7494a8c5a6b12d99e5176bc470b87b178f2bd9fa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Jun 2024 17:38:16 -0600 +Subject: drm/amd/display: Check null pointers before using them + +From: Alex Hung + +[ 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 +Signed-off-by: Jerry Zuo +Signed-off-by: Alex Hung +Tested-by: Daniel Wheeler +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +index 3541d154cc8d0..9a578b1df141f 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -6951,6 +6951,9 @@ create_validate_stream_for_sink(struct amdgpu_dm_connector *aconnector, + int requested_bpc = drm_state ? drm_state->max_requested_bpc : 8; + enum dc_status dc_result = DC_OK; + ++ if (!dm_state) ++ return NULL; ++ + do { + stream = create_stream_for_sink(connector, drm_mode, + dm_state, old_stream, +@@ -8963,7 +8966,7 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_state *state, + if (acrtc) + old_crtc_state = drm_atomic_get_old_crtc_state(state, &acrtc->base); + +- if (!acrtc->wb_enabled) ++ if (!acrtc || !acrtc->wb_enabled) + continue; + + dm_old_crtc_state = to_dm_crtc_state(old_crtc_state); +@@ -9362,9 +9365,10 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) + + DRM_INFO("[HDCP_DM] hdcp_update_display enable_encryption = %x\n", enable_encryption); + +- hdcp_update_display( +- adev->dm.hdcp_workqueue, aconnector->dc_link->link_index, aconnector, +- new_con_state->hdcp_content_type, enable_encryption); ++ if (aconnector->dc_link) ++ hdcp_update_display( ++ adev->dm.hdcp_workqueue, aconnector->dc_link->link_index, aconnector, ++ new_con_state->hdcp_content_type, enable_encryption); + } + } + +-- +2.43.0 + diff --git a/queue-6.10/drm-amd-display-check-phantom_stream-before-it-is-us.patch b/queue-6.10/drm-amd-display-check-phantom_stream-before-it-is-us.patch new file mode 100644 index 00000000000..5cb6a20070f --- /dev/null +++ b/queue-6.10/drm-amd-display-check-phantom_stream-before-it-is-us.patch @@ -0,0 +1,41 @@ +From 6f9e87a4cc4aaa15e752a72084b86a6193dd4564 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 20 Jun 2024 20:23:41 -0600 +Subject: drm/amd/display: Check phantom_stream before it is used + +From: Alex Hung + +[ 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 +Signed-off-by: Jerry Zuo +Signed-off-by: Alex Hung +Tested-by: Daniel Wheeler +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c +index 9209bcad699a8..55fbe86383c04 100644 +--- a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c +@@ -1714,6 +1714,9 @@ void dcn32_add_phantom_pipes(struct dc *dc, struct dc_state *context, + // be a valid candidate for SubVP (i.e. has a plane, stream, doesn't + // already have phantom pipe assigned, etc.) by previous checks. + phantom_stream = dcn32_enable_phantom_stream(dc, context, pipes, pipe_cnt, index); ++ if (!phantom_stream) ++ return; ++ + dcn32_enable_phantom_plane(dc, context, phantom_stream, index); + + for (i = 0; i < dc->res_pool->pipe_count; i++) { +-- +2.43.0 + diff --git a/queue-6.10/drm-amd-display-check-stream-before-comparing-them.patch b/queue-6.10/drm-amd-display-check-stream-before-comparing-them.patch new file mode 100644 index 00000000000..0ef909bc11c --- /dev/null +++ b/queue-6.10/drm-amd-display-check-stream-before-comparing-them.patch @@ -0,0 +1,41 @@ +From 3a9cb6560abc4458be1e1714180d74aef6d8227d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Jun 2024 20:05:14 -0600 +Subject: drm/amd/display: Check stream before comparing them + +From: Alex Hung + +[ Upstream commit 35ff747c86767937ee1e0ca987545b7eed7a0810 ] + +[WHAT & HOW] +amdgpu_dm can pass a null stream to dc_is_stream_unchanged. It is +necessary to check for null before dereferencing them. + +This fixes 1 FORWARD_NULL issue reported by Coverity. + +Reviewed-by: Rodrigo Siqueira +Signed-off-by: Jerry Zuo +Signed-off-by: Alex Hung +Tested-by: Daniel Wheeler +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +index 7462c34793799..58f6155fecc5a 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +@@ -3134,6 +3134,8 @@ static bool are_stream_backends_same( + bool dc_is_stream_unchanged( + struct dc_stream_state *old_stream, struct dc_stream_state *stream) + { ++ if (!old_stream || !stream) ++ return false; + + if (!are_stream_backends_same(old_stream, stream)) + return false; +-- +2.43.0 + diff --git a/queue-6.10/drm-amd-display-fix-double-free-issue-during-amdgpu-.patch b/queue-6.10/drm-amd-display-fix-double-free-issue-during-amdgpu-.patch new file mode 100644 index 00000000000..2ac192363d5 --- /dev/null +++ b/queue-6.10/drm-amd-display-fix-double-free-issue-during-amdgpu-.patch @@ -0,0 +1,79 @@ +From f586f182bb227a804c7b1da87eeabaae99407308 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Aug 2024 18:45:22 -0400 +Subject: drm/amd/display: fix double free issue during amdgpu module unload + +From: Tim Huang + +[ Upstream commit 20b5a8f9f4670a8503aa9fa95ca632e77c6bf55d ] + +Flexible endpoints use DIGs from available inflexible endpoints, +so only the encoders of inflexible links need to be freed. +Otherwise, a double free issue may occur when unloading the +amdgpu module. + +[ 279.190523] RIP: 0010:__slab_free+0x152/0x2f0 +[ 279.190577] Call Trace: +[ 279.190580] +[ 279.190582] ? show_regs+0x69/0x80 +[ 279.190590] ? die+0x3b/0x90 +[ 279.190595] ? do_trap+0xc8/0xe0 +[ 279.190601] ? do_error_trap+0x73/0xa0 +[ 279.190605] ? __slab_free+0x152/0x2f0 +[ 279.190609] ? exc_invalid_op+0x56/0x70 +[ 279.190616] ? __slab_free+0x152/0x2f0 +[ 279.190642] ? asm_exc_invalid_op+0x1f/0x30 +[ 279.190648] ? dcn10_link_encoder_destroy+0x19/0x30 [amdgpu] +[ 279.191096] ? __slab_free+0x152/0x2f0 +[ 279.191102] ? dcn10_link_encoder_destroy+0x19/0x30 [amdgpu] +[ 279.191469] kfree+0x260/0x2b0 +[ 279.191474] dcn10_link_encoder_destroy+0x19/0x30 [amdgpu] +[ 279.191821] link_destroy+0xd7/0x130 [amdgpu] +[ 279.192248] dc_destruct+0x90/0x270 [amdgpu] +[ 279.192666] dc_destroy+0x19/0x40 [amdgpu] +[ 279.193020] amdgpu_dm_fini+0x16e/0x200 [amdgpu] +[ 279.193432] dm_hw_fini+0x26/0x40 [amdgpu] +[ 279.193795] amdgpu_device_fini_hw+0x24c/0x400 [amdgpu] +[ 279.194108] amdgpu_driver_unload_kms+0x4f/0x70 [amdgpu] +[ 279.194436] amdgpu_pci_remove+0x40/0x80 [amdgpu] +[ 279.194632] pci_device_remove+0x3a/0xa0 +[ 279.194638] device_remove+0x40/0x70 +[ 279.194642] device_release_driver_internal+0x1ad/0x210 +[ 279.194647] driver_detach+0x4e/0xa0 +[ 279.194650] bus_remove_driver+0x6f/0xf0 +[ 279.194653] driver_unregister+0x33/0x60 +[ 279.194657] pci_unregister_driver+0x44/0x90 +[ 279.194662] amdgpu_exit+0x19/0x1f0 [amdgpu] +[ 279.194939] __do_sys_delete_module.isra.0+0x198/0x2f0 +[ 279.194946] __x64_sys_delete_module+0x16/0x20 +[ 279.194950] do_syscall_64+0x58/0x120 +[ 279.194954] entry_SYSCALL_64_after_hwframe+0x6e/0x76 +[ 279.194980] + +Reviewed-by: Rodrigo Siqueira +Signed-off-by: Tim Huang +Reviewed-by: Roman Li +Signed-off-by: Roman Li +Tested-by: Daniel Wheeler +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/link/link_factory.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/link/link_factory.c b/drivers/gpu/drm/amd/display/dc/link/link_factory.c +index 72df9bdfb23ff..608491f860b29 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/link_factory.c ++++ b/drivers/gpu/drm/amd/display/dc/link/link_factory.c +@@ -385,7 +385,7 @@ static void link_destruct(struct dc_link *link) + if (link->panel_cntl) + link->panel_cntl->funcs->destroy(&link->panel_cntl); + +- if (link->link_enc) { ++ if (link->link_enc && !link->is_dig_mapping_flexible) { + /* Update link encoder resource tracking variables. These are used for + * the dynamic assignment of link encoders to streams. Virtual links + * are not assigned encoder resources on creation. +-- +2.43.0 + diff --git a/queue-6.10/drm-amd-display-fix-index-out-of-bounds-in-dcn30-col.patch b/queue-6.10/drm-amd-display-fix-index-out-of-bounds-in-dcn30-col.patch new file mode 100644 index 00000000000..01121e15180 --- /dev/null +++ b/queue-6.10/drm-amd-display-fix-index-out-of-bounds-in-dcn30-col.patch @@ -0,0 +1,54 @@ +From 8902693d3ceb14f9dcdf74c87347152bb229b481 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Jul 2024 18:05:20 +0530 +Subject: drm/amd/display: Fix index out of bounds in DCN30 color + transformation + +From: Srinivasan Shanmugam + +[ Upstream commit d81873f9e715b72d4f8d391c8eb243946f784dfc ] + +This commit addresses a potential index out of bounds issue in the +`cm3_helper_translate_curve_to_hw_format` function in the DCN30 color +management module. The issue could occur when the index 'i' exceeds the +number of transfer function points (TRANSFER_FUNC_POINTS). + +The fix adds a check to ensure 'i' is within bounds before accessing the +transfer function points. If 'i' is out of bounds, the function returns +false to indicate an error. + +drivers/gpu/drm/amd/amdgpu/../display/dc/dcn30/dcn30_cm_common.c:180 cm3_helper_translate_curve_to_hw_format() error: buffer overflow 'output_tf->tf_pts.red' 1025 <= s32max +drivers/gpu/drm/amd/amdgpu/../display/dc/dcn30/dcn30_cm_common.c:181 cm3_helper_translate_curve_to_hw_format() error: buffer overflow 'output_tf->tf_pts.green' 1025 <= s32max +drivers/gpu/drm/amd/amdgpu/../display/dc/dcn30/dcn30_cm_common.c:182 cm3_helper_translate_curve_to_hw_format() error: buffer overflow 'output_tf->tf_pts.blue' 1025 <= s32max + +Cc: Tom Chung +Cc: Rodrigo Siqueira +Cc: Roman Li +Cc: Alex Hung +Cc: Aurabindo Pillai +Cc: Harry Wentland +Cc: Hamza Mahfooz +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Tom Chung +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c +index edc77615d0973..0433f6b5dac78 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c +@@ -177,6 +177,8 @@ bool cm3_helper_translate_curve_to_hw_format( + i += increment) { + if (j == hw_points) + break; ++ if (i >= TRANSFER_FUNC_POINTS) ++ return false; + rgb_resulted[j].red = output_tf->tf_pts.red[i]; + rgb_resulted[j].green = output_tf->tf_pts.green[i]; + rgb_resulted[j].blue = output_tf->tf_pts.blue[i]; +-- +2.43.0 + diff --git a/queue-6.10/drm-amd-display-fix-index-out-of-bounds-in-dcn30-deg.patch b/queue-6.10/drm-amd-display-fix-index-out-of-bounds-in-dcn30-deg.patch new file mode 100644 index 00000000000..15525988644 --- /dev/null +++ b/queue-6.10/drm-amd-display-fix-index-out-of-bounds-in-dcn30-deg.patch @@ -0,0 +1,55 @@ +From 2637755aeaeef1b03c8b4cf994632c87e5da157c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Jul 2024 18:44:02 +0530 +Subject: drm/amd/display: Fix index out of bounds in DCN30 degamma hardware + format translation + +From: Srinivasan Shanmugam + +[ Upstream commit bc50b614d59990747dd5aeced9ec22f9258991ff ] + +This commit addresses a potential index out of bounds issue in the +`cm3_helper_translate_curve_to_degamma_hw_format` function in the DCN30 +color management module. The issue could occur when the index 'i' +exceeds the number of transfer function points (TRANSFER_FUNC_POINTS). + +The fix adds a check to ensure 'i' is within bounds before accessing the +transfer function points. If 'i' is out of bounds, the function returns +false to indicate an error. + +Reported by smatch: +drivers/gpu/drm/amd/amdgpu/../display/dc/dcn30/dcn30_cm_common.c:338 cm3_helper_translate_curve_to_degamma_hw_format() error: buffer overflow 'output_tf->tf_pts.red' 1025 <= s32max +drivers/gpu/drm/amd/amdgpu/../display/dc/dcn30/dcn30_cm_common.c:339 cm3_helper_translate_curve_to_degamma_hw_format() error: buffer overflow 'output_tf->tf_pts.green' 1025 <= s32max +drivers/gpu/drm/amd/amdgpu/../display/dc/dcn30/dcn30_cm_common.c:340 cm3_helper_translate_curve_to_degamma_hw_format() error: buffer overflow 'output_tf->tf_pts.blue' 1025 <= s32max + +Cc: Tom Chung +Cc: Rodrigo Siqueira +Cc: Roman Li +Cc: Alex Hung +Cc: Aurabindo Pillai +Cc: Harry Wentland +Cc: Hamza Mahfooz +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Tom Chung +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c +index b8327237ed441..edc77615d0973 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c +@@ -335,6 +335,8 @@ bool cm3_helper_translate_curve_to_degamma_hw_format( + i += increment) { + if (j == hw_points - 1) + break; ++ if (i >= TRANSFER_FUNC_POINTS) ++ return false; + rgb_resulted[j].red = output_tf->tf_pts.red[i]; + rgb_resulted[j].green = output_tf->tf_pts.green[i]; + rgb_resulted[j].blue = output_tf->tf_pts.blue[i]; +-- +2.43.0 + diff --git a/queue-6.10/drm-amd-display-fix-index-out-of-bounds-in-degamma-h.patch b/queue-6.10/drm-amd-display-fix-index-out-of-bounds-in-degamma-h.patch new file mode 100644 index 00000000000..5a7797b27b3 --- /dev/null +++ b/queue-6.10/drm-amd-display-fix-index-out-of-bounds-in-degamma-h.patch @@ -0,0 +1,55 @@ +From 90dce44ee6b6b61ee161f3818a2361651dfc7afe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Jul 2024 17:48:27 +0530 +Subject: drm/amd/display: Fix index out of bounds in degamma hardware format + translation + +From: Srinivasan Shanmugam + +[ Upstream commit b7e99058eb2e86aabd7a10761e76cae33d22b49f ] + +Fixes index out of bounds issue in +`cm_helper_translate_curve_to_degamma_hw_format` function. The issue +could occur when the index 'i' exceeds the number of transfer function +points (TRANSFER_FUNC_POINTS). + +The fix adds a check to ensure 'i' is within bounds before accessing the +transfer function points. If 'i' is out of bounds the function returns +false to indicate an error. + +Reported by smatch: +drivers/gpu/drm/amd/amdgpu/../display/dc/dcn10/dcn10_cm_common.c:594 cm_helper_translate_curve_to_degamma_hw_format() error: buffer overflow 'output_tf->tf_pts.red' 1025 <= s32max +drivers/gpu/drm/amd/amdgpu/../display/dc/dcn10/dcn10_cm_common.c:595 cm_helper_translate_curve_to_degamma_hw_format() error: buffer overflow 'output_tf->tf_pts.green' 1025 <= s32max +drivers/gpu/drm/amd/amdgpu/../display/dc/dcn10/dcn10_cm_common.c:596 cm_helper_translate_curve_to_degamma_hw_format() error: buffer overflow 'output_tf->tf_pts.blue' 1025 <= s32max + +Cc: Tom Chung +Cc: Rodrigo Siqueira +Cc: Roman Li +Cc: Alex Hung +Cc: Aurabindo Pillai +Cc: Harry Wentland +Cc: Hamza Mahfooz +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Tom Chung +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c +index 0b49362f71b06..eaed5d1c398aa 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c +@@ -591,6 +591,8 @@ bool cm_helper_translate_curve_to_degamma_hw_format( + i += increment) { + if (j == hw_points - 1) + break; ++ if (i >= TRANSFER_FUNC_POINTS) ++ return false; + rgb_resulted[j].red = output_tf->tf_pts.red[i]; + rgb_resulted[j].green = output_tf->tf_pts.green[i]; + rgb_resulted[j].blue = output_tf->tf_pts.blue[i]; +-- +2.43.0 + diff --git a/queue-6.10/drm-amd-display-handle-null-stream_status-in-planes_.patch b/queue-6.10/drm-amd-display-handle-null-stream_status-in-planes_.patch new file mode 100644 index 00000000000..27a7fea06a5 --- /dev/null +++ b/queue-6.10/drm-amd-display-handle-null-stream_status-in-planes_.patch @@ -0,0 +1,52 @@ +From 01bdb1d36092eae870d7dc4734deddbbe4546343 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Jul 2024 19:31:55 +0530 +Subject: drm/amd/display: Handle null 'stream_status' in + 'planes_changed_for_existing_stream' + +From: Srinivasan Shanmugam + +[ Upstream commit 8141f21b941710ecebe49220b69822cab3abd23d ] + +This commit adds a null check for 'stream_status' in the function +'planes_changed_for_existing_stream'. Previously, the code assumed +'stream_status' could be null, but did not handle the case where it was +actually null. This could lead to a null pointer dereference. + +Reported by smatch: +drivers/gpu/drm/amd/amdgpu/../display/dc/core/dc_resource.c:3784 planes_changed_for_existing_stream() error: we previously assumed 'stream_status' could be null (see line 3774) + +Cc: Tom Chung +Cc: Rodrigo Siqueira +Cc: Roman Li +Cc: Alex Hung +Cc: Aurabindo Pillai +Cc: Harry Wentland +Cc: Hamza Mahfooz +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Tom Chung +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +index 786b56e96a816..7462c34793799 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +@@ -3662,8 +3662,10 @@ static bool planes_changed_for_existing_stream(struct dc_state *context, + } + } + +- if (!stream_status) ++ if (!stream_status) { + ASSERT(0); ++ return false; ++ } + + for (i = 0; i < set_count; i++) + if (set[i].stream == stream) +-- +2.43.0 + diff --git a/queue-6.10/drm-amd-display-initialize-get_bytes_per_element-s-d.patch b/queue-6.10/drm-amd-display-initialize-get_bytes_per_element-s-d.patch new file mode 100644 index 00000000000..49752f05510 --- /dev/null +++ b/queue-6.10/drm-amd-display-initialize-get_bytes_per_element-s-d.patch @@ -0,0 +1,55 @@ +From 15b6e650cb40bb877b553f7d0a30b8bd5dcc0b9a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Jul 2024 09:57:01 -0600 +Subject: drm/amd/display: Initialize get_bytes_per_element's default to 1 + +From: Alex Hung + +[ Upstream commit 4067f4fa0423a89fb19a30b57231b384d77d2610 ] + +Variables, used as denominators and maybe not assigned to other values, +should not be 0. bytes_per_element_y & bytes_per_element_c are +initialized by get_bytes_per_element() which should never return 0. + +This fixes 10 DIVIDE_BY_ZERO issues reported by Coverity. + +Signed-off-by: Alex Hung +Reviewed-by: Aurabindo Pillai +Tested-by: Daniel Wheeler +Signed-off-by: Rodrigo Siqueira +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c | 2 +- + .../gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c +index 0fc9f3e3ffaef..f603486af6e30 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c ++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c +@@ -78,7 +78,7 @@ static void calculate_ttu_cursor(struct display_mode_lib *mode_lib, + + static unsigned int get_bytes_per_element(enum source_format_class source_format, bool is_chroma) + { +- unsigned int ret_val = 0; ++ unsigned int ret_val = 1; + + if (source_format == dm_444_16) { + if (!is_chroma) +diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c +index 618f4b682ab1b..9f28e4d3c664c 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c ++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c +@@ -53,7 +53,7 @@ static void calculate_ttu_cursor( + + static unsigned int get_bytes_per_element(enum source_format_class source_format, bool is_chroma) + { +- unsigned int ret_val = 0; ++ unsigned int ret_val = 1; + + if (source_format == dm_444_16) { + if (!is_chroma) +-- +2.43.0 + diff --git a/queue-6.10/drm-amd-display-pass-non-null-to-dcn20_validate_appl.patch b/queue-6.10/drm-amd-display-pass-non-null-to-dcn20_validate_appl.patch new file mode 100644 index 00000000000..75c7cfa1fe9 --- /dev/null +++ b/queue-6.10/drm-amd-display-pass-non-null-to-dcn20_validate_appl.patch @@ -0,0 +1,73 @@ +From 10aa1c246de785f2329bb0ce0f95800c224d2a80 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Jerry Zuo +Signed-off-by: Alex Hung +Tested-by: Daniel Wheeler +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c | 3 ++- + drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c | 3 ++- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c +index 6b380e037e3f8..c0d1b41eb9004 100644 +--- a/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c +@@ -2033,6 +2033,7 @@ bool dcn20_fast_validate_bw( + { + bool out = false; + int split[MAX_PIPES] = { 0 }; ++ bool merge[MAX_PIPES] = { false }; + int pipe_cnt, i, pipe_idx, vlevel; + + ASSERT(pipes); +@@ -2057,7 +2058,7 @@ bool dcn20_fast_validate_bw( + if (vlevel > context->bw_ctx.dml.soc.num_states) + goto validate_fail; + +- vlevel = dcn20_validate_apply_pipe_split_flags(dc, context, vlevel, split, NULL); ++ vlevel = dcn20_validate_apply_pipe_split_flags(dc, context, vlevel, split, merge); + + /*initialize pipe_just_split_from to invalid idx*/ + for (i = 0; i < MAX_PIPES; i++) +diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c +index 8663cbc3d1cf5..347e6aaea582f 100644 +--- a/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c +@@ -774,6 +774,7 @@ bool dcn21_fast_validate_bw(struct dc *dc, + { + bool out = false; + int split[MAX_PIPES] = { 0 }; ++ bool merge[MAX_PIPES] = { false }; + int pipe_cnt, i, pipe_idx, vlevel; + + ASSERT(pipes); +@@ -816,7 +817,7 @@ bool dcn21_fast_validate_bw(struct dc *dc, + goto validate_fail; + } + +- vlevel = dcn20_validate_apply_pipe_split_flags(dc, context, vlevel, split, NULL); ++ vlevel = dcn20_validate_apply_pipe_split_flags(dc, context, vlevel, split, merge); + + for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; +-- +2.43.0 + diff --git a/queue-6.10/drm-amd-display-use-gpuvm_min_page_size_kbytes-for-d.patch b/queue-6.10/drm-amd-display-use-gpuvm_min_page_size_kbytes-for-d.patch new file mode 100644 index 00000000000..30284888b7a --- /dev/null +++ b/queue-6.10/drm-amd-display-use-gpuvm_min_page_size_kbytes-for-d.patch @@ -0,0 +1,96 @@ +From 74cb516c5ef321e3636b64783a42545f4c3a975c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Jun Lei +Tested-by: Daniel Wheeler +Signed-off-by: Rodrigo Siqueira +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../display/dc/dml2/dml2_translation_helper.c | 20 +++++++++++++------ + 1 file changed, 14 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c b/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c +index edff6b447680c..d5dbfb33f93dc 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c ++++ b/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c +@@ -828,7 +828,9 @@ static void get_scaler_data_for_plane(const struct dc_plane_state *in, struct dc + memcpy(out, &temp_pipe->plane_res.scl_data, sizeof(*out)); + } + +-static void populate_dummy_dml_plane_cfg(struct dml_plane_cfg_st *out, unsigned int location, const struct dc_stream_state *in) ++static void populate_dummy_dml_plane_cfg(struct dml_plane_cfg_st *out, unsigned int location, ++ const struct dc_stream_state *in, ++ const struct soc_bounding_box_st *soc) + { + dml_uint_t width, height; + +@@ -845,7 +847,7 @@ static void populate_dummy_dml_plane_cfg(struct dml_plane_cfg_st *out, unsigned + out->CursorBPP[location] = dml_cur_32bit; + out->CursorWidth[location] = 256; + +- out->GPUVMMinPageSizeKBytes[location] = 256; ++ out->GPUVMMinPageSizeKBytes[location] = soc->gpuvm_min_page_size_kbytes; + + out->ViewportWidth[location] = width; + out->ViewportHeight[location] = height; +@@ -882,7 +884,9 @@ static void populate_dummy_dml_plane_cfg(struct dml_plane_cfg_st *out, unsigned + out->ScalerEnabled[location] = false; + } + +-static void populate_dml_plane_cfg_from_plane_state(struct dml_plane_cfg_st *out, unsigned int location, const struct dc_plane_state *in, struct dc_state *context) ++static void populate_dml_plane_cfg_from_plane_state(struct dml_plane_cfg_st *out, unsigned int location, ++ const struct dc_plane_state *in, struct dc_state *context, ++ const struct soc_bounding_box_st *soc) + { + struct scaler_data *scaler_data = kzalloc(sizeof(*scaler_data), GFP_KERNEL); + if (!scaler_data) +@@ -893,7 +897,7 @@ static void populate_dml_plane_cfg_from_plane_state(struct dml_plane_cfg_st *out + out->CursorBPP[location] = dml_cur_32bit; + out->CursorWidth[location] = 256; + +- out->GPUVMMinPageSizeKBytes[location] = 256; ++ out->GPUVMMinPageSizeKBytes[location] = soc->gpuvm_min_page_size_kbytes; + + out->ViewportWidth[location] = scaler_data->viewport.width; + out->ViewportHeight[location] = scaler_data->viewport.height; +@@ -1174,7 +1178,8 @@ void map_dc_state_into_dml_display_cfg(struct dml2_context *dml2, struct dc_stat + disp_cfg_plane_location = dml_dispcfg->num_surfaces++; + + populate_dummy_dml_surface_cfg(&dml_dispcfg->surface, disp_cfg_plane_location, context->streams[i]); +- populate_dummy_dml_plane_cfg(&dml_dispcfg->plane, disp_cfg_plane_location, context->streams[i]); ++ populate_dummy_dml_plane_cfg(&dml_dispcfg->plane, disp_cfg_plane_location, ++ context->streams[i], &dml2->v20.dml_core_ctx.soc); + + dml_dispcfg->plane.BlendingAndTiming[disp_cfg_plane_location] = disp_cfg_stream_location; + +@@ -1190,7 +1195,10 @@ void map_dc_state_into_dml_display_cfg(struct dml2_context *dml2, struct dc_stat + ASSERT(disp_cfg_plane_location >= 0 && disp_cfg_plane_location <= __DML2_WRAPPER_MAX_STREAMS_PLANES__); + + populate_dml_surface_cfg_from_plane_state(dml2->v20.dml_core_ctx.project, &dml_dispcfg->surface, disp_cfg_plane_location, context->stream_status[i].plane_states[j]); +- populate_dml_plane_cfg_from_plane_state(&dml_dispcfg->plane, disp_cfg_plane_location, context->stream_status[i].plane_states[j], context); ++ populate_dml_plane_cfg_from_plane_state( ++ &dml_dispcfg->plane, disp_cfg_plane_location, ++ context->stream_status[i].plane_states[j], context, ++ &dml2->v20.dml_core_ctx.soc); + + if (stream_mall_type == SUBVP_MAIN) { + dml_dispcfg->plane.UseMALLForPStateChange[disp_cfg_plane_location] = dml_use_mall_pstate_change_sub_viewport; +-- +2.43.0 + diff --git a/queue-6.10/drm-amd-pm-ensure-the-fw_info-is-not-null-before-usi.patch b/queue-6.10/drm-amd-pm-ensure-the-fw_info-is-not-null-before-usi.patch new file mode 100644 index 00000000000..02fdeaf7088 --- /dev/null +++ b/queue-6.10/drm-amd-pm-ensure-the-fw_info-is-not-null-before-usi.patch @@ -0,0 +1,36 @@ +From fdead484e49c95c4bee7f8ca05eaf73092532e90 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Aug 2024 17:15:12 +0800 +Subject: drm/amd/pm: ensure the fw_info is not null before using it + +From: Tim Huang + +[ Upstream commit 186fb12e7a7b038c2710ceb2fb74068f1b5d55a4 ] + +This resolves the dereference null return value warning +reported by Coverity. + +Signed-off-by: Tim Huang +Reviewed-by: Jesse Zhang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c +index 5794b64507bf9..56a2257525806 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c +@@ -1185,6 +1185,8 @@ static int init_overdrive_limits(struct pp_hwmgr *hwmgr, + fw_info = smu_atom_get_data_table(hwmgr->adev, + GetIndexIntoMasterTable(DATA, FirmwareInfo), + &size, &frev, &crev); ++ PP_ASSERT_WITH_CODE(fw_info != NULL, ++ "Missing firmware info!", return -EINVAL); + + if ((fw_info->ucTableFormatRevision == 1) + && (le16_to_cpu(fw_info->usStructureSize) >= sizeof(ATOM_FIRMWARE_INFO_V1_4))) +-- +2.43.0 + diff --git a/queue-6.10/drm-amdgpu-add-list-empty-check-to-avoid-null-pointe.patch b/queue-6.10/drm-amdgpu-add-list-empty-check-to-avoid-null-pointe.patch new file mode 100644 index 00000000000..652e4da5c0d --- /dev/null +++ b/queue-6.10/drm-amdgpu-add-list-empty-check-to-avoid-null-pointe.patch @@ -0,0 +1,61 @@ +From eca008855174ca03f598be20cc15d16391300e7d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Aug 2024 14:42:41 +0800 +Subject: drm/amdgpu: add list empty check to avoid null pointer issue + +From: Yang Wang + +[ 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 +Reviewed-by: Tao Zhou +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c +index 9baee7c246b6d..a513819b72311 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c +@@ -80,6 +80,9 @@ static void aca_banks_release(struct aca_banks *banks) + { + struct aca_bank_node *node, *tmp; + ++ if (list_empty(&banks->list)) ++ return; ++ + list_for_each_entry_safe(node, tmp, &banks->list, node) { + list_del(&node->node); + kvfree(node); +@@ -562,9 +565,13 @@ static void aca_error_fini(struct aca_error *aerr) + struct aca_bank_error *bank_error, *tmp; + + mutex_lock(&aerr->lock); ++ if (list_empty(&aerr->list)) ++ goto out_unlock; ++ + list_for_each_entry_safe(bank_error, tmp, &aerr->list, node) + aca_bank_error_remove(aerr, bank_error); + ++out_unlock: + mutex_destroy(&aerr->lock); + } + +@@ -680,6 +687,9 @@ static void aca_manager_fini(struct aca_handle_manager *mgr) + { + struct aca_handle *handle, *tmp; + ++ if (list_empty(&mgr->list)) ++ return; ++ + list_for_each_entry_safe(handle, tmp, &mgr->list, node) + amdgpu_aca_remove_handle(handle); + } +-- +2.43.0 + diff --git a/queue-6.10/drm-amdgpu-add-raven1-gfxoff-quirk.patch b/queue-6.10/drm-amdgpu-add-raven1-gfxoff-quirk.patch new file mode 100644 index 00000000000..27e4540d3f8 --- /dev/null +++ b/queue-6.10/drm-amdgpu-add-raven1-gfxoff-quirk.patch @@ -0,0 +1,35 @@ +From 3c9741dcf701d420303ebaa8105a889b62b35d0c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Aug 2024 15:25:54 +0800 +Subject: drm/amdgpu: add raven1 gfxoff quirk + +From: Peng Liu + +[ Upstream commit 0126c0ae11e8b52ecfde9d1b174ee2f32d6c3a5d ] + +Fix screen corruption with openkylin. + +Link: https://bbs.openkylin.top/t/topic/171497 +Signed-off-by: Peng Liu +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +index 3c8c5abf35abd..c86a6363b2c3d 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +@@ -1172,6 +1172,8 @@ static const struct amdgpu_gfxoff_quirk amdgpu_gfxoff_quirk_list[] = { + { 0x1002, 0x15dd, 0x1002, 0x15dd, 0xc6 }, + /* Apple MacBook Pro (15-inch, 2019) Radeon Pro Vega 20 4 GB */ + { 0x1002, 0x69af, 0x106b, 0x019a, 0xc0 }, ++ /* https://bbs.openkylin.top/t/topic/171497 */ ++ { 0x1002, 0x15d8, 0x19e5, 0x3e14, 0xc2 }, + { 0, 0, 0, 0, 0 }, + }; + +-- +2.43.0 + diff --git a/queue-6.10/drm-amdgpu-block-mmr_read-ioctl-in-reset.patch b/queue-6.10/drm-amdgpu-block-mmr_read-ioctl-in-reset.patch new file mode 100644 index 00000000000..5876500c569 --- /dev/null +++ b/queue-6.10/drm-amdgpu-block-mmr_read-ioctl-in-reset.patch @@ -0,0 +1,111 @@ +From f284b9fcbd8c159d528a7ecff7e5ee4e9d5df29e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Aug 2024 13:40:23 -0400 +Subject: drm/amdgpu: Block MMR_READ IOCTL in reset + +From: Victor Skvortsov + +[ Upstream commit 9e823f307074c0f82b5f6044943b0086e3079bed ] + +Register access from userspace should be blocked until +reset is complete. + +Signed-off-by: Victor Skvortsov +Reviewed-by: Alex Deucher +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 43 ++++++++++++++++++------- + 1 file changed, 31 insertions(+), 12 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +index 977cde6d13626..6d4e774b6cedc 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +@@ -43,6 +43,7 @@ + #include "amdgpu_gem.h" + #include "amdgpu_display.h" + #include "amdgpu_ras.h" ++#include "amdgpu_reset.h" + #include "amd_pcie.h" + + void amdgpu_unregister_gpu_instance(struct amdgpu_device *adev) +@@ -778,6 +779,7 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) + ? -EFAULT : 0; + } + case AMDGPU_INFO_READ_MMR_REG: { ++ int ret = 0; + unsigned int n, alloc_size; + uint32_t *regs; + unsigned int se_num = (info->read_mmr_reg.instance >> +@@ -787,24 +789,37 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) + AMDGPU_INFO_MMR_SH_INDEX_SHIFT) & + AMDGPU_INFO_MMR_SH_INDEX_MASK; + ++ if (!down_read_trylock(&adev->reset_domain->sem)) ++ return -ENOENT; ++ + /* set full masks if the userspace set all bits + * in the bitfields + */ +- if (se_num == AMDGPU_INFO_MMR_SE_INDEX_MASK) ++ if (se_num == AMDGPU_INFO_MMR_SE_INDEX_MASK) { + se_num = 0xffffffff; +- else if (se_num >= AMDGPU_GFX_MAX_SE) +- return -EINVAL; +- if (sh_num == AMDGPU_INFO_MMR_SH_INDEX_MASK) ++ } else if (se_num >= AMDGPU_GFX_MAX_SE) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ if (sh_num == AMDGPU_INFO_MMR_SH_INDEX_MASK) { + sh_num = 0xffffffff; +- else if (sh_num >= AMDGPU_GFX_MAX_SH_PER_SE) +- return -EINVAL; ++ } else if (sh_num >= AMDGPU_GFX_MAX_SH_PER_SE) { ++ ret = -EINVAL; ++ goto out; ++ } + +- if (info->read_mmr_reg.count > 128) +- return -EINVAL; ++ if (info->read_mmr_reg.count > 128) { ++ ret = -EINVAL; ++ goto out; ++ } + + regs = kmalloc_array(info->read_mmr_reg.count, sizeof(*regs), GFP_KERNEL); +- if (!regs) +- return -ENOMEM; ++ if (!regs) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ + alloc_size = info->read_mmr_reg.count * sizeof(*regs); + + amdgpu_gfx_off_ctrl(adev, false); +@@ -816,13 +831,17 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) + info->read_mmr_reg.dword_offset + i); + kfree(regs); + amdgpu_gfx_off_ctrl(adev, true); +- return -EFAULT; ++ ret = -EFAULT; ++ goto out; + } + } + amdgpu_gfx_off_ctrl(adev, true); + n = copy_to_user(out, regs, min(size, alloc_size)); + kfree(regs); +- return n ? -EFAULT : 0; ++ ret = (n ? -EFAULT : 0); ++out: ++ up_read(&adev->reset_domain->sem); ++ return ret; + } + case AMDGPU_INFO_DEV_INFO: { + struct drm_amdgpu_info_device *dev_info; +-- +2.43.0 + diff --git a/queue-6.10/drm-amdgpu-disallow-multiple-bo_handles-chunks-in-on.patch b/queue-6.10/drm-amdgpu-disallow-multiple-bo_handles-chunks-in-on.patch new file mode 100644 index 00000000000..1c8f505669a --- /dev/null +++ b/queue-6.10/drm-amdgpu-disallow-multiple-bo_handles-chunks-in-on.patch @@ -0,0 +1,49 @@ +From ea14f7e443375ce5354949f73febe7aa27e3fdaf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jul 2024 11:54:30 +0200 +Subject: drm/amdgpu: disallow multiple BO_HANDLES chunks in one submit +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Pierre-Eric Pelloux-Prayer + +[ Upstream commit fec5f8e8c6bcf83ed7a392801d7b44c5ecfc1e82 ] + +Before this commit, only submits with both a BO_HANDLES chunk and a +'bo_list_handle' would be rejected (by amdgpu_cs_parser_bos). + +But if UMD sent multiple BO_HANDLES, what would happen is: +* only the last one would be really used +* all the others would leak memory as amdgpu_cs_p1_bo_handles would + overwrite the previous p->bo_list value + +This commit rejects submissions with multiple BO_HANDLES chunks to +match the implementation of the parser. + +Signed-off-by: Pierre-Eric Pelloux-Prayer +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +index 6dfdff58bffd1..78b3c067fea7e 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +@@ -263,6 +263,10 @@ static int amdgpu_cs_pass1(struct amdgpu_cs_parser *p, + if (size < sizeof(struct drm_amdgpu_bo_list_in)) + goto free_partial_kdata; + ++ /* Only a single BO list is allowed to simplify handling. */ ++ if (p->bo_list) ++ ret = -EINVAL; ++ + ret = amdgpu_cs_p1_bo_handles(p, p->chunks[i].kdata); + if (ret) + goto free_partial_kdata; +-- +2.43.0 + diff --git a/queue-6.10/drm-amdgpu-enable-gfxoff-quirk-on-hp-705g4.patch b/queue-6.10/drm-amdgpu-enable-gfxoff-quirk-on-hp-705g4.patch new file mode 100644 index 00000000000..7375fd5e64c --- /dev/null +++ b/queue-6.10/drm-amdgpu-enable-gfxoff-quirk-on-hp-705g4.patch @@ -0,0 +1,38 @@ +From ab9c7b50eb4002c898db893d88c71083de991104 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Aug 2024 15:27:08 +0800 +Subject: drm/amdgpu: enable gfxoff quirk on HP 705G4 + +From: Peng Liu + +[ Upstream commit 2c7795e245d993bcba2f716a8c93a5891ef910c9 ] + +Enabling gfxoff quirk results in perfectly usable +graphical user interface on HP 705G4 DM with R5 2400G. + +Without the quirk, X server is completely unusable as +every few seconds there is gpu reset due to ring gfx timeout. + +Signed-off-by: Peng Liu +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +index c86a6363b2c3d..0594eab666a9b 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +@@ -1174,6 +1174,8 @@ static const struct amdgpu_gfxoff_quirk amdgpu_gfxoff_quirk_list[] = { + { 0x1002, 0x69af, 0x106b, 0x019a, 0xc0 }, + /* https://bbs.openkylin.top/t/topic/171497 */ + { 0x1002, 0x15d8, 0x19e5, 0x3e14, 0xc2 }, ++ /* HP 705G4 DM with R5 2400G */ ++ { 0x1002, 0x15dd, 0x103c, 0x8464, 0xd6 }, + { 0, 0, 0, 0, 0 }, + }; + +-- +2.43.0 + diff --git a/queue-6.10/drm-amdgpu-fix-unchecked-return-value-warning-for-am.patch b/queue-6.10/drm-amdgpu-fix-unchecked-return-value-warning-for-am.patch new file mode 100644 index 00000000000..d927c25d8f1 --- /dev/null +++ b/queue-6.10/drm-amdgpu-fix-unchecked-return-value-warning-for-am.patch @@ -0,0 +1,72 @@ +From d7726729a2100aaf7a1070454c2df1ffb28dddcf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 1 Aug 2024 10:38:37 +0800 +Subject: drm/amdgpu: fix unchecked return value warning for amdgpu_gfx + +From: Tim Huang + +[ Upstream commit c0277b9d7c2ee9ee5dbc948548984f0fbb861301 ] + +This resolves the unchecded return value warning reported by Coverity. + +Signed-off-by: Tim Huang +Reviewed-by: Jesse Zhang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c | 18 ++++++++++++++---- + 1 file changed, 14 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +index e92bdc9a39d35..1935b211b527d 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +@@ -816,8 +816,11 @@ int amdgpu_gfx_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *r + int r; + + if (amdgpu_ras_is_supported(adev, ras_block->block)) { +- if (!amdgpu_persistent_edc_harvesting_supported(adev)) +- amdgpu_ras_reset_error_status(adev, AMDGPU_RAS_BLOCK__GFX); ++ if (!amdgpu_persistent_edc_harvesting_supported(adev)) { ++ r = amdgpu_ras_reset_error_status(adev, AMDGPU_RAS_BLOCK__GFX); ++ if (r) ++ return r; ++ } + + r = amdgpu_ras_block_late_init(adev, ras_block); + if (r) +@@ -961,7 +964,10 @@ uint32_t amdgpu_kiq_rreg(struct amdgpu_device *adev, uint32_t reg, uint32_t xcc_ + pr_err("critical bug! too many kiq readers\n"); + goto failed_unlock; + } +- amdgpu_ring_alloc(ring, 32); ++ r = amdgpu_ring_alloc(ring, 32); ++ if (r) ++ goto failed_unlock; ++ + amdgpu_ring_emit_rreg(ring, reg, reg_val_offs); + r = amdgpu_fence_emit_polling(ring, &seq, MAX_KIQ_REG_WAIT); + if (r) +@@ -1027,7 +1033,10 @@ void amdgpu_kiq_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v, uint3 + } + + spin_lock_irqsave(&kiq->ring_lock, flags); +- amdgpu_ring_alloc(ring, 32); ++ r = amdgpu_ring_alloc(ring, 32); ++ if (r) ++ goto failed_unlock; ++ + amdgpu_ring_emit_wreg(ring, reg, v); + r = amdgpu_fence_emit_polling(ring, &seq, MAX_KIQ_REG_WAIT); + if (r) +@@ -1063,6 +1072,7 @@ void amdgpu_kiq_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v, uint3 + + failed_undo: + amdgpu_ring_undo(ring); ++failed_unlock: + spin_unlock_irqrestore(&kiq->ring_lock, flags); + failed_kiq_write: + dev_err(adev->dev, "failed to write reg:%x\n", reg); +-- +2.43.0 + diff --git a/queue-6.10/drm-amdgpu-fix-unchecked-return-value-warning-for-am.patch-12177 b/queue-6.10/drm-amdgpu-fix-unchecked-return-value-warning-for-am.patch-12177 new file mode 100644 index 00000000000..1f16eb49900 --- /dev/null +++ b/queue-6.10/drm-amdgpu-fix-unchecked-return-value-warning-for-am.patch-12177 @@ -0,0 +1,110 @@ +From c41c7229251589c515b35d1cad324ace9059fb3d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 1 Aug 2024 13:47:55 +0800 +Subject: drm/amdgpu: fix unchecked return value warning for amdgpu_atombios + +From: Tim Huang + +[ Upstream commit 92549780e32718d64a6d08bbbb3c6fffecb541c7 ] + +This resolves the unchecded return value warning reported by Coverity. + +Signed-off-by: Tim Huang +Reviewed-by: Jesse Zhang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c | 35 ++++++++++++-------- + 1 file changed, 21 insertions(+), 14 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c +index 7dc102f0bc1d3..0c8975ac5af9e 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c +@@ -1018,8 +1018,9 @@ int amdgpu_atombios_get_clock_dividers(struct amdgpu_device *adev, + if (clock_type == COMPUTE_ENGINE_PLL_PARAM) { + args.v3.ulClockParams = cpu_to_le32((clock_type << 24) | clock); + +- amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, +- sizeof(args)); ++ if (amdgpu_atom_execute_table(adev->mode_info.atom_context, ++ index, (uint32_t *)&args, sizeof(args))) ++ return -EINVAL; + + dividers->post_div = args.v3.ucPostDiv; + dividers->enable_post_div = (args.v3.ucCntlFlag & +@@ -1039,8 +1040,9 @@ int amdgpu_atombios_get_clock_dividers(struct amdgpu_device *adev, + if (strobe_mode) + args.v5.ucInputFlag = ATOM_PLL_INPUT_FLAG_PLL_STROBE_MODE_EN; + +- amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, +- sizeof(args)); ++ if (amdgpu_atom_execute_table(adev->mode_info.atom_context, ++ index, (uint32_t *)&args, sizeof(args))) ++ return -EINVAL; + + dividers->post_div = args.v5.ucPostDiv; + dividers->enable_post_div = (args.v5.ucCntlFlag & +@@ -1058,8 +1060,9 @@ int amdgpu_atombios_get_clock_dividers(struct amdgpu_device *adev, + /* fusion */ + args.v4.ulClock = cpu_to_le32(clock); /* 10 khz */ + +- amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, +- sizeof(args)); ++ if (amdgpu_atom_execute_table(adev->mode_info.atom_context, ++ index, (uint32_t *)&args, sizeof(args))) ++ return -EINVAL; + + dividers->post_divider = dividers->post_div = args.v4.ucPostDiv; + dividers->real_clock = le32_to_cpu(args.v4.ulClock); +@@ -1070,8 +1073,9 @@ int amdgpu_atombios_get_clock_dividers(struct amdgpu_device *adev, + args.v6_in.ulClock.ulComputeClockFlag = clock_type; + args.v6_in.ulClock.ulClockFreq = cpu_to_le32(clock); /* 10 khz */ + +- amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, +- sizeof(args)); ++ if (amdgpu_atom_execute_table(adev->mode_info.atom_context, ++ index, (uint32_t *)&args, sizeof(args))) ++ return -EINVAL; + + dividers->whole_fb_div = le16_to_cpu(args.v6_out.ulFbDiv.usFbDiv); + dividers->frac_fb_div = le16_to_cpu(args.v6_out.ulFbDiv.usFbDivFrac); +@@ -1113,8 +1117,9 @@ int amdgpu_atombios_get_memory_pll_dividers(struct amdgpu_device *adev, + if (strobe_mode) + args.ucInputFlag |= MPLL_INPUT_FLAG_STROBE_MODE_EN; + +- amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, +- sizeof(args)); ++ if (amdgpu_atom_execute_table(adev->mode_info.atom_context, ++ index, (uint32_t *)&args, sizeof(args))) ++ return -EINVAL; + + mpll_param->clkfrac = le16_to_cpu(args.ulFbDiv.usFbDivFrac); + mpll_param->clkf = le16_to_cpu(args.ulFbDiv.usFbDiv); +@@ -1211,8 +1216,9 @@ int amdgpu_atombios_get_max_vddc(struct amdgpu_device *adev, u8 voltage_type, + args.v2.ucVoltageMode = 0; + args.v2.usVoltageLevel = 0; + +- amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, +- sizeof(args)); ++ if (amdgpu_atom_execute_table(adev->mode_info.atom_context, ++ index, (uint32_t *)&args, sizeof(args))) ++ return -EINVAL; + + *voltage = le16_to_cpu(args.v2.usVoltageLevel); + break; +@@ -1221,8 +1227,9 @@ int amdgpu_atombios_get_max_vddc(struct amdgpu_device *adev, u8 voltage_type, + args.v3.ucVoltageMode = ATOM_GET_VOLTAGE_LEVEL; + args.v3.usVoltageLevel = cpu_to_le16(voltage_id); + +- amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, +- sizeof(args)); ++ if (amdgpu_atom_execute_table(adev->mode_info.atom_context, ++ index, (uint32_t *)&args, sizeof(args))) ++ return -EINVAL; + + *voltage = le16_to_cpu(args.v3.usVoltageLevel); + break; +-- +2.43.0 + diff --git a/queue-6.10/drm-amdgpu-gfx10-use-rlc-safe-mode-for-soft-recovery.patch b/queue-6.10/drm-amdgpu-gfx10-use-rlc-safe-mode-for-soft-recovery.patch new file mode 100644 index 00000000000..4a43894d906 --- /dev/null +++ b/queue-6.10/drm-amdgpu-gfx10-use-rlc-safe-mode-for-soft-recovery.patch @@ -0,0 +1,35 @@ +From d48d9048adce8926942b9f7750a67aefb6825b9f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Jul 2024 18:20:34 -0400 +Subject: drm/amdgpu/gfx10: use rlc safe mode for soft recovery + +From: Alex Deucher + +[ Upstream commit ead60e9c4e29c8574cae1be4fe3af1d9a978fb0f ] + +Protect the MMIO access with safe mode. + +Acked-by: Vitaly Prosyak +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +index 536287ddd2ec1..6204336750c6a 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +@@ -8897,7 +8897,9 @@ static void gfx_v10_0_ring_soft_recovery(struct amdgpu_ring *ring, + value = REG_SET_FIELD(value, SQ_CMD, MODE, 0x01); + value = REG_SET_FIELD(value, SQ_CMD, CHECK_VMID, 1); + value = REG_SET_FIELD(value, SQ_CMD, VM_ID, vmid); ++ amdgpu_gfx_rlc_enter_safe_mode(adev, 0); + WREG32_SOC15(GC, 0, mmSQ_CMD, value); ++ amdgpu_gfx_rlc_exit_safe_mode(adev, 0); + } + + static void +-- +2.43.0 + diff --git a/queue-6.10/drm-amdgpu-gfx11-enter-safe-mode-before-touching-cp_.patch b/queue-6.10/drm-amdgpu-gfx11-enter-safe-mode-before-touching-cp_.patch new file mode 100644 index 00000000000..333e84c9886 --- /dev/null +++ b/queue-6.10/drm-amdgpu-gfx11-enter-safe-mode-before-touching-cp_.patch @@ -0,0 +1,43 @@ +From eefee339f47697cbe172d60ee24a5d5d2fb5fd76 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 12 Jul 2024 15:36:19 -0400 +Subject: drm/amdgpu/gfx11: enter safe mode before touching CP_INT_CNTL + +From: Alex Deucher + +[ Upstream commit b5be054c585110b2c5c1b180136800e8c41c7bb4 ] + +Need to enter safe mode before touching GC MMIO. + +Acked-by: Vitaly Prosyak +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +index 4ba8eb45ac174..0bcdcb2101577 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +@@ -4497,6 +4497,8 @@ static int gfx_v11_0_soft_reset(void *handle) + int r, i, j, k; + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + ++ gfx_v11_0_set_safe_mode(adev, 0); ++ + tmp = RREG32_SOC15(GC, 0, regCP_INT_CNTL); + tmp = REG_SET_FIELD(tmp, CP_INT_CNTL, CMP_BUSY_INT_ENABLE, 0); + tmp = REG_SET_FIELD(tmp, CP_INT_CNTL, CNTX_BUSY_INT_ENABLE, 0); +@@ -4504,8 +4506,6 @@ static int gfx_v11_0_soft_reset(void *handle) + tmp = REG_SET_FIELD(tmp, CP_INT_CNTL, GFX_IDLE_INT_ENABLE, 0); + WREG32_SOC15(GC, 0, regCP_INT_CNTL, tmp); + +- gfx_v11_0_set_safe_mode(adev, 0); +- + mutex_lock(&adev->srbm_mutex); + for (i = 0; i < adev->gfx.mec.num_mec; ++i) { + for (j = 0; j < adev->gfx.mec.num_queue_per_pipe; j++) { +-- +2.43.0 + diff --git a/queue-6.10/drm-amdgpu-gfx11-use-rlc-safe-mode-for-soft-recovery.patch b/queue-6.10/drm-amdgpu-gfx11-use-rlc-safe-mode-for-soft-recovery.patch new file mode 100644 index 00000000000..1a4d4135815 --- /dev/null +++ b/queue-6.10/drm-amdgpu-gfx11-use-rlc-safe-mode-for-soft-recovery.patch @@ -0,0 +1,35 @@ +From 06d094709cb66935ac8de8a0326a3f7913eb4679 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Jul 2024 18:20:23 -0400 +Subject: drm/amdgpu/gfx11: use rlc safe mode for soft recovery + +From: Alex Deucher + +[ Upstream commit 3f2d35c325534c1b7ac5072173f0dc7ca969dec2 ] + +Protect the MMIO access with safe mode. + +Acked-by: Vitaly Prosyak +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +index 0bcdcb2101577..6b5cd0dcd25f4 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +@@ -5792,7 +5792,9 @@ static void gfx_v11_0_ring_soft_recovery(struct amdgpu_ring *ring, + value = REG_SET_FIELD(value, SQ_CMD, MODE, 0x01); + value = REG_SET_FIELD(value, SQ_CMD, CHECK_VMID, 1); + value = REG_SET_FIELD(value, SQ_CMD, VM_ID, vmid); ++ amdgpu_gfx_rlc_enter_safe_mode(adev, 0); + WREG32_SOC15(GC, 0, regSQ_CMD, value); ++ amdgpu_gfx_rlc_exit_safe_mode(adev, 0); + } + + static void +-- +2.43.0 + diff --git a/queue-6.10/drm-amdgpu-gfx9-properly-handle-error-ints-on-all-pi.patch b/queue-6.10/drm-amdgpu-gfx9-properly-handle-error-ints-on-all-pi.patch new file mode 100644 index 00000000000..72097a0eb88 --- /dev/null +++ b/queue-6.10/drm-amdgpu-gfx9-properly-handle-error-ints-on-all-pi.patch @@ -0,0 +1,170 @@ +From 1b9adcb5f75046d24e96ecb4815fcead7e371fd6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ Upstream commit 48695573d2feaf42812c1ad54e01caff0d1c2d71 ] + +Need to handle the interrupt enables for all pipes. + +Acked-by: Christian König +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 44 +++++++++++++++++++++- + drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c | 50 +++++++++++++++++++++++-- + 2 files changed, 89 insertions(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +index 0594eab666a9b..b278453cad6d4 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +@@ -2477,7 +2477,7 @@ static void gfx_v9_0_enable_gui_idle_interrupt(struct amdgpu_device *adev, + tmp = REG_SET_FIELD(tmp, CP_INT_CNTL_RING0, CNTX_BUSY_INT_ENABLE, enable ? 1 : 0); + tmp = REG_SET_FIELD(tmp, CP_INT_CNTL_RING0, CNTX_EMPTY_INT_ENABLE, enable ? 1 : 0); + tmp = REG_SET_FIELD(tmp, CP_INT_CNTL_RING0, CMP_BUSY_INT_ENABLE, enable ? 1 : 0); +- if(adev->gfx.num_gfx_rings) ++ if (adev->gfx.num_gfx_rings) + tmp = REG_SET_FIELD(tmp, CP_INT_CNTL_RING0, GFX_IDLE_INT_ENABLE, enable ? 1 : 0); + + WREG32_SOC15(GC, 0, mmCP_INT_CNTL_RING0, tmp); +@@ -5772,17 +5772,59 @@ static void gfx_v9_0_set_compute_eop_interrupt_state(struct amdgpu_device *adev, + } + } + ++static u32 gfx_v9_0_get_cpc_int_cntl(struct amdgpu_device *adev, ++ int me, int pipe) ++{ ++ /* ++ * amdgpu controls only the first MEC. That's why this function only ++ * handles the setting of interrupts for this specific MEC. All other ++ * pipes' interrupts are set by amdkfd. ++ */ ++ if (me != 1) ++ return 0; ++ ++ switch (pipe) { ++ case 0: ++ return SOC15_REG_OFFSET(GC, 0, mmCP_ME1_PIPE0_INT_CNTL); ++ case 1: ++ return SOC15_REG_OFFSET(GC, 0, mmCP_ME1_PIPE1_INT_CNTL); ++ case 2: ++ return SOC15_REG_OFFSET(GC, 0, mmCP_ME1_PIPE2_INT_CNTL); ++ case 3: ++ return SOC15_REG_OFFSET(GC, 0, mmCP_ME1_PIPE3_INT_CNTL); ++ default: ++ return 0; ++ } ++} ++ + static int gfx_v9_0_set_priv_reg_fault_state(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + unsigned type, + enum amdgpu_interrupt_state state) + { ++ u32 cp_int_cntl_reg, cp_int_cntl; ++ int i, j; ++ + switch (state) { + case AMDGPU_IRQ_STATE_DISABLE: + case AMDGPU_IRQ_STATE_ENABLE: + WREG32_FIELD15(GC, 0, CP_INT_CNTL_RING0, + PRIV_REG_INT_ENABLE, + state == AMDGPU_IRQ_STATE_ENABLE ? 1 : 0); ++ for (i = 0; i < adev->gfx.mec.num_mec; i++) { ++ for (j = 0; j < adev->gfx.mec.num_pipe_per_mec; j++) { ++ /* MECs start at 1 */ ++ cp_int_cntl_reg = gfx_v9_0_get_cpc_int_cntl(adev, i + 1, j); ++ ++ if (cp_int_cntl_reg) { ++ cp_int_cntl = RREG32_SOC15_IP(GC, cp_int_cntl_reg); ++ cp_int_cntl = REG_SET_FIELD(cp_int_cntl, CP_ME1_PIPE0_INT_CNTL, ++ PRIV_REG_INT_ENABLE, ++ state == AMDGPU_IRQ_STATE_ENABLE ? 1 : 0); ++ WREG32_SOC15_IP(GC, cp_int_cntl_reg, cp_int_cntl); ++ } ++ } ++ } + break; + default: + break; +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c +index f5b9f443cfdd7..2564a003526ae 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c +@@ -2824,21 +2824,63 @@ static void gfx_v9_4_3_xcc_set_compute_eop_interrupt_state( + } + } + ++static u32 gfx_v9_4_3_get_cpc_int_cntl(struct amdgpu_device *adev, ++ int xcc_id, int me, int pipe) ++{ ++ /* ++ * amdgpu controls only the first MEC. That's why this function only ++ * handles the setting of interrupts for this specific MEC. All other ++ * pipes' interrupts are set by amdkfd. ++ */ ++ if (me != 1) ++ return 0; ++ ++ switch (pipe) { ++ case 0: ++ return SOC15_REG_OFFSET(GC, GET_INST(GC, xcc_id), regCP_ME1_PIPE0_INT_CNTL); ++ case 1: ++ return SOC15_REG_OFFSET(GC, GET_INST(GC, xcc_id), regCP_ME1_PIPE1_INT_CNTL); ++ case 2: ++ return SOC15_REG_OFFSET(GC, GET_INST(GC, xcc_id), regCP_ME1_PIPE2_INT_CNTL); ++ case 3: ++ return SOC15_REG_OFFSET(GC, GET_INST(GC, xcc_id), regCP_ME1_PIPE3_INT_CNTL); ++ default: ++ return 0; ++ } ++} ++ + static int gfx_v9_4_3_set_priv_reg_fault_state(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + unsigned type, + enum amdgpu_interrupt_state state) + { +- int i, num_xcc; ++ u32 mec_int_cntl_reg, mec_int_cntl; ++ int i, j, k, num_xcc; + + num_xcc = NUM_XCC(adev->gfx.xcc_mask); + switch (state) { + case AMDGPU_IRQ_STATE_DISABLE: + case AMDGPU_IRQ_STATE_ENABLE: +- for (i = 0; i < num_xcc; i++) ++ for (i = 0; i < num_xcc; i++) { + WREG32_FIELD15_PREREG(GC, GET_INST(GC, i), CP_INT_CNTL_RING0, +- PRIV_REG_INT_ENABLE, +- state == AMDGPU_IRQ_STATE_ENABLE ? 1 : 0); ++ PRIV_REG_INT_ENABLE, ++ state == AMDGPU_IRQ_STATE_ENABLE ? 1 : 0); ++ for (j = 0; j < adev->gfx.mec.num_mec; j++) { ++ for (k = 0; k < adev->gfx.mec.num_pipe_per_mec; k++) { ++ /* MECs start at 1 */ ++ mec_int_cntl_reg = gfx_v9_4_3_get_cpc_int_cntl(adev, i, j + 1, k); ++ ++ if (mec_int_cntl_reg) { ++ mec_int_cntl = RREG32_XCC(mec_int_cntl_reg, i); ++ mec_int_cntl = REG_SET_FIELD(mec_int_cntl, CP_ME1_PIPE0_INT_CNTL, ++ PRIV_REG_INT_ENABLE, ++ state == AMDGPU_IRQ_STATE_ENABLE ? ++ 1 : 0); ++ WREG32_XCC(mec_int_cntl_reg, mec_int_cntl, i); ++ } ++ } ++ } ++ } + break; + default: + break; +-- +2.43.0 + diff --git a/queue-6.10/drm-amdgpu-gfx9-use-rlc-safe-mode-for-soft-recovery.patch b/queue-6.10/drm-amdgpu-gfx9-use-rlc-safe-mode-for-soft-recovery.patch new file mode 100644 index 00000000000..681d5525afc --- /dev/null +++ b/queue-6.10/drm-amdgpu-gfx9-use-rlc-safe-mode-for-soft-recovery.patch @@ -0,0 +1,35 @@ +From 3716fb348cb9d34ac5f1b89456fa9d236a417a5d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Jul 2024 18:20:57 -0400 +Subject: drm/amdgpu/gfx9: use rlc safe mode for soft recovery + +From: Alex Deucher + +[ Upstream commit 3ec2ad7c34c412bd9264cd1ff235d0812be90e82 ] + +Protect the MMIO access with safe mode. + +Acked-by: Vitaly Prosyak +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +index b278453cad6d4..d8d3d2c93d8ee 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +@@ -5701,7 +5701,9 @@ static void gfx_v9_0_ring_soft_recovery(struct amdgpu_ring *ring, unsigned vmid) + value = REG_SET_FIELD(value, SQ_CMD, MODE, 0x01); + value = REG_SET_FIELD(value, SQ_CMD, CHECK_VMID, 1); + value = REG_SET_FIELD(value, SQ_CMD, VM_ID, vmid); ++ amdgpu_gfx_rlc_enter_safe_mode(adev, 0); + WREG32_SOC15(GC, 0, mmSQ_CMD, value); ++ amdgpu_gfx_rlc_exit_safe_mode(adev, 0); + } + + static void gfx_v9_0_set_gfx_eop_interrupt_state(struct amdgpu_device *adev, +-- +2.43.0 + diff --git a/queue-6.10/drm-amdkfd-amdkfd_free_gtt_mem-clear-the-correct-poi.patch b/queue-6.10/drm-amdkfd-amdkfd_free_gtt_mem-clear-the-correct-poi.patch new file mode 100644 index 00000000000..14dde348f77 --- /dev/null +++ b/queue-6.10/drm-amdkfd-amdkfd_free_gtt_mem-clear-the-correct-poi.patch @@ -0,0 +1,165 @@ +From 05572408f8d9c5e60c1df8fb8cf409c825533f62 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 14 Jul 2024 11:11:05 -0400 +Subject: drm/amdkfd: amdkfd_free_gtt_mem clear the correct pointer +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Philip Yang + +[ Upstream commit c86ad39140bbcb9dc75a10046c2221f657e8083b ] + +Pass pointer reference to amdgpu_bo_unref to clear the correct pointer, +otherwise amdgpu_bo_unref clear the local variable, the original pointer +not set to NULL, this could cause use-after-free bug. + +Signed-off-by: Philip Yang +Reviewed-by: Felix Kuehling +Acked-by: Christian König +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 14 +++++++------- + drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h | 2 +- + drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 2 +- + drivers/gpu/drm/amd/amdkfd/kfd_device.c | 4 ++-- + .../gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 2 +- + drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c | 2 +- + drivers/gpu/drm/amd/amdkfd/kfd_process.c | 2 +- + .../gpu/drm/amd/amdkfd/kfd_process_queue_manager.c | 4 ++-- + 8 files changed, 16 insertions(+), 16 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +index e3738d4172458..26ecca3e8e900 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +@@ -360,15 +360,15 @@ int amdgpu_amdkfd_alloc_gtt_mem(struct amdgpu_device *adev, size_t size, + return r; + } + +-void amdgpu_amdkfd_free_gtt_mem(struct amdgpu_device *adev, void *mem_obj) ++void amdgpu_amdkfd_free_gtt_mem(struct amdgpu_device *adev, void **mem_obj) + { +- struct amdgpu_bo *bo = (struct amdgpu_bo *) mem_obj; ++ struct amdgpu_bo **bo = (struct amdgpu_bo **) mem_obj; + +- amdgpu_bo_reserve(bo, true); +- amdgpu_bo_kunmap(bo); +- amdgpu_bo_unpin(bo); +- amdgpu_bo_unreserve(bo); +- amdgpu_bo_unref(&(bo)); ++ amdgpu_bo_reserve(*bo, true); ++ amdgpu_bo_kunmap(*bo); ++ amdgpu_bo_unpin(*bo); ++ amdgpu_bo_unreserve(*bo); ++ amdgpu_bo_unref(bo); + } + + int amdgpu_amdkfd_alloc_gws(struct amdgpu_device *adev, size_t size, +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +index 1de021ebdd467..ee16d8a9ba559 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +@@ -233,7 +233,7 @@ int amdgpu_amdkfd_bo_validate_and_fence(struct amdgpu_bo *bo, + int amdgpu_amdkfd_alloc_gtt_mem(struct amdgpu_device *adev, size_t size, + void **mem_obj, uint64_t *gpu_addr, + void **cpu_ptr, bool mqd_gfx9); +-void amdgpu_amdkfd_free_gtt_mem(struct amdgpu_device *adev, void *mem_obj); ++void amdgpu_amdkfd_free_gtt_mem(struct amdgpu_device *adev, void **mem_obj); + int amdgpu_amdkfd_alloc_gws(struct amdgpu_device *adev, size_t size, + void **mem_obj); + void amdgpu_amdkfd_free_gws(struct amdgpu_device *adev, void *mem_obj); +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +index fdf171ad4a3c6..4f260adce8c46 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +@@ -423,7 +423,7 @@ static int kfd_ioctl_create_queue(struct file *filep, struct kfd_process *p, + + err_create_queue: + if (wptr_bo) +- amdgpu_amdkfd_free_gtt_mem(dev->adev, wptr_bo); ++ amdgpu_amdkfd_free_gtt_mem(dev->adev, (void **)&wptr_bo); + err_wptr_map_gart: + err_bind_process: + err_pdd: +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c +index afc57df421cd9..3343079f28c90 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c +@@ -863,7 +863,7 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd, + kfd_doorbell_error: + kfd_gtt_sa_fini(kfd); + kfd_gtt_sa_init_error: +- amdgpu_amdkfd_free_gtt_mem(kfd->adev, kfd->gtt_mem); ++ amdgpu_amdkfd_free_gtt_mem(kfd->adev, &kfd->gtt_mem); + alloc_gtt_mem_failure: + dev_err(kfd_device, + "device %x:%x NOT added due to errors\n", +@@ -881,7 +881,7 @@ void kgd2kfd_device_exit(struct kfd_dev *kfd) + kfd_doorbell_fini(kfd); + ida_destroy(&kfd->doorbell_ida); + kfd_gtt_sa_fini(kfd); +- amdgpu_amdkfd_free_gtt_mem(kfd->adev, kfd->gtt_mem); ++ amdgpu_amdkfd_free_gtt_mem(kfd->adev, &kfd->gtt_mem); + } + + kfree(kfd); +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +index c08b6ee252898..dbef9eac2694f 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +@@ -2633,7 +2633,7 @@ static void deallocate_hiq_sdma_mqd(struct kfd_node *dev, + { + WARN(!mqd, "No hiq sdma mqd trunk to free"); + +- amdgpu_amdkfd_free_gtt_mem(dev->adev, mqd->gtt_mem); ++ amdgpu_amdkfd_free_gtt_mem(dev->adev, &mqd->gtt_mem); + } + + void device_queue_manager_uninit(struct device_queue_manager *dqm) +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c +index 8746a61a852dc..d501fd2222dc3 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c +@@ -223,7 +223,7 @@ void kfd_free_mqd_cp(struct mqd_manager *mm, void *mqd, + struct kfd_mem_obj *mqd_mem_obj) + { + if (mqd_mem_obj->gtt_mem) { +- amdgpu_amdkfd_free_gtt_mem(mm->dev->adev, mqd_mem_obj->gtt_mem); ++ amdgpu_amdkfd_free_gtt_mem(mm->dev->adev, &mqd_mem_obj->gtt_mem); + kfree(mqd_mem_obj); + } else { + kfd_gtt_sa_free(mm->dev, mqd_mem_obj); +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c +index 451bb058cc620..66150ea8e64d8 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c +@@ -1048,7 +1048,7 @@ static void kfd_process_destroy_pdds(struct kfd_process *p) + + if (pdd->dev->kfd->shared_resources.enable_mes) + amdgpu_amdkfd_free_gtt_mem(pdd->dev->adev, +- pdd->proc_ctx_bo); ++ &pdd->proc_ctx_bo); + /* + * before destroying pdd, make sure to report availability + * for auto suspend +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +index a5bdc3258ae54..c97b4fc44859d 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +@@ -201,9 +201,9 @@ static void pqm_clean_queue_resource(struct process_queue_manager *pqm, + } + + if (dev->kfd->shared_resources.enable_mes) { +- amdgpu_amdkfd_free_gtt_mem(dev->adev, pqn->q->gang_ctx_bo); ++ amdgpu_amdkfd_free_gtt_mem(dev->adev, &pqn->q->gang_ctx_bo); + if (pqn->q->wptr_bo) +- amdgpu_amdkfd_free_gtt_mem(dev->adev, pqn->q->wptr_bo); ++ amdgpu_amdkfd_free_gtt_mem(dev->adev, (void **)&pqn->q->wptr_bo); + } + } + +-- +2.43.0 + diff --git a/queue-6.10/drm-amdkfd-check-int-source-id-for-utcl2-poison-even.patch b/queue-6.10/drm-amdkfd-check-int-source-id-for-utcl2-poison-even.patch new file mode 100644 index 00000000000..8185010198e --- /dev/null +++ b/queue-6.10/drm-amdkfd-check-int-source-id-for-utcl2-poison-even.patch @@ -0,0 +1,76 @@ +From 67598afe98001e0008aefbc9727d2926b33a7209 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Aug 2024 13:56:32 +0800 +Subject: drm/amdkfd: Check int source id for utcl2 poison event + +From: Hawking Zhang + +[ 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 +Reviewed-by: Tao Zhou +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../gpu/drm/amd/amdkfd/kfd_int_process_v9.c | 18 +----------------- + drivers/gpu/drm/amd/amdkfd/soc15_int.h | 1 + + 2 files changed, 2 insertions(+), 17 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c +index 78dde62fb04ad..c282f5253c445 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c +@@ -414,25 +414,9 @@ static void event_interrupt_wq_v9(struct kfd_node *dev, + client_id == SOC15_IH_CLIENTID_UTCL2) { + struct kfd_vm_fault_info info = {0}; + uint16_t ring_id = SOC15_RING_ID_FROM_IH_ENTRY(ih_ring_entry); +- uint32_t node_id = SOC15_NODEID_FROM_IH_ENTRY(ih_ring_entry); +- uint32_t vmid_type = SOC15_VMID_TYPE_FROM_IH_ENTRY(ih_ring_entry); +- int hub_inst = 0; + struct kfd_hsa_memory_exception_data exception_data; + +- /* gfxhub */ +- if (!vmid_type && dev->adev->gfx.funcs->ih_node_to_logical_xcc) { +- hub_inst = dev->adev->gfx.funcs->ih_node_to_logical_xcc(dev->adev, +- node_id); +- if (hub_inst < 0) +- hub_inst = 0; +- } +- +- /* mmhub */ +- if (vmid_type && client_id == SOC15_IH_CLIENTID_VMC) +- hub_inst = node_id / 4; +- +- if (amdgpu_amdkfd_ras_query_utcl2_poison_status(dev->adev, +- hub_inst, vmid_type)) { ++ if (source_id == SOC15_INTSRC_VMC_UTCL2_POISON) { + event_interrupt_poison_consumption_v9(dev, pasid, client_id); + return; + } +diff --git a/drivers/gpu/drm/amd/amdkfd/soc15_int.h b/drivers/gpu/drm/amd/amdkfd/soc15_int.h +index 10138676f27fd..e5c0205f26181 100644 +--- a/drivers/gpu/drm/amd/amdkfd/soc15_int.h ++++ b/drivers/gpu/drm/amd/amdkfd/soc15_int.h +@@ -29,6 +29,7 @@ + #define SOC15_INTSRC_CP_BAD_OPCODE 183 + #define SOC15_INTSRC_SQ_INTERRUPT_MSG 239 + #define SOC15_INTSRC_VMC_FAULT 0 ++#define SOC15_INTSRC_VMC_UTCL2_POISON 1 + #define SOC15_INTSRC_SDMA_TRAP 224 + #define SOC15_INTSRC_SDMA_ECC 220 + #define SOC21_INTSRC_SDMA_TRAP 49 +-- +2.43.0 + diff --git a/queue-6.10/drm-amdkfd-fix-resource-leak-in-criu-restore-queue.patch b/queue-6.10/drm-amdkfd-fix-resource-leak-in-criu-restore-queue.patch new file mode 100644 index 00000000000..4488d04a81a --- /dev/null +++ b/queue-6.10/drm-amdkfd-fix-resource-leak-in-criu-restore-queue.patch @@ -0,0 +1,35 @@ +From 416b2b78a2d2b5ec7daf9c298860cdfd931a5145 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Sep 2024 11:29:55 +0800 +Subject: drm/amdkfd: Fix resource leak in criu restore queue + +From: Jesse Zhang + +[ Upstream commit aa47fe8d3595365a935921a90d00bc33ee374728 ] + +To avoid memory leaks, release q_extra_data when exiting the restore queue. +v2: Correct the proto (Alex) + +Signed-off-by: Jesse Zhang +Reviewed-by: Tim Huang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +index c97b4fc44859d..db2b71f7226f4 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +@@ -984,6 +984,7 @@ int kfd_criu_restore_queue(struct kfd_process *p, + pr_debug("Queue id %d was restored successfully\n", queue_id); + + kfree(q_data); ++ kfree(q_extra_data); + + return ret; + } +-- +2.43.0 + diff --git a/queue-6.10/drm-msm-adreno-assign-msm_gpu-pdev-earlier-to-avoid-.patch b/queue-6.10/drm-msm-adreno-assign-msm_gpu-pdev-earlier-to-avoid-.patch new file mode 100644 index 00000000000..055f1453b75 --- /dev/null +++ b/queue-6.10/drm-msm-adreno-assign-msm_gpu-pdev-earlier-to-avoid-.patch @@ -0,0 +1,61 @@ +From dbfe4ad3ff1f05785d9f5662d3dc94c6ae7d14fc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Jul 2024 13:15:40 +0200 +Subject: drm/msm/adreno: Assign msm_gpu->pdev earlier to avoid nullptrs + +From: Konrad Dybcio + +[ Upstream commit 16007768551d5bfe53426645401435ca8d2ef54f ] + +There are some cases, such as the one uncovered by Commit 46d4efcccc68 +("drm/msm/a6xx: Avoid a nullptr dereference when speedbin setting fails") +where + +msm_gpu_cleanup() : platform_set_drvdata(gpu->pdev, NULL); + +is called on gpu->pdev == NULL, as the GPU device has not been fully +initialized yet. + +Turns out that there's more than just the aforementioned path that +causes this to happen (e.g. the case when there's speedbin data in the +catalog, but opp-supported-hw is missing in DT). + +Assigning msm_gpu->pdev earlier seems like the least painful solution +to this, therefore do so. + +Signed-off-by: Konrad Dybcio +Patchwork: https://patchwork.freedesktop.org/patch/602742/ +Signed-off-by: Rob Clark +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/adreno/adreno_gpu.c | 1 + + drivers/gpu/drm/msm/msm_gpu.c | 1 - + 2 files changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c +index d5d9361e11aa5..8e8f55225e1ea 100644 +--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c ++++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c +@@ -1079,6 +1079,7 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, + adreno_gpu->chip_id = config->chip_id; + + gpu->allow_relocs = config->info->family < ADRENO_6XX_GEN1; ++ gpu->pdev = pdev; + + /* Only handle the core clock when GMU is not in use (or is absent). */ + if (adreno_has_gmu_wrapper(adreno_gpu) || +diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c +index cd185b9636d26..56b6de049bd7b 100644 +--- a/drivers/gpu/drm/msm/msm_gpu.c ++++ b/drivers/gpu/drm/msm/msm_gpu.c +@@ -929,7 +929,6 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, + if (IS_ERR(gpu->gpu_cx)) + gpu->gpu_cx = NULL; + +- gpu->pdev = pdev; + platform_set_drvdata(pdev, &gpu->adreno_smmu); + + msm_devfreq_init(gpu); +-- +2.43.0 + diff --git a/queue-6.10/drm-printer-allow-null-data-in-devcoredump-printer.patch b/queue-6.10/drm-printer-allow-null-data-in-devcoredump-printer.patch new file mode 100644 index 00000000000..c9ae3efc8ba --- /dev/null +++ b/queue-6.10/drm-printer-allow-null-data-in-devcoredump-printer.patch @@ -0,0 +1,144 @@ +From 168e280227eb6a7ce3b4c50d2b0efc343091f448 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 1 Aug 2024 08:41:17 -0700 +Subject: drm/printer: Allow NULL data in devcoredump printer + +From: Matthew Brost + +[ Upstream commit 53369581dc0c68a5700ed51e1660f44c4b2bb524 ] + +We want to determine the size of the devcoredump before writing it out. +To that end, we will run the devcoredump printer with NULL data to get +the size, alloc data based on the generated offset, then run the +devcorecump again with a valid data pointer to print. This necessitates +not writing data to the data pointer on the initial pass, when it is +NULL. + +v5: + - Better commit message (Jonathan) + - Add kerenl doc with examples (Jani) + +Cc: Maarten Lankhorst +Acked-by: Maarten Lankhorst +Signed-off-by: Matthew Brost +Reviewed-by: Jonathan Cavitt +Link: https://patchwork.freedesktop.org/patch/msgid/20240801154118.2547543-3-matthew.brost@intel.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/drm_print.c | 13 +++++---- + include/drm/drm_print.h | 54 ++++++++++++++++++++++++++++++++++++- + 2 files changed, 61 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/drm_print.c b/drivers/gpu/drm/drm_print.c +index cf2efb44722c9..1d122d4de70ec 100644 +--- a/drivers/gpu/drm/drm_print.c ++++ b/drivers/gpu/drm/drm_print.c +@@ -100,8 +100,9 @@ void __drm_puts_coredump(struct drm_printer *p, const char *str) + copy = iterator->remain; + + /* Copy out the bit of the string that we need */ +- memcpy(iterator->data, +- str + (iterator->start - iterator->offset), copy); ++ if (iterator->data) ++ memcpy(iterator->data, ++ str + (iterator->start - iterator->offset), copy); + + iterator->offset = iterator->start + copy; + iterator->remain -= copy; +@@ -110,7 +111,8 @@ void __drm_puts_coredump(struct drm_printer *p, const char *str) + + len = min_t(ssize_t, strlen(str), iterator->remain); + +- memcpy(iterator->data + pos, str, len); ++ if (iterator->data) ++ memcpy(iterator->data + pos, str, len); + + iterator->offset += len; + iterator->remain -= len; +@@ -140,8 +142,9 @@ void __drm_printfn_coredump(struct drm_printer *p, struct va_format *vaf) + if ((iterator->offset >= iterator->start) && (len < iterator->remain)) { + ssize_t pos = iterator->offset - iterator->start; + +- snprintf(((char *) iterator->data) + pos, +- iterator->remain, "%pV", vaf); ++ if (iterator->data) ++ snprintf(((char *) iterator->data) + pos, ++ iterator->remain, "%pV", vaf); + + iterator->offset += len; + iterator->remain -= len; +diff --git a/include/drm/drm_print.h b/include/drm/drm_print.h +index 089950ad8681a..8fad7d09bedae 100644 +--- a/include/drm/drm_print.h ++++ b/include/drm/drm_print.h +@@ -220,7 +220,8 @@ drm_vprintf(struct drm_printer *p, const char *fmt, va_list *va) + + /** + * struct drm_print_iterator - local struct used with drm_printer_coredump +- * @data: Pointer to the devcoredump output buffer ++ * @data: Pointer to the devcoredump output buffer, can be NULL if using ++ * drm_printer_coredump to determine size of devcoredump + * @start: The offset within the buffer to start writing + * @remain: The number of bytes to write for this iteration + */ +@@ -265,6 +266,57 @@ struct drm_print_iterator { + * coredump_read, ...) + * } + * ++ * The above example has a time complexity of O(N^2), where N is the size of the ++ * devcoredump. This is acceptable for small devcoredumps but scales poorly for ++ * larger ones. ++ * ++ * Another use case for drm_coredump_printer is to capture the devcoredump into ++ * a saved buffer before the dev_coredump() callback. This involves two passes: ++ * one to determine the size of the devcoredump and another to print it to a ++ * buffer. Then, in dev_coredump(), copy from the saved buffer into the ++ * devcoredump read buffer. ++ * ++ * For example:: ++ * ++ * char *devcoredump_saved_buffer; ++ * ++ * ssize_t __coredump_print(char *buffer, ssize_t count, ...) ++ * { ++ * struct drm_print_iterator iter; ++ * struct drm_printer p; ++ * ++ * iter.data = buffer; ++ * iter.start = 0; ++ * iter.remain = count; ++ * ++ * p = drm_coredump_printer(&iter); ++ * ++ * drm_printf(p, "foo=%d\n", foo); ++ * ... ++ * return count - iter.remain; ++ * } ++ * ++ * void coredump_print(...) ++ * { ++ * ssize_t count; ++ * ++ * count = __coredump_print(NULL, INT_MAX, ...); ++ * devcoredump_saved_buffer = kvmalloc(count, GFP_KERNEL); ++ * __coredump_print(devcoredump_saved_buffer, count, ...); ++ * } ++ * ++ * void coredump_read(char *buffer, loff_t offset, size_t count, ++ * void *data, size_t datalen) ++ * { ++ * ... ++ * memcpy(buffer, devcoredump_saved_buffer + offset, count); ++ * ... ++ * } ++ * ++ * The above example has a time complexity of O(N*2), where N is the size of the ++ * devcoredump. This scales better than the previous example for larger ++ * devcoredumps. ++ * + * RETURNS: + * The &drm_printer object + */ +-- +2.43.0 + diff --git a/queue-6.10/drm-radeon-r100-handle-unknown-family-in-r100_cp_ini.patch b/queue-6.10/drm-radeon-r100-handle-unknown-family-in-r100_cp_ini.patch new file mode 100644 index 00000000000..8f7b95039d6 --- /dev/null +++ b/queue-6.10/drm-radeon-r100-handle-unknown-family-in-r100_cp_ini.patch @@ -0,0 +1,140 @@ +From 638094311e34f49390d48489255ba890335e4fad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Jul 2024 17:58:12 +0200 +Subject: drm/radeon/r100: Handle unknown family in r100_cp_init_microcode() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Geert Uytterhoeven + +[ Upstream commit c6dbab46324b1742b50dc2fb5c1fee2c28129439 ] + +With -Werror: + + In function ‘r100_cp_init_microcode’, + inlined from ‘r100_cp_init’ at drivers/gpu/drm/radeon/r100.c:1136:7: + include/linux/printk.h:465:44: error: ‘%s’ directive argument is null [-Werror=format-overflow=] + 465 | #define printk(fmt, ...) printk_index_wrap(_printk, fmt, ##__VA_ARGS__) + | ^ + include/linux/printk.h:437:17: note: in definition of macro ‘printk_index_wrap’ + 437 | _p_func(_fmt, ##__VA_ARGS__); \ + | ^~~~~~~ + include/linux/printk.h:508:9: note: in expansion of macro ‘printk’ + 508 | printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__) + | ^~~~~~ + drivers/gpu/drm/radeon/r100.c:1062:17: note: in expansion of macro ‘pr_err’ + 1062 | pr_err("radeon_cp: Failed to load firmware \"%s\"\n", fw_name); + | ^~~~~~ + +Fix this by converting the if/else if/... construct into a proper +switch() statement with a default to handle the error case. + +As a bonus, the generated code is ca. 100 bytes smaller (with gcc 11.4.0 +targeting arm32). + +Signed-off-by: Geert Uytterhoeven +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/radeon/r100.c | 70 ++++++++++++++++++++++------------- + 1 file changed, 45 insertions(+), 25 deletions(-) + +diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c +index 0b1e19345f43a..bfd42e3e161e9 100644 +--- a/drivers/gpu/drm/radeon/r100.c ++++ b/drivers/gpu/drm/radeon/r100.c +@@ -1016,45 +1016,65 @@ static int r100_cp_init_microcode(struct radeon_device *rdev) + + DRM_DEBUG_KMS("\n"); + +- if ((rdev->family == CHIP_R100) || (rdev->family == CHIP_RV100) || +- (rdev->family == CHIP_RV200) || (rdev->family == CHIP_RS100) || +- (rdev->family == CHIP_RS200)) { ++ switch (rdev->family) { ++ case CHIP_R100: ++ case CHIP_RV100: ++ case CHIP_RV200: ++ case CHIP_RS100: ++ case CHIP_RS200: + DRM_INFO("Loading R100 Microcode\n"); + fw_name = FIRMWARE_R100; +- } else if ((rdev->family == CHIP_R200) || +- (rdev->family == CHIP_RV250) || +- (rdev->family == CHIP_RV280) || +- (rdev->family == CHIP_RS300)) { ++ break; ++ ++ case CHIP_R200: ++ case CHIP_RV250: ++ case CHIP_RV280: ++ case CHIP_RS300: + DRM_INFO("Loading R200 Microcode\n"); + fw_name = FIRMWARE_R200; +- } else if ((rdev->family == CHIP_R300) || +- (rdev->family == CHIP_R350) || +- (rdev->family == CHIP_RV350) || +- (rdev->family == CHIP_RV380) || +- (rdev->family == CHIP_RS400) || +- (rdev->family == CHIP_RS480)) { ++ break; ++ ++ case CHIP_R300: ++ case CHIP_R350: ++ case CHIP_RV350: ++ case CHIP_RV380: ++ case CHIP_RS400: ++ case CHIP_RS480: + DRM_INFO("Loading R300 Microcode\n"); + fw_name = FIRMWARE_R300; +- } else if ((rdev->family == CHIP_R420) || +- (rdev->family == CHIP_R423) || +- (rdev->family == CHIP_RV410)) { ++ break; ++ ++ case CHIP_R420: ++ case CHIP_R423: ++ case CHIP_RV410: + DRM_INFO("Loading R400 Microcode\n"); + fw_name = FIRMWARE_R420; +- } else if ((rdev->family == CHIP_RS690) || +- (rdev->family == CHIP_RS740)) { ++ break; ++ ++ case CHIP_RS690: ++ case CHIP_RS740: + DRM_INFO("Loading RS690/RS740 Microcode\n"); + fw_name = FIRMWARE_RS690; +- } else if (rdev->family == CHIP_RS600) { ++ break; ++ ++ case CHIP_RS600: + DRM_INFO("Loading RS600 Microcode\n"); + fw_name = FIRMWARE_RS600; +- } else if ((rdev->family == CHIP_RV515) || +- (rdev->family == CHIP_R520) || +- (rdev->family == CHIP_RV530) || +- (rdev->family == CHIP_R580) || +- (rdev->family == CHIP_RV560) || +- (rdev->family == CHIP_RV570)) { ++ break; ++ ++ case CHIP_RV515: ++ case CHIP_R520: ++ case CHIP_RV530: ++ case CHIP_R580: ++ case CHIP_RV560: ++ case CHIP_RV570: + DRM_INFO("Loading R500 Microcode\n"); + fw_name = FIRMWARE_R520; ++ break; ++ ++ default: ++ DRM_ERROR("Unsupported Radeon family %u\n", rdev->family); ++ return -EINVAL; + } + + err = request_firmware(&rdev->me_fw, fw_name, rdev->dev); +-- +2.43.0 + diff --git a/queue-6.10/drm-stm-avoid-use-after-free-issues-with-crtc-and-pl.patch b/queue-6.10/drm-stm-avoid-use-after-free-issues-with-crtc-and-pl.patch new file mode 100644 index 00000000000..f5d2a0e0b32 --- /dev/null +++ b/queue-6.10/drm-stm-avoid-use-after-free-issues-with-crtc-and-pl.patch @@ -0,0 +1,254 @@ +From 42aa6221cd6f0d02ca188473a9238d6854f5b0d7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Feb 2024 15:50:40 +0300 +Subject: drm/stm: Avoid use-after-free issues with crtc and plane +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Katya Orlova + +[ Upstream commit 19dd9780b7ac673be95bf6fd6892a184c9db611f ] + +ltdc_load() calls functions drm_crtc_init_with_planes(), +drm_universal_plane_init() and drm_encoder_init(). These functions +should not be called with parameters allocated with devm_kzalloc() +to avoid use-after-free issues [1]. + +Use allocations managed by the DRM framework. + +Found by Linux Verification Center (linuxtesting.org). + +[1] +https://lore.kernel.org/lkml/u366i76e3qhh3ra5oxrtngjtm2u5lterkekcz6y2jkndhuxzli@diujon4h7qwb/ + +Signed-off-by: Katya Orlova +Acked-by: Raphaël Gallais-Pou +Link: https://patchwork.freedesktop.org/patch/msgid/20240216125040.8968-1-e.orlova@ispras.ru +Signed-off-by: Raphael Gallais-Pou +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/stm/drv.c | 3 +- + drivers/gpu/drm/stm/ltdc.c | 73 ++++++++++---------------------------- + 2 files changed, 20 insertions(+), 56 deletions(-) + +diff --git a/drivers/gpu/drm/stm/drv.c b/drivers/gpu/drm/stm/drv.c +index 4d2db079ad4ff..e1232f74dfa53 100644 +--- a/drivers/gpu/drm/stm/drv.c ++++ b/drivers/gpu/drm/stm/drv.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + + #include "ltdc.h" + +@@ -75,7 +76,7 @@ static int drv_load(struct drm_device *ddev) + + DRM_DEBUG("%s\n", __func__); + +- ldev = devm_kzalloc(ddev->dev, sizeof(*ldev), GFP_KERNEL); ++ ldev = drmm_kzalloc(ddev, sizeof(*ldev), GFP_KERNEL); + if (!ldev) + return -ENOMEM; + +diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c +index 5aec1e58c968c..056642d12265c 100644 +--- a/drivers/gpu/drm/stm/ltdc.c ++++ b/drivers/gpu/drm/stm/ltdc.c +@@ -36,6 +36,7 @@ + #include + #include + #include ++#include + + #include