From: Greg Kroah-Hartman Date: Thu, 12 Dec 2024 12:23:34 +0000 (+0100) Subject: 5.15-stable patches X-Git-Tag: v5.4.287~23 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=60c6a05033c80414d15832220de8f262c63b2b62;p=thirdparty%2Fkernel%2Fstable-queue.git 5.15-stable patches added patches: arm64-smccc-remove-broken-support-for-smcccv1.3-sve-discard-hint.patch arm64-sve-discard-stale-cpu-state-when-handling-sve-traps.patch bluetooth-l2cap-fix-uaf-in-l2cap_connect.patch crypto-hisilicon-qm-inject-error-before-stopping-queue.patch fou-remove-warn-in-gue_gro_receive-on-unsupported-protocol.patch gve-fixes-for-napi_poll-when-budget-is-0.patch ima-fix-use-after-free-on-a-dentry-s-dname.name.patch net-dsa-microchip-correct-ksz8795-static-mac-table-access.patch revert-drm-amdgpu-add-missing-size-check-in-amdgpu_debugfs_gprwave_read.patch scsi-core-fix-scsi_mode_select-buffer-length-handling.patch serial-sc16is7xx-change-efr-lock-to-operate-on-each-channels.patch serial-sc16is7xx-improve-regmap-debugfs-by-using-one-regmap-per-port.patch serial-sc16is7xx-remove-global-regmap-from-struct-sc16is7xx_port.patch serial-sc16is7xx-remove-unused-line-structure-member.patch serial-sc16is7xx-remove-wasteful-static-buffer-in-sc16is7xx_regmap_name.patch --- diff --git a/queue-5.15/arm64-smccc-remove-broken-support-for-smcccv1.3-sve-discard-hint.patch b/queue-5.15/arm64-smccc-remove-broken-support-for-smcccv1.3-sve-discard-hint.patch new file mode 100644 index 00000000000..25b68713523 --- /dev/null +++ b/queue-5.15/arm64-smccc-remove-broken-support-for-smcccv1.3-sve-discard-hint.patch @@ -0,0 +1,224 @@ +From 8c462d56487e3abdbf8a61cedfe7c795a54f4a78 Mon Sep 17 00:00:00 2001 +From: Mark Rutland +Date: Wed, 6 Nov 2024 16:04:48 +0000 +Subject: arm64: smccc: Remove broken support for SMCCCv1.3 SVE discard hint + +From: Mark Rutland + +commit 8c462d56487e3abdbf8a61cedfe7c795a54f4a78 upstream. + +SMCCCv1.3 added a hint bit which callers can set in an SMCCC function ID +(AKA "FID") to indicate that it is acceptable for the SMCCC +implementation to discard SVE and/or SME state over a specific SMCCC +call. The kernel support for using this hint is broken and SMCCC calls +may clobber the SVE and/or SME state of arbitrary tasks, though FPSIMD +state is unaffected. + +The kernel support is intended to use the hint when there is no SVE or +SME state to save, and to do this it checks whether TIF_FOREIGN_FPSTATE +is set or TIF_SVE is clear in assembly code: + +| ldr , [, #TSK_TI_FLAGS] +| tbnz , #TIF_FOREIGN_FPSTATE, 1f // Any live FP state? +| tbnz , #TIF_SVE, 2f // Does that state include SVE? +| +| 1: orr , , ARM_SMCCC_1_3_SVE_HINT +| 2: +| << SMCCC call using FID >> + +This is not safe as-is: + +(1) SMCCC calls can be made in a preemptible context and preemption can + result in TIF_FOREIGN_FPSTATE being set or cleared at arbitrary + points in time. Thus checking for TIF_FOREIGN_FPSTATE provides no + guarantee. + +(2) TIF_FOREIGN_FPSTATE only indicates that the live FP/SVE/SME state in + the CPU does not belong to the current task, and does not indicate + that clobbering this state is acceptable. + + When the live CPU state is clobbered it is necessary to update + fpsimd_last_state.st to ensure that a subsequent context switch will + reload FP/SVE/SME state from memory rather than consuming the + clobbered state. This and the SMCCC call itself must happen in a + critical section with preemption disabled to avoid races. + +(3) Live SVE/SME state can exist with TIF_SVE clear (e.g. with only + TIF_SME set), and checking TIF_SVE alone is insufficient. + +Remove the broken support for the SMCCCv1.3 SVE saving hint. This is +effectively a revert of commits: + +* cfa7ff959a78 ("arm64: smccc: Support SMCCC v1.3 SVE register saving hint") +* a7c3acca5380 ("arm64: smccc: Save lr before calling __arm_smccc_sve_check()") + +... leaving behind the ARM_SMCCC_VERSION_1_3 and ARM_SMCCC_1_3_SVE_HINT +definitions, since these are simply definitions from the SMCCC +specification, and the latter is used in KVM via ARM_SMCCC_CALL_HINTS. + +If we want to bring this back in future, we'll probably want to handle +this logic in C where we can use all the usual FPSIMD/SVE/SME helper +functions, and that'll likely require some rework of the SMCCC code +and/or its callers. + +Fixes: cfa7ff959a78 ("arm64: smccc: Support SMCCC v1.3 SVE register saving hint") +Signed-off-by: Mark Rutland +Cc: Ard Biesheuvel +Cc: Catalin Marinas +Cc: Marc Zyngier +Cc: Mark Brown +Cc: Will Deacon +Cc: stable@vger.kernel.org +Reviewed-by: Mark Brown +Link: https://lore.kernel.org/r/20241106160448.2712997-1-mark.rutland@arm.com +Signed-off-by: Will Deacon +[ Mark: fix conflicts in and drivers/firmware/smccc/smccc.c ] +Signed-off-by: Mark Rutland +Signed-off-by: Greg Kroah-Hartman +--- + arch/arm64/kernel/smccc-call.S | 35 +++-------------------------------- + drivers/firmware/smccc/smccc.c | 4 ---- + include/linux/arm-smccc.h | 30 ++---------------------------- + 3 files changed, 5 insertions(+), 64 deletions(-) + +--- a/arch/arm64/kernel/smccc-call.S ++++ b/arch/arm64/kernel/smccc-call.S +@@ -7,48 +7,19 @@ + + #include + #include +-#include +- +-/* +- * If we have SMCCC v1.3 and (as is likely) no SVE state in +- * the registers then set the SMCCC hint bit to say there's no +- * need to preserve it. Do this by directly adjusting the SMCCC +- * function value which is already stored in x0 ready to be called. +- */ +-SYM_FUNC_START(__arm_smccc_sve_check) +- +- ldr_l x16, smccc_has_sve_hint +- cbz x16, 2f +- +- get_current_task x16 +- ldr x16, [x16, #TSK_TI_FLAGS] +- tbnz x16, #TIF_FOREIGN_FPSTATE, 1f // Any live FP state? +- tbnz x16, #TIF_SVE, 2f // Does that state include SVE? +- +-1: orr x0, x0, ARM_SMCCC_1_3_SVE_HINT +- +-2: ret +-SYM_FUNC_END(__arm_smccc_sve_check) +-EXPORT_SYMBOL(__arm_smccc_sve_check) + + .macro SMCCC instr +- stp x29, x30, [sp, #-16]! +- mov x29, sp +-alternative_if ARM64_SVE +- bl __arm_smccc_sve_check +-alternative_else_nop_endif + \instr #0 +- ldr x4, [sp, #16] ++ ldr x4, [sp] + stp x0, x1, [x4, #ARM_SMCCC_RES_X0_OFFS] + stp x2, x3, [x4, #ARM_SMCCC_RES_X2_OFFS] +- ldr x4, [sp, #24] ++ ldr x4, [sp, #8] + cbz x4, 1f /* no quirk structure */ + ldr x9, [x4, #ARM_SMCCC_QUIRK_ID_OFFS] + cmp x9, #ARM_SMCCC_QUIRK_QCOM_A6 + b.ne 1f + str x6, [x4, ARM_SMCCC_QUIRK_STATE_OFFS] +-1: ldp x29, x30, [sp], #16 +- ret ++1: ret + .endm + + /* +--- a/drivers/firmware/smccc/smccc.c ++++ b/drivers/firmware/smccc/smccc.c +@@ -16,7 +16,6 @@ static u32 smccc_version = ARM_SMCCC_VER + static enum arm_smccc_conduit smccc_conduit = SMCCC_CONDUIT_NONE; + + bool __ro_after_init smccc_trng_available = false; +-u64 __ro_after_init smccc_has_sve_hint = false; + + void __init arm_smccc_version_init(u32 version, enum arm_smccc_conduit conduit) + { +@@ -24,9 +23,6 @@ void __init arm_smccc_version_init(u32 v + smccc_conduit = conduit; + + smccc_trng_available = smccc_probe_trng(); +- if (IS_ENABLED(CONFIG_ARM64_SVE) && +- smccc_version >= ARM_SMCCC_VERSION_1_3) +- smccc_has_sve_hint = true; + } + + enum arm_smccc_conduit arm_smccc_1_1_get_conduit(void) +--- a/include/linux/arm-smccc.h ++++ b/include/linux/arm-smccc.h +@@ -224,8 +224,6 @@ u32 arm_smccc_get_version(void); + + void __init arm_smccc_version_init(u32 version, enum arm_smccc_conduit conduit); + +-extern u64 smccc_has_sve_hint; +- + /** + * struct arm_smccc_res - Result from SMC/HVC call + * @a0-a3 result values from registers 0 to 3 +@@ -306,15 +304,6 @@ struct arm_smccc_quirk { + }; + + /** +- * __arm_smccc_sve_check() - Set the SVE hint bit when doing SMC calls +- * +- * Sets the SMCCC hint bit to indicate if there is live state in the SVE +- * registers, this modifies x0 in place and should never be called from C +- * code. +- */ +-asmlinkage unsigned long __arm_smccc_sve_check(unsigned long x0); +- +-/** + * __arm_smccc_smc() - make SMC calls + * @a0-a7: arguments passed in registers 0 to 7 + * @res: result values from registers 0 to 3 +@@ -381,20 +370,6 @@ asmlinkage void __arm_smccc_hvc(unsigned + + #endif + +-/* nVHE hypervisor doesn't have a current thread so needs separate checks */ +-#if defined(CONFIG_ARM64_SVE) && !defined(__KVM_NVHE_HYPERVISOR__) +- +-#define SMCCC_SVE_CHECK ALTERNATIVE("nop \n", "bl __arm_smccc_sve_check \n", \ +- ARM64_SVE) +-#define smccc_sve_clobbers "x16", "x30", "cc", +- +-#else +- +-#define SMCCC_SVE_CHECK +-#define smccc_sve_clobbers +- +-#endif +- + #define ___count_args(_0, _1, _2, _3, _4, _5, _6, _7, _8, x, ...) x + + #define __count_args(...) \ +@@ -462,7 +437,7 @@ asmlinkage void __arm_smccc_hvc(unsigned + + #define ___constraints(count) \ + : __constraint_read_ ## count \ +- : smccc_sve_clobbers "memory" ++ : "memory" + #define __constraints(count) ___constraints(count) + + /* +@@ -477,8 +452,7 @@ asmlinkage void __arm_smccc_hvc(unsigned + register unsigned long r2 asm("r2"); \ + register unsigned long r3 asm("r3"); \ + __declare_args(__count_args(__VA_ARGS__), __VA_ARGS__); \ +- asm volatile(SMCCC_SVE_CHECK \ +- inst "\n" : \ ++ asm volatile(inst "\n" : \ + "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3) \ + __constraints(__count_args(__VA_ARGS__))); \ + if (___res) \ diff --git a/queue-5.15/arm64-sve-discard-stale-cpu-state-when-handling-sve-traps.patch b/queue-5.15/arm64-sve-discard-stale-cpu-state-when-handling-sve-traps.patch new file mode 100644 index 00000000000..714fb15e7fc --- /dev/null +++ b/queue-5.15/arm64-sve-discard-stale-cpu-state-when-handling-sve-traps.patch @@ -0,0 +1,91 @@ +From 751ecf6afd6568adc98f2a6052315552c0483d18 Mon Sep 17 00:00:00 2001 +From: Mark Brown +Date: Wed, 30 Oct 2024 20:23:50 +0000 +Subject: arm64/sve: Discard stale CPU state when handling SVE traps + +From: Mark Brown + +commit 751ecf6afd6568adc98f2a6052315552c0483d18 upstream. + +The logic for handling SVE traps manipulates saved FPSIMD/SVE state +incorrectly, and a race with preemption can result in a task having +TIF_SVE set and TIF_FOREIGN_FPSTATE clear even though the live CPU state +is stale (e.g. with SVE traps enabled). This has been observed to result +in warnings from do_sve_acc() where SVE traps are not expected while +TIF_SVE is set: + +| if (test_and_set_thread_flag(TIF_SVE)) +| WARN_ON(1); /* SVE access shouldn't have trapped */ + +Warnings of this form have been reported intermittently, e.g. + + https://lore.kernel.org/linux-arm-kernel/CA+G9fYtEGe_DhY2Ms7+L7NKsLYUomGsgqpdBj+QwDLeSg=JhGg@mail.gmail.com/ + https://lore.kernel.org/linux-arm-kernel/000000000000511e9a060ce5a45c@google.com/ + +The race can occur when the SVE trap handler is preempted before and +after manipulating the saved FPSIMD/SVE state, starting and ending on +the same CPU, e.g. + +| void do_sve_acc(unsigned long esr, struct pt_regs *regs) +| { +| // Trap on CPU 0 with TIF_SVE clear, SVE traps enabled +| // task->fpsimd_cpu is 0. +| // per_cpu_ptr(&fpsimd_last_state, 0) is task. +| +| ... +| +| // Preempted; migrated from CPU 0 to CPU 1. +| // TIF_FOREIGN_FPSTATE is set. +| +| get_cpu_fpsimd_context(); +| +| if (test_and_set_thread_flag(TIF_SVE)) +| WARN_ON(1); /* SVE access shouldn't have trapped */ +| +| sve_init_regs() { +| if (!test_thread_flag(TIF_FOREIGN_FPSTATE)) { +| ... +| } else { +| fpsimd_to_sve(current); +| current->thread.fp_type = FP_STATE_SVE; +| } +| } +| +| put_cpu_fpsimd_context(); +| +| // Preempted; migrated from CPU 1 to CPU 0. +| // task->fpsimd_cpu is still 0 +| // If per_cpu_ptr(&fpsimd_last_state, 0) is still task then: +| // - Stale HW state is reused (with SVE traps enabled) +| // - TIF_FOREIGN_FPSTATE is cleared +| // - A return to userspace skips HW state restore +| } + +Fix the case where the state is not live and TIF_FOREIGN_FPSTATE is set +by calling fpsimd_flush_task_state() to detach from the saved CPU +state. This ensures that a subsequent context switch will not reuse the +stale CPU state, and will instead set TIF_FOREIGN_FPSTATE, forcing the +new state to be reloaded from memory prior to a return to userspace. + +Fixes: cccb78ce89c4 ("arm64/sve: Rework SVE access trap to convert state in registers") +Reported-by: Mark Rutland +Signed-off-by: Mark Brown +Cc: stable@vger.kernel.org +Reviewed-by: Mark Rutland +Link: https://lore.kernel.org/r/20241030-arm64-fpsimd-foreign-flush-v1-1-bd7bd66905a2@kernel.org +Signed-off-by: Will Deacon +Signed-off-by: Greg Kroah-Hartman +--- + arch/arm64/kernel/fpsimd.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/arm64/kernel/fpsimd.c ++++ b/arch/arm64/kernel/fpsimd.c +@@ -964,6 +964,7 @@ void do_sve_acc(unsigned long esr, struc + fpsimd_bind_task_to_cpu(); + } else { + fpsimd_to_sve(current); ++ fpsimd_flush_task_state(current); + } + + put_cpu_fpsimd_context(); diff --git a/queue-5.15/bluetooth-l2cap-fix-uaf-in-l2cap_connect.patch b/queue-5.15/bluetooth-l2cap-fix-uaf-in-l2cap_connect.patch new file mode 100644 index 00000000000..81f6f3041ea --- /dev/null +++ b/queue-5.15/bluetooth-l2cap-fix-uaf-in-l2cap_connect.patch @@ -0,0 +1,123 @@ +From 333b4fd11e89b29c84c269123f871883a30be586 Mon Sep 17 00:00:00 2001 +From: Luiz Augusto von Dentz +Date: Mon, 23 Sep 2024 12:47:39 -0400 +Subject: Bluetooth: L2CAP: Fix uaf in l2cap_connect + +From: Luiz Augusto von Dentz + +commit 333b4fd11e89b29c84c269123f871883a30be586 upstream. + +[Syzbot reported] +BUG: KASAN: slab-use-after-free in l2cap_connect.constprop.0+0x10d8/0x1270 net/bluetooth/l2cap_core.c:3949 +Read of size 8 at addr ffff8880241e9800 by task kworker/u9:0/54 + +CPU: 0 UID: 0 PID: 54 Comm: kworker/u9:0 Not tainted 6.11.0-rc6-syzkaller-00268-g788220eee30d #0 +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 08/06/2024 +Workqueue: hci2 hci_rx_work +Call Trace: + + __dump_stack lib/dump_stack.c:93 [inline] + dump_stack_lvl+0x116/0x1f0 lib/dump_stack.c:119 + print_address_description mm/kasan/report.c:377 [inline] + print_report+0xc3/0x620 mm/kasan/report.c:488 + kasan_report+0xd9/0x110 mm/kasan/report.c:601 + l2cap_connect.constprop.0+0x10d8/0x1270 net/bluetooth/l2cap_core.c:3949 + l2cap_connect_req net/bluetooth/l2cap_core.c:4080 [inline] + l2cap_bredr_sig_cmd net/bluetooth/l2cap_core.c:4772 [inline] + l2cap_sig_channel net/bluetooth/l2cap_core.c:5543 [inline] + l2cap_recv_frame+0xf0b/0x8eb0 net/bluetooth/l2cap_core.c:6825 + l2cap_recv_acldata+0x9b4/0xb70 net/bluetooth/l2cap_core.c:7514 + hci_acldata_packet net/bluetooth/hci_core.c:3791 [inline] + hci_rx_work+0xaab/0x1610 net/bluetooth/hci_core.c:4028 + process_one_work+0x9c5/0x1b40 kernel/workqueue.c:3231 + process_scheduled_works kernel/workqueue.c:3312 [inline] + worker_thread+0x6c8/0xed0 kernel/workqueue.c:3389 + kthread+0x2c1/0x3a0 kernel/kthread.c:389 + ret_from_fork+0x45/0x80 arch/x86/kernel/process.c:147 + ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:244 +... + +Freed by task 5245: + kasan_save_stack+0x33/0x60 mm/kasan/common.c:47 + kasan_save_track+0x14/0x30 mm/kasan/common.c:68 + kasan_save_free_info+0x3b/0x60 mm/kasan/generic.c:579 + poison_slab_object+0xf7/0x160 mm/kasan/common.c:240 + __kasan_slab_free+0x32/0x50 mm/kasan/common.c:256 + kasan_slab_free include/linux/kasan.h:184 [inline] + slab_free_hook mm/slub.c:2256 [inline] + slab_free mm/slub.c:4477 [inline] + kfree+0x12a/0x3b0 mm/slub.c:4598 + l2cap_conn_free net/bluetooth/l2cap_core.c:1810 [inline] + kref_put include/linux/kref.h:65 [inline] + l2cap_conn_put net/bluetooth/l2cap_core.c:1822 [inline] + l2cap_conn_del+0x59d/0x730 net/bluetooth/l2cap_core.c:1802 + l2cap_connect_cfm+0x9e6/0xf80 net/bluetooth/l2cap_core.c:7241 + hci_connect_cfm include/net/bluetooth/hci_core.h:1960 [inline] + hci_conn_failed+0x1c3/0x370 net/bluetooth/hci_conn.c:1265 + hci_abort_conn_sync+0x75a/0xb50 net/bluetooth/hci_sync.c:5583 + abort_conn_sync+0x197/0x360 net/bluetooth/hci_conn.c:2917 + hci_cmd_sync_work+0x1a4/0x410 net/bluetooth/hci_sync.c:328 + process_one_work+0x9c5/0x1b40 kernel/workqueue.c:3231 + process_scheduled_works kernel/workqueue.c:3312 [inline] + worker_thread+0x6c8/0xed0 kernel/workqueue.c:3389 + kthread+0x2c1/0x3a0 kernel/kthread.c:389 + ret_from_fork+0x45/0x80 arch/x86/kernel/process.c:147 + ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:244 + +Reported-by: syzbot+c12e2f941af1feb5632c@syzkaller.appspotmail.com +Tested-by: syzbot+c12e2f941af1feb5632c@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=c12e2f941af1feb5632c +Fixes: 7b064edae38d ("Bluetooth: Fix authentication if acl data comes before remote feature evt") +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Xiangyu Chen +Signed-off-by: Guocai He +Signed-off-by: Greg Kroah-Hartman +--- + net/bluetooth/hci_core.c | 2 ++ + net/bluetooth/hci_event.c | 2 +- + net/bluetooth/l2cap_core.c | 9 --------- + 3 files changed, 3 insertions(+), 10 deletions(-) + +--- a/net/bluetooth/hci_core.c ++++ b/net/bluetooth/hci_core.c +@@ -4964,6 +4964,8 @@ static void hci_acldata_packet(struct hc + + hci_dev_lock(hdev); + conn = hci_conn_hash_lookup_handle(hdev, handle); ++ if (conn && hci_dev_test_flag(hdev, HCI_MGMT)) ++ mgmt_device_connected(hdev, conn, NULL, 0); + hci_dev_unlock(hdev); + + if (conn) { +--- a/net/bluetooth/hci_event.c ++++ b/net/bluetooth/hci_event.c +@@ -3338,7 +3338,7 @@ static void hci_remote_features_evt(stru + goto unlock; + } + +- if (!ev->status && !test_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) { ++ if (!ev->status) { + struct hci_cp_remote_name_req cp; + memset(&cp, 0, sizeof(cp)); + bacpy(&cp.bdaddr, &conn->dst); +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -4276,18 +4276,9 @@ sendresp: + static int l2cap_connect_req(struct l2cap_conn *conn, + struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data) + { +- struct hci_dev *hdev = conn->hcon->hdev; +- struct hci_conn *hcon = conn->hcon; +- + if (cmd_len < sizeof(struct l2cap_conn_req)) + return -EPROTO; + +- hci_dev_lock(hdev); +- if (hci_dev_test_flag(hdev, HCI_MGMT) && +- !test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &hcon->flags)) +- mgmt_device_connected(hdev, hcon, NULL, 0); +- hci_dev_unlock(hdev); +- + l2cap_connect(conn, cmd, data, L2CAP_CONN_RSP, 0); + return 0; + } diff --git a/queue-5.15/crypto-hisilicon-qm-inject-error-before-stopping-queue.patch b/queue-5.15/crypto-hisilicon-qm-inject-error-before-stopping-queue.patch new file mode 100644 index 00000000000..968f47403b8 --- /dev/null +++ b/queue-5.15/crypto-hisilicon-qm-inject-error-before-stopping-queue.patch @@ -0,0 +1,108 @@ +From b04f06fc0243600665b3b50253869533b7938468 Mon Sep 17 00:00:00 2001 +From: Weili Qian +Date: Sat, 31 Aug 2024 19:48:31 +0800 +Subject: crypto: hisilicon/qm - inject error before stopping queue + +From: Weili Qian + +commit b04f06fc0243600665b3b50253869533b7938468 upstream. + +The master ooo cannot be completely closed when the +accelerator core reports memory error. Therefore, the driver +needs to inject the qm error to close the master ooo. Currently, +the qm error is injected after stopping queue, memory may be +released immediately after stopping queue, causing the device to +access the released memory. Therefore, error is injected to close master +ooo before stopping queue to ensure that the device does not access +the released memory. + +Fixes: 6c6dd5802c2d ("crypto: hisilicon/qm - add controller reset interface") +Signed-off-by: Weili Qian +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Libo Chen +--- + drivers/crypto/hisilicon/qm.c | 51 +++++++++++++++++++----------------------- + 1 file changed, 24 insertions(+), 27 deletions(-) + +--- a/drivers/crypto/hisilicon/qm.c ++++ b/drivers/crypto/hisilicon/qm.c +@@ -4638,6 +4638,28 @@ static int qm_set_vf_mse(struct hisi_qm + return -ETIMEDOUT; + } + ++static void qm_dev_ecc_mbit_handle(struct hisi_qm *qm) ++{ ++ u32 nfe_enb = 0; ++ ++ /* Kunpeng930 hardware automatically close master ooo when NFE occurs */ ++ if (qm->ver >= QM_HW_V3) ++ return; ++ ++ if (!qm->err_status.is_dev_ecc_mbit && ++ qm->err_status.is_qm_ecc_mbit && ++ qm->err_ini->close_axi_master_ooo) { ++ qm->err_ini->close_axi_master_ooo(qm); ++ } else if (qm->err_status.is_dev_ecc_mbit && ++ !qm->err_status.is_qm_ecc_mbit && ++ !qm->err_ini->close_axi_master_ooo) { ++ nfe_enb = readl(qm->io_base + QM_RAS_NFE_ENABLE); ++ writel(nfe_enb & QM_RAS_NFE_MBIT_DISABLE, ++ qm->io_base + QM_RAS_NFE_ENABLE); ++ writel(QM_ECC_MBIT, qm->io_base + QM_ABNORMAL_INT_SET); ++ } ++} ++ + static int qm_vf_reset_prepare(struct hisi_qm *qm, + enum qm_stop_reason stop_reason) + { +@@ -4742,6 +4764,8 @@ static int qm_controller_reset_prepare(s + return ret; + } + ++ qm_dev_ecc_mbit_handle(qm); ++ + /* PF obtains the information of VF by querying the register. */ + qm_cmd_uninit(qm); + +@@ -4766,31 +4790,6 @@ static int qm_controller_reset_prepare(s + return 0; + } + +-static void qm_dev_ecc_mbit_handle(struct hisi_qm *qm) +-{ +- u32 nfe_enb = 0; +- +- /* Kunpeng930 hardware automatically close master ooo when NFE occurs */ +- if (qm->ver >= QM_HW_V3) +- return; +- +- if (!qm->err_status.is_dev_ecc_mbit && +- qm->err_status.is_qm_ecc_mbit && +- qm->err_ini->close_axi_master_ooo) { +- +- qm->err_ini->close_axi_master_ooo(qm); +- +- } else if (qm->err_status.is_dev_ecc_mbit && +- !qm->err_status.is_qm_ecc_mbit && +- !qm->err_ini->close_axi_master_ooo) { +- +- nfe_enb = readl(qm->io_base + QM_RAS_NFE_ENABLE); +- writel(nfe_enb & QM_RAS_NFE_MBIT_DISABLE, +- qm->io_base + QM_RAS_NFE_ENABLE); +- writel(QM_ECC_MBIT, qm->io_base + QM_ABNORMAL_INT_SET); +- } +-} +- + static int qm_soft_reset(struct hisi_qm *qm) + { + struct pci_dev *pdev = qm->pdev; +@@ -4816,8 +4815,6 @@ static int qm_soft_reset(struct hisi_qm + return ret; + } + +- qm_dev_ecc_mbit_handle(qm); +- + /* OOO register set and check */ + writel(ACC_MASTER_GLOBAL_CTRL_SHUTDOWN, + qm->io_base + ACC_MASTER_GLOBAL_CTRL); diff --git a/queue-5.15/fou-remove-warn-in-gue_gro_receive-on-unsupported-protocol.patch b/queue-5.15/fou-remove-warn-in-gue_gro_receive-on-unsupported-protocol.patch new file mode 100644 index 00000000000..a1a3a92d70b --- /dev/null +++ b/queue-5.15/fou-remove-warn-in-gue_gro_receive-on-unsupported-protocol.patch @@ -0,0 +1,42 @@ +From dd89a81d850fa9a65f67b4527c0e420d15bf836c Mon Sep 17 00:00:00 2001 +From: Willem de Bruijn +Date: Fri, 14 Jun 2024 08:25:18 -0400 +Subject: fou: remove warn in gue_gro_receive on unsupported protocol + +From: Willem de Bruijn + +commit dd89a81d850fa9a65f67b4527c0e420d15bf836c upstream. + +Drop the WARN_ON_ONCE inn gue_gro_receive if the encapsulated type is +not known or does not have a GRO handler. + +Such a packet is easily constructed. Syzbot generates them and sets +off this warning. + +Remove the warning as it is expected and not actionable. + +The warning was previously reduced from WARN_ON to WARN_ON_ONCE in +commit 270136613bf7 ("fou: Do WARN_ON_ONCE in gue_gro_receive for bad +proto callbacks"). + +Signed-off-by: Willem de Bruijn +Reviewed-by: Eric Dumazet +Link: https://lore.kernel.org/r/20240614122552.1649044-1-willemdebruijn.kernel@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Libo Chen +--- + net/ipv4/fou.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/ipv4/fou.c ++++ b/net/ipv4/fou.c +@@ -453,7 +453,7 @@ next_proto: + + offloads = NAPI_GRO_CB(skb)->is_ipv6 ? inet6_offloads : inet_offloads; + ops = rcu_dereference(offloads[proto]); +- if (WARN_ON_ONCE(!ops || !ops->callbacks.gro_receive)) ++ if (!ops || !ops->callbacks.gro_receive) + goto out; + + pp = call_gro_receive(ops->callbacks.gro_receive, head, skb); diff --git a/queue-5.15/gve-fixes-for-napi_poll-when-budget-is-0.patch b/queue-5.15/gve-fixes-for-napi_poll-when-budget-is-0.patch new file mode 100644 index 00000000000..83aee3d0788 --- /dev/null +++ b/queue-5.15/gve-fixes-for-napi_poll-when-budget-is-0.patch @@ -0,0 +1,78 @@ +From 278a370c1766060d2144d6cf0b06c101e1043b6d Mon Sep 17 00:00:00 2001 +From: Ziwei Xiao +Date: Mon, 13 Nov 2023 16:41:44 -0800 +Subject: gve: Fixes for napi_poll when budget is 0 + +From: Ziwei Xiao + +commit 278a370c1766060d2144d6cf0b06c101e1043b6d upstream. + +Netpoll will explicilty pass the polling call with a budget of 0 to +indicate it's clearing the Tx path only. For the gve_rx_poll and +gve_xdp_poll, they were mistakenly taking the 0 budget as the indication +to do all the work. Add check to avoid the rx path and xdp path being +called when budget is 0. And also avoid napi_complete_done being called +when budget is 0 for netpoll. + +Fixes: f5cedc84a30d ("gve: Add transmit and receive support") +Signed-off-by: Ziwei Xiao +Link: https://lore.kernel.org/r/20231114004144.2022268-1-ziweixiao@google.com +Signed-off-by: Jakub Kicinski +Reviewed-by: Praveen Kaligineedi +Signed-off-by: Praveen Kaligineedi +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/google/gve/gve_main.c | 7 +++++++ + drivers/net/ethernet/google/gve/gve_rx.c | 4 ---- + drivers/net/ethernet/google/gve/gve_tx.c | 4 ---- + 3 files changed, 7 insertions(+), 8 deletions(-) + +--- a/drivers/net/ethernet/google/gve/gve_main.c ++++ b/drivers/net/ethernet/google/gve/gve_main.c +@@ -201,6 +201,10 @@ static int gve_napi_poll(struct napi_str + + if (block->tx) + reschedule |= gve_tx_poll(block, budget); ++ ++ if (!budget) ++ return 0; ++ + if (block->rx) + reschedule |= gve_rx_poll(block, budget); + +@@ -236,6 +240,9 @@ static int gve_napi_poll_dqo(struct napi + if (block->tx) + reschedule |= gve_tx_poll_dqo(block, /*do_clean=*/true); + ++ if (!budget) ++ return 0; ++ + if (block->rx) { + work_done = gve_rx_poll_dqo(block, budget); + reschedule |= work_done == budget; +--- a/drivers/net/ethernet/google/gve/gve_rx.c ++++ b/drivers/net/ethernet/google/gve/gve_rx.c +@@ -606,10 +606,6 @@ bool gve_rx_poll(struct gve_notify_block + + feat = block->napi.dev->features; + +- /* If budget is 0, do all the work */ +- if (budget == 0) +- budget = INT_MAX; +- + if (budget > 0) + repoll |= gve_clean_rx_done(rx, budget, feat); + else +--- a/drivers/net/ethernet/google/gve/gve_tx.c ++++ b/drivers/net/ethernet/google/gve/gve_tx.c +@@ -686,10 +686,6 @@ bool gve_tx_poll(struct gve_notify_block + u32 nic_done; + u32 to_do; + +- /* If budget is 0, do all the work */ +- if (budget == 0) +- budget = INT_MAX; +- + /* Find out how much work there is to be done */ + tx->last_nic_done = gve_tx_load_event_counter(priv, tx); + nic_done = be32_to_cpu(tx->last_nic_done); diff --git a/queue-5.15/ima-fix-use-after-free-on-a-dentry-s-dname.name.patch b/queue-5.15/ima-fix-use-after-free-on-a-dentry-s-dname.name.patch new file mode 100644 index 00000000000..d72401d3ef5 --- /dev/null +++ b/queue-5.15/ima-fix-use-after-free-on-a-dentry-s-dname.name.patch @@ -0,0 +1,114 @@ +From be84f32bb2c981ca670922e047cdde1488b233de Mon Sep 17 00:00:00 2001 +From: Stefan Berger +Date: Fri, 22 Mar 2024 10:03:12 -0400 +Subject: ima: Fix use-after-free on a dentry's dname.name + +From: Stefan Berger + +commit be84f32bb2c981ca670922e047cdde1488b233de upstream. + +->d_name.name can change on rename and the earlier value can be freed; +there are conditions sufficient to stabilize it (->d_lock on dentry, +->d_lock on its parent, ->i_rwsem exclusive on the parent's inode, +rename_lock), but none of those are met at any of the sites. Take a stable +snapshot of the name instead. + +Link: https://lore.kernel.org/all/20240202182732.GE2087318@ZenIV/ +Signed-off-by: Al Viro +Signed-off-by: Stefan Berger +Signed-off-by: Mimi Zohar +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Libo Chen +--- + security/integrity/ima/ima_api.c | 16 ++++++++++++---- + security/integrity/ima/ima_template_lib.c | 17 ++++++++++++++--- + 2 files changed, 26 insertions(+), 7 deletions(-) + +--- a/security/integrity/ima/ima_api.c ++++ b/security/integrity/ima/ima_api.c +@@ -217,7 +217,7 @@ int ima_collect_measurement(struct integ + const char *audit_cause = "failed"; + struct inode *inode = file_inode(file); + struct inode *real_inode = d_real_inode(file_dentry(file)); +- const char *filename = file->f_path.dentry->d_name.name; ++ struct name_snapshot filename; + int result = 0; + int length; + void *tmpbuf; +@@ -280,9 +280,13 @@ out: + if (file->f_flags & O_DIRECT) + audit_cause = "failed(directio)"; + ++ take_dentry_name_snapshot(&filename, file->f_path.dentry); ++ + integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, +- filename, "collect_data", audit_cause, +- result, 0); ++ filename.name.name, "collect_data", ++ audit_cause, result, 0); ++ ++ release_dentry_name_snapshot(&filename); + } + return result; + } +@@ -395,6 +399,7 @@ out: + */ + const char *ima_d_path(const struct path *path, char **pathbuf, char *namebuf) + { ++ struct name_snapshot filename; + char *pathname = NULL; + + *pathbuf = __getname(); +@@ -408,7 +413,10 @@ const char *ima_d_path(const struct path + } + + if (!pathname) { +- strlcpy(namebuf, path->dentry->d_name.name, NAME_MAX); ++ take_dentry_name_snapshot(&filename, path->dentry); ++ strscpy(namebuf, filename.name.name, NAME_MAX); ++ release_dentry_name_snapshot(&filename); ++ + pathname = namebuf; + } + +--- a/security/integrity/ima/ima_template_lib.c ++++ b/security/integrity/ima/ima_template_lib.c +@@ -426,7 +426,10 @@ static int ima_eventname_init_common(str + bool size_limit) + { + const char *cur_filename = NULL; ++ struct name_snapshot filename; + u32 cur_filename_len = 0; ++ bool snapshot = false; ++ int ret; + + BUG_ON(event_data->filename == NULL && event_data->file == NULL); + +@@ -439,7 +442,10 @@ static int ima_eventname_init_common(str + } + + if (event_data->file) { +- cur_filename = event_data->file->f_path.dentry->d_name.name; ++ take_dentry_name_snapshot(&filename, ++ event_data->file->f_path.dentry); ++ snapshot = true; ++ cur_filename = filename.name.name; + cur_filename_len = strlen(cur_filename); + } else + /* +@@ -448,8 +454,13 @@ static int ima_eventname_init_common(str + */ + cur_filename_len = IMA_EVENT_NAME_LEN_MAX; + out: +- return ima_write_template_field_data(cur_filename, cur_filename_len, +- DATA_FMT_STRING, field_data); ++ ret = ima_write_template_field_data(cur_filename, cur_filename_len, ++ DATA_FMT_STRING, field_data); ++ ++ if (snapshot) ++ release_dentry_name_snapshot(&filename); ++ ++ return ret; + } + + /* diff --git a/queue-5.15/net-dsa-microchip-correct-ksz8795-static-mac-table-access.patch b/queue-5.15/net-dsa-microchip-correct-ksz8795-static-mac-table-access.patch new file mode 100644 index 00000000000..f747cc52f46 --- /dev/null +++ b/queue-5.15/net-dsa-microchip-correct-ksz8795-static-mac-table-access.patch @@ -0,0 +1,75 @@ +From 4bdf79d686b49ac49373b36466acfb93972c7d7c Mon Sep 17 00:00:00 2001 +From: Tristram Ha +Date: Thu, 13 Jul 2023 17:46:22 -0700 +Subject: net: dsa: microchip: correct KSZ8795 static MAC table access + +From: Tristram Ha + +commit 4bdf79d686b49ac49373b36466acfb93972c7d7c upstream. + +The KSZ8795 driver code was modified to use on KSZ8863/73, which has +different register definitions. Some of the new KSZ8795 register +information are wrong compared to previous code. + +KSZ8795 also behaves differently in that the STATIC_MAC_TABLE_USE_FID +and STATIC_MAC_TABLE_FID bits are off by 1 when doing MAC table reading +than writing. To compensate that a special code was added to shift the +register value by 1 before applying those bits. This is wrong when the +code is running on KSZ8863, so this special code is only executed when +KSZ8795 is detected. + +Fixes: 4b20a07e103f ("net: dsa: microchip: ksz8795: add support for ksz88xx chips") +Signed-off-by: Tristram Ha +Reviewed-by: Horatiu Vultur +Reviewed-by: Simon Horman +Signed-off-by: David S. Miller +Signed-off-by: Jörg Sommer +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/dsa/microchip/ksz8795.c | 18 +++++++++++++----- + 1 file changed, 13 insertions(+), 5 deletions(-) + +--- a/drivers/net/dsa/microchip/ksz8795.c ++++ b/drivers/net/dsa/microchip/ksz8795.c +@@ -25,6 +25,8 @@ + #include "ksz8795_reg.h" + #include "ksz8.h" + ++#define KSZ8795_CHIP_ID 0x09 ++ + static const u8 ksz8795_regs[] = { + [REG_IND_CTRL_0] = 0x6E, + [REG_IND_DATA_8] = 0x70, +@@ -52,13 +54,13 @@ static const u32 ksz8795_masks[] = { + [STATIC_MAC_TABLE_VALID] = BIT(21), + [STATIC_MAC_TABLE_USE_FID] = BIT(23), + [STATIC_MAC_TABLE_FID] = GENMASK(30, 24), +- [STATIC_MAC_TABLE_OVERRIDE] = BIT(26), +- [STATIC_MAC_TABLE_FWD_PORTS] = GENMASK(24, 20), ++ [STATIC_MAC_TABLE_OVERRIDE] = BIT(22), ++ [STATIC_MAC_TABLE_FWD_PORTS] = GENMASK(20, 16), + [DYNAMIC_MAC_TABLE_ENTRIES_H] = GENMASK(6, 0), +- [DYNAMIC_MAC_TABLE_MAC_EMPTY] = BIT(8), ++ [DYNAMIC_MAC_TABLE_MAC_EMPTY] = BIT(7), + [DYNAMIC_MAC_TABLE_NOT_READY] = BIT(7), + [DYNAMIC_MAC_TABLE_ENTRIES] = GENMASK(31, 29), +- [DYNAMIC_MAC_TABLE_FID] = GENMASK(26, 20), ++ [DYNAMIC_MAC_TABLE_FID] = GENMASK(22, 16), + [DYNAMIC_MAC_TABLE_SRC_PORT] = GENMASK(26, 24), + [DYNAMIC_MAC_TABLE_TIMESTAMP] = GENMASK(28, 27), + }; +@@ -601,7 +603,13 @@ static int ksz8_r_sta_mac_table(struct k + shifts[STATIC_MAC_FWD_PORTS]; + alu->is_override = + (data_hi & masks[STATIC_MAC_TABLE_OVERRIDE]) ? 1 : 0; +- data_hi >>= 1; ++ ++ /* KSZ8795 family switches have STATIC_MAC_TABLE_USE_FID and ++ * STATIC_MAC_TABLE_FID definitions off by 1 when doing read on the ++ * static MAC table compared to doing write. ++ */ ++ if (dev->chip_id == KSZ8795_CHIP_ID) ++ data_hi >>= 1; + alu->is_static = true; + alu->is_use_fid = + (data_hi & masks[STATIC_MAC_TABLE_USE_FID]) ? 1 : 0; diff --git a/queue-5.15/revert-drm-amdgpu-add-missing-size-check-in-amdgpu_debugfs_gprwave_read.patch b/queue-5.15/revert-drm-amdgpu-add-missing-size-check-in-amdgpu_debugfs_gprwave_read.patch new file mode 100644 index 00000000000..ebba14eec57 --- /dev/null +++ b/queue-5.15/revert-drm-amdgpu-add-missing-size-check-in-amdgpu_debugfs_gprwave_read.patch @@ -0,0 +1,34 @@ +From zhangzekun11@huawei.com Thu Dec 12 12:45:23 2024 +From: Zhang Zekun +Date: Wed, 4 Dec 2024 16:26:27 +0800 +Subject: Revert "drm/amdgpu: add missing size check in amdgpu_debugfs_gprwave_read()" +To: +Cc: , , , , , +Message-ID: <20241204082627.3756-1-zhangzekun11@huawei.com> + +From: Zhang Zekun + +This reverts commit aaf6160a4b7f9ee3cd91aa5b3251f5dbe2170f42. + +The origin mainline patch fix a buffer overflow issue in +amdgpu_debugfs_gprwave_read(), but it has not been introduced in kernel +6.1 and older kernels. This patch add a check in a wrong function in the +same file. + +Signed-off-by: Zhang Zekun +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c +@@ -401,7 +401,7 @@ static ssize_t amdgpu_debugfs_regs_didt_ + ssize_t result = 0; + int r; + +- if (size > 4096 || size & 0x3 || *pos & 0x3) ++ if (size & 0x3 || *pos & 0x3) + return -EINVAL; + + if (!adev->didt_wreg) diff --git a/queue-5.15/scsi-core-fix-scsi_mode_select-buffer-length-handling.patch b/queue-5.15/scsi-core-fix-scsi_mode_select-buffer-length-handling.patch new file mode 100644 index 00000000000..0519ba368f9 --- /dev/null +++ b/queue-5.15/scsi-core-fix-scsi_mode_select-buffer-length-handling.patch @@ -0,0 +1,71 @@ +From a7d6840bed0c2b16ac3071b74b5fcf08fc488241 Mon Sep 17 00:00:00 2001 +From: Damien Le Moal +Date: Fri, 20 Aug 2021 16:02:54 +0900 +Subject: scsi: core: Fix scsi_mode_select() buffer length handling + +From: Damien Le Moal + +commit a7d6840bed0c2b16ac3071b74b5fcf08fc488241 upstream. + +The MODE SELECT(6) command allows handling mode page buffers that are up to +255 bytes, including the 4 byte header needed in front of the page +buffer. For requests larger than this limit, automatically use the MODE +SELECT(10) command. + +In both cases, since scsi_mode_select() adds the mode select page header, +checks on the buffer length value must include this header size to avoid +overflows of the command CDB allocation length field. + +While at it, use put_unaligned_be16() for setting the header block +descriptor length and CDB allocation length when using MODE SELECT(10). + +[mkp: fix MODE SENSE vs. MODE SELECT confusion] + +Link: https://lore.kernel.org/r/20210820070255.682775-3-damien.lemoal@wdc.com +Signed-off-by: Damien Le Moal +Signed-off-by: Martin K. Petersen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/scsi/scsi_lib.c | 21 +++++++++++++-------- + 1 file changed, 13 insertions(+), 8 deletions(-) + +--- a/drivers/scsi/scsi_lib.c ++++ b/drivers/scsi/scsi_lib.c +@@ -2044,8 +2044,15 @@ scsi_mode_select(struct scsi_device *sde + memset(cmd, 0, sizeof(cmd)); + cmd[1] = (pf ? 0x10 : 0) | (sp ? 0x01 : 0); + +- if (sdev->use_10_for_ms) { +- if (len > 65535) ++ /* ++ * Use MODE SELECT(10) if the device asked for it or if the mode page ++ * and the mode select header cannot fit within the maximumm 255 bytes ++ * of the MODE SELECT(6) command. ++ */ ++ if (sdev->use_10_for_ms || ++ len + 4 > 255 || ++ data->block_descriptor_length > 255) { ++ if (len > 65535 - 8) + return -EINVAL; + real_buffer = kmalloc(8 + len, GFP_KERNEL); + if (!real_buffer) +@@ -2058,15 +2065,13 @@ scsi_mode_select(struct scsi_device *sde + real_buffer[3] = data->device_specific; + real_buffer[4] = data->longlba ? 0x01 : 0; + real_buffer[5] = 0; +- real_buffer[6] = data->block_descriptor_length >> 8; +- real_buffer[7] = data->block_descriptor_length; ++ put_unaligned_be16(data->block_descriptor_length, ++ &real_buffer[6]); + + cmd[0] = MODE_SELECT_10; +- cmd[7] = len >> 8; +- cmd[8] = len; ++ put_unaligned_be16(len, &cmd[7]); + } else { +- if (len > 255 || data->block_descriptor_length > 255 || +- data->longlba) ++ if (data->longlba) + return -EINVAL; + + real_buffer = kmalloc(4 + len, GFP_KERNEL); diff --git a/queue-5.15/serial-sc16is7xx-change-efr-lock-to-operate-on-each-channels.patch b/queue-5.15/serial-sc16is7xx-change-efr-lock-to-operate-on-each-channels.patch new file mode 100644 index 00000000000..0f4b7b19796 --- /dev/null +++ b/queue-5.15/serial-sc16is7xx-change-efr-lock-to-operate-on-each-channels.patch @@ -0,0 +1,181 @@ +From 4409df5866b7ff7686ba27e449ca97a92ee063c9 Mon Sep 17 00:00:00 2001 +From: Hugo Villeneuve +Date: Mon, 11 Dec 2023 12:13:51 -0500 +Subject: serial: sc16is7xx: change EFR lock to operate on each channels + +From: Hugo Villeneuve + +commit 4409df5866b7ff7686ba27e449ca97a92ee063c9 upstream. + +Now that the driver has been converted to use one regmap per port, change +efr locking to operate on a channel basis instead of on the whole IC. + +Fixes: 3837a0379533 ("serial: sc16is7xx: improve regmap debugfs by using one regmap per port") +Cc: # 6.1.x: 3837a03 serial: sc16is7xx: improve regmap debugfs by using one regmap per port +Signed-off-by: Hugo Villeneuve +Link: https://lore.kernel.org/r/20231211171353.2901416-5-hugo@hugovil.com +[Hui: fixed some conflict when backporting to 5.15.y] +Signed-off-by: Hui Wang +Signed-off-by: Greg Kroah-Hartman +--- + drivers/tty/serial/sc16is7xx.c | 41 +++++++++++++++++++++++------------------ + 1 file changed, 23 insertions(+), 18 deletions(-) + +--- a/drivers/tty/serial/sc16is7xx.c ++++ b/drivers/tty/serial/sc16is7xx.c +@@ -314,6 +314,7 @@ struct sc16is7xx_one_config { + struct sc16is7xx_one { + struct uart_port port; + struct regmap *regmap; ++ struct mutex efr_lock; /* EFR registers access */ + struct kthread_work tx_work; + struct kthread_work reg_work; + struct sc16is7xx_one_config config; +@@ -329,7 +330,6 @@ struct sc16is7xx_port { + unsigned char buf[SC16IS7XX_FIFO_SIZE]; + struct kthread_worker kworker; + struct task_struct *kworker_task; +- struct mutex efr_lock; + struct sc16is7xx_one p[]; + }; + +@@ -491,7 +491,6 @@ static bool sc16is7xx_regmap_noinc(struc + */ + static int sc16is7xx_set_baud(struct uart_port *port, int baud) + { +- struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + u8 lcr; + unsigned int prescaler = 1; +@@ -515,7 +514,7 @@ static int sc16is7xx_set_baud(struct uar + * because the bulk of the interrupt processing is run as a workqueue + * job in thread context. + */ +- mutex_lock(&s->efr_lock); ++ mutex_lock(&one->efr_lock); + + lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG); + +@@ -532,7 +531,7 @@ static int sc16is7xx_set_baud(struct uar + /* Put LCR back to the normal mode */ + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr); + +- mutex_unlock(&s->efr_lock); ++ mutex_unlock(&one->efr_lock); + + /* If bit MCR_CLKSEL is set, the divide by 4 prescaler is activated. */ + sc16is7xx_port_update(port, SC16IS7XX_MCR_REG, +@@ -680,14 +679,20 @@ static void sc16is7xx_handle_tx(struct u + + static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno) + { ++ bool rc = true; + struct uart_port *port = &s->p[portno].port; ++ struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); ++ ++ mutex_lock(&one->efr_lock); + + do { + unsigned int iir, rxlen; + + iir = sc16is7xx_port_read(port, SC16IS7XX_IIR_REG); +- if (iir & SC16IS7XX_IIR_NO_INT_BIT) +- return false; ++ if (iir & SC16IS7XX_IIR_NO_INT_BIT) { ++ rc = false; ++ goto out_port_irq; ++ } + + iir &= SC16IS7XX_IIR_ID_MASK; + +@@ -722,15 +727,17 @@ static bool sc16is7xx_port_irq(struct sc + break; + } + } while (0); +- return true; ++ ++out_port_irq: ++ mutex_unlock(&one->efr_lock); ++ ++ return rc; + } + + static irqreturn_t sc16is7xx_irq(int irq, void *dev_id) + { + struct sc16is7xx_port *s = (struct sc16is7xx_port *)dev_id; + +- mutex_lock(&s->efr_lock); +- + while (1) { + bool keep_polling = false; + int i; +@@ -741,23 +748,21 @@ static irqreturn_t sc16is7xx_irq(int irq + break; + } + +- mutex_unlock(&s->efr_lock); +- + return IRQ_HANDLED; + } + + static void sc16is7xx_tx_proc(struct kthread_work *ws) + { + struct uart_port *port = &(to_sc16is7xx_one(ws, tx_work)->port); +- struct sc16is7xx_port *s = dev_get_drvdata(port->dev); ++ struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + + if ((port->rs485.flags & SER_RS485_ENABLED) && + (port->rs485.delay_rts_before_send > 0)) + msleep(port->rs485.delay_rts_before_send); + +- mutex_lock(&s->efr_lock); ++ mutex_lock(&one->efr_lock); + sc16is7xx_handle_tx(port); +- mutex_unlock(&s->efr_lock); ++ mutex_unlock(&one->efr_lock); + } + + static void sc16is7xx_reconf_rs485(struct uart_port *port) +@@ -878,7 +883,6 @@ static void sc16is7xx_set_termios(struct + struct ktermios *termios, + struct ktermios *old) + { +- struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + unsigned int lcr, flow = 0; + int baud; +@@ -934,7 +938,7 @@ static void sc16is7xx_set_termios(struct + port->ignore_status_mask |= SC16IS7XX_LSR_BRK_ERROR_MASK; + + /* As above, claim the mutex while accessing the EFR. */ +- mutex_lock(&s->efr_lock); ++ mutex_lock(&one->efr_lock); + + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, + SC16IS7XX_LCR_CONF_MODE_B); +@@ -957,7 +961,7 @@ static void sc16is7xx_set_termios(struct + /* Update LCR register */ + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr); + +- mutex_unlock(&s->efr_lock); ++ mutex_unlock(&one->efr_lock); + + /* Get baud rate generator configuration */ + baud = uart_get_baud_rate(port, termios, old, +@@ -1261,7 +1265,6 @@ static int sc16is7xx_probe(struct device + + s->devtype = devtype; + dev_set_drvdata(dev, s); +- mutex_init(&s->efr_lock); + + kthread_init_worker(&s->kworker); + s->kworker_task = kthread_run(kthread_worker_fn, &s->kworker, +@@ -1302,6 +1305,8 @@ static int sc16is7xx_probe(struct device + goto out_ports; + } + ++ mutex_init(&s->p[i].efr_lock); ++ + /* Disable all interrupts */ + sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_IER_REG, 0); + /* Disable TX/RX */ diff --git a/queue-5.15/serial-sc16is7xx-improve-regmap-debugfs-by-using-one-regmap-per-port.patch b/queue-5.15/serial-sc16is7xx-improve-regmap-debugfs-by-using-one-regmap-per-port.patch new file mode 100644 index 00000000000..f49b3009f46 --- /dev/null +++ b/queue-5.15/serial-sc16is7xx-improve-regmap-debugfs-by-using-one-regmap-per-port.patch @@ -0,0 +1,432 @@ +From 3837a0379533aabb9e4483677077479f7c6aa910 Mon Sep 17 00:00:00 2001 +From: Hugo Villeneuve +Date: Mon, 30 Oct 2023 17:14:47 -0400 +Subject: serial: sc16is7xx: improve regmap debugfs by using one regmap per port + +From: Hugo Villeneuve + +commit 3837a0379533aabb9e4483677077479f7c6aa910 upstream. + +With this current driver regmap implementation, it is hard to make sense +of the register addresses displayed using the regmap debugfs interface, +because they do not correspond to the actual register addresses documented +in the datasheet. For example, register 1 is displayed as registers 04 thru +07: + +$ cat /sys/kernel/debug/regmap/spi0.0/registers + 04: 10 -> Port 0, register offset 1 + 05: 10 -> Port 1, register offset 1 + 06: 00 -> Port 2, register offset 1 -> invalid + 07: 00 -> port 3, register offset 1 -> invalid + ... + +The reason is that bits 0 and 1 of the register address correspond to the +channel (port) bits, so the register address itself starts at bit 2, and we +must 'mentally' shift each register address by 2 bits to get its real +address/offset. + +Also, only channels 0 and 1 are supported by the chip, so channel mask +combinations of 10b and 11b are invalid, and the display of these +registers is useless. + +This patch adds a separate regmap configuration for each port, similar to +what is done in the max310x driver, so that register addresses displayed +match the register addresses in the chip datasheet. Also, each port now has +its own debugfs entry. + +Example with new regmap implementation: + +$ cat /sys/kernel/debug/regmap/spi0.0-port0/registers +1: 10 +2: 01 +3: 00 +... + +$ cat /sys/kernel/debug/regmap/spi0.0-port1/registers +1: 10 +2: 01 +3: 00 + +As an added bonus, this also simplifies some operations (read/write/modify) +because it is no longer necessary to manually shift register addresses. + +Signed-off-by: Hugo Villeneuve +Link: https://lore.kernel.org/r/20231030211447.974779-1-hugo@hugovil.com +[Hui: Fixed some conflict when backporting to 5.15.y] +Signed-off-by: Hui Wang +Signed-off-by: Greg Kroah-Hartman +--- + drivers/tty/serial/sc16is7xx.c | 136 +++++++++++++++++++++++------------------ + 1 file changed, 79 insertions(+), 57 deletions(-) + +--- a/drivers/tty/serial/sc16is7xx.c ++++ b/drivers/tty/serial/sc16is7xx.c +@@ -292,8 +292,9 @@ + */ + + /* Misc definitions */ ++#define SC16IS7XX_SPI_READ_BIT BIT(7) + #define SC16IS7XX_FIFO_SIZE (64) +-#define SC16IS7XX_REG_SHIFT 2 ++#define SC16IS7XX_GPIOS_PER_BANK 4 + + struct sc16is7xx_devtype { + char name[10]; +@@ -313,6 +314,7 @@ struct sc16is7xx_one_config { + struct sc16is7xx_one { + struct uart_port port; + u8 line; ++ struct regmap *regmap; + struct kthread_work tx_work; + struct kthread_work reg_work; + struct sc16is7xx_one_config config; +@@ -344,46 +346,35 @@ static struct uart_driver sc16is7xx_uart + #define to_sc16is7xx_port(p,e) ((container_of((p), struct sc16is7xx_port, e))) + #define to_sc16is7xx_one(p,e) ((container_of((p), struct sc16is7xx_one, e))) + +-static int sc16is7xx_line(struct uart_port *port) +-{ +- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); +- +- return one->line; +-} +- + static u8 sc16is7xx_port_read(struct uart_port *port, u8 reg) + { +- struct sc16is7xx_port *s = dev_get_drvdata(port->dev); ++ struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + unsigned int val = 0; +- const u8 line = sc16is7xx_line(port); + +- regmap_read(s->regmap, (reg << SC16IS7XX_REG_SHIFT) | line, &val); ++ regmap_read(one->regmap, reg, &val); + + return val; + } + + static void sc16is7xx_port_write(struct uart_port *port, u8 reg, u8 val) + { +- struct sc16is7xx_port *s = dev_get_drvdata(port->dev); +- const u8 line = sc16is7xx_line(port); ++ struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + +- regmap_write(s->regmap, (reg << SC16IS7XX_REG_SHIFT) | line, val); ++ regmap_write(one->regmap, reg, val); + } + + static void sc16is7xx_fifo_read(struct uart_port *port, unsigned int rxlen) + { + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); +- const u8 line = sc16is7xx_line(port); +- u8 addr = (SC16IS7XX_RHR_REG << SC16IS7XX_REG_SHIFT) | line; ++ struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + +- regmap_noinc_read(s->regmap, addr, s->buf, rxlen); ++ regmap_noinc_read(one->regmap, SC16IS7XX_RHR_REG, s->buf, rxlen); + } + + static void sc16is7xx_fifo_write(struct uart_port *port, u8 to_send) + { + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); +- const u8 line = sc16is7xx_line(port); +- u8 addr = (SC16IS7XX_THR_REG << SC16IS7XX_REG_SHIFT) | line; ++ struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + + /* + * Don't send zero-length data, at least on SPI it confuses the chip +@@ -392,17 +383,15 @@ static void sc16is7xx_fifo_write(struct + if (unlikely(!to_send)) + return; + +- regmap_noinc_write(s->regmap, addr, s->buf, to_send); ++ regmap_noinc_write(one->regmap, SC16IS7XX_THR_REG, s->buf, to_send); + } + + static void sc16is7xx_port_update(struct uart_port *port, u8 reg, + u8 mask, u8 val) + { +- struct sc16is7xx_port *s = dev_get_drvdata(port->dev); +- const u8 line = sc16is7xx_line(port); ++ struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + +- regmap_update_bits(s->regmap, (reg << SC16IS7XX_REG_SHIFT) | line, +- mask, val); ++ regmap_update_bits(one->regmap, reg, mask, val); + } + + static int sc16is7xx_alloc_line(void) +@@ -457,7 +446,7 @@ static const struct sc16is7xx_devtype sc + + static bool sc16is7xx_regmap_volatile(struct device *dev, unsigned int reg) + { +- switch (reg >> SC16IS7XX_REG_SHIFT) { ++ switch (reg) { + case SC16IS7XX_RHR_REG: + case SC16IS7XX_IIR_REG: + case SC16IS7XX_LSR_REG: +@@ -475,7 +464,7 @@ static bool sc16is7xx_regmap_volatile(st + + static bool sc16is7xx_regmap_precious(struct device *dev, unsigned int reg) + { +- switch (reg >> SC16IS7XX_REG_SHIFT) { ++ switch (reg) { + case SC16IS7XX_RHR_REG: + return true; + default: +@@ -505,6 +494,7 @@ static bool sc16is7xx_regmap_noinc(struc + static int sc16is7xx_set_baud(struct uart_port *port, int baud) + { + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); ++ struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + u8 lcr; + unsigned int prescaler = 1; + unsigned long clk = port->uartclk, div = clk / 16 / baud; +@@ -536,10 +526,10 @@ static int sc16is7xx_set_baud(struct uar + SC16IS7XX_LCR_CONF_MODE_B); + + /* Enable enhanced features */ +- regcache_cache_bypass(s->regmap, true); ++ regcache_cache_bypass(one->regmap, true); + sc16is7xx_port_write(port, SC16IS7XX_EFR_REG, + SC16IS7XX_EFR_ENABLE_BIT); +- regcache_cache_bypass(s->regmap, false); ++ regcache_cache_bypass(one->regmap, false); + + /* Put LCR back to the normal mode */ + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr); +@@ -556,10 +546,10 @@ static int sc16is7xx_set_baud(struct uar + SC16IS7XX_LCR_CONF_MODE_A); + + /* Write the new divisor */ +- regcache_cache_bypass(s->regmap, true); ++ regcache_cache_bypass(one->regmap, true); + sc16is7xx_port_write(port, SC16IS7XX_DLH_REG, div / 256); + sc16is7xx_port_write(port, SC16IS7XX_DLL_REG, div % 256); +- regcache_cache_bypass(s->regmap, false); ++ regcache_cache_bypass(one->regmap, false); + + /* Put LCR back to the normal mode */ + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr); +@@ -891,6 +881,7 @@ static void sc16is7xx_set_termios(struct + struct ktermios *old) + { + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); ++ struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + unsigned int lcr, flow = 0; + int baud; + +@@ -951,7 +942,7 @@ static void sc16is7xx_set_termios(struct + SC16IS7XX_LCR_CONF_MODE_B); + + /* Configure flow control */ +- regcache_cache_bypass(s->regmap, true); ++ regcache_cache_bypass(one->regmap, true); + sc16is7xx_port_write(port, SC16IS7XX_XON1_REG, termios->c_cc[VSTART]); + sc16is7xx_port_write(port, SC16IS7XX_XOFF1_REG, termios->c_cc[VSTOP]); + if (termios->c_cflag & CRTSCTS) +@@ -963,7 +954,7 @@ static void sc16is7xx_set_termios(struct + flow |= SC16IS7XX_EFR_SWFLOW1_BIT; + + sc16is7xx_port_write(port, SC16IS7XX_EFR_REG, flow); +- regcache_cache_bypass(s->regmap, false); ++ regcache_cache_bypass(one->regmap, false); + + /* Update LCR register */ + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr); +@@ -1018,7 +1009,6 @@ static int sc16is7xx_config_rs485(struct + static int sc16is7xx_startup(struct uart_port *port) + { + struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); +- struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + unsigned int val; + + sc16is7xx_power(port, 1); +@@ -1034,7 +1024,7 @@ static int sc16is7xx_startup(struct uart + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, + SC16IS7XX_LCR_CONF_MODE_B); + +- regcache_cache_bypass(s->regmap, true); ++ regcache_cache_bypass(one->regmap, true); + + /* Enable write access to enhanced features and internal clock div */ + sc16is7xx_port_write(port, SC16IS7XX_EFR_REG, +@@ -1051,7 +1041,7 @@ static int sc16is7xx_startup(struct uart + SC16IS7XX_TCR_RX_RESUME(24) | + SC16IS7XX_TCR_RX_HALT(48)); + +- regcache_cache_bypass(s->regmap, false); ++ regcache_cache_bypass(one->regmap, false); + + /* Now, initialize the UART */ + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, SC16IS7XX_LCR_WORD_LEN_8); +@@ -1216,7 +1206,7 @@ static int sc16is7xx_gpio_direction_outp + + static int sc16is7xx_probe(struct device *dev, + const struct sc16is7xx_devtype *devtype, +- struct regmap *regmap, int irq) ++ struct regmap *regmaps[], int irq) + { + unsigned long freq = 0, *pfreq = dev_get_platdata(dev); + unsigned int val; +@@ -1224,16 +1214,16 @@ static int sc16is7xx_probe(struct device + int i, ret; + struct sc16is7xx_port *s; + +- if (IS_ERR(regmap)) +- return PTR_ERR(regmap); ++ for (i = 0; i < devtype->nr_uart; i++) ++ if (IS_ERR(regmaps[i])) ++ return PTR_ERR(regmaps[i]); + + /* + * This device does not have an identification register that would + * tell us if we are really connected to the correct device. + * The best we can do is to check if communication is at all possible. + */ +- ret = regmap_read(regmap, +- SC16IS7XX_LSR_REG << SC16IS7XX_REG_SHIFT, &val); ++ ret = regmap_read(regmaps[0], SC16IS7XX_LSR_REG, &val); + if (ret < 0) + return -EPROBE_DEFER; + +@@ -1267,7 +1257,7 @@ static int sc16is7xx_probe(struct device + return -EINVAL; + } + +- s->regmap = regmap; ++ s->regmap = regmaps[0]; + s->devtype = devtype; + dev_set_drvdata(dev, s); + mutex_init(&s->efr_lock); +@@ -1282,8 +1272,8 @@ static int sc16is7xx_probe(struct device + sched_set_fifo(s->kworker_task); + + /* reset device, purging any pending irq / data */ +- regmap_write(s->regmap, SC16IS7XX_IOCONTROL_REG << SC16IS7XX_REG_SHIFT, +- SC16IS7XX_IOCONTROL_SRESET_BIT); ++ regmap_write(s->regmap, SC16IS7XX_IOCONTROL_REG, ++ SC16IS7XX_IOCONTROL_SRESET_BIT); + + for (i = 0; i < devtype->nr_uart; ++i) { + s->p[i].line = i; +@@ -1305,6 +1295,8 @@ static int sc16is7xx_probe(struct device + s->p[i].port.rs485_config = sc16is7xx_config_rs485; + s->p[i].port.ops = &sc16is7xx_ops; + s->p[i].port.line = sc16is7xx_alloc_line(); ++ s->p[i].regmap = regmaps[i]; ++ + if (s->p[i].port.line >= SC16IS7XX_MAX_DEVS) { + ret = -ENOMEM; + goto out_ports; +@@ -1326,13 +1318,13 @@ static int sc16is7xx_probe(struct device + sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_LCR_REG, + SC16IS7XX_LCR_CONF_MODE_B); + +- regcache_cache_bypass(s->regmap, true); ++ regcache_cache_bypass(regmaps[i], true); + + /* Enable write access to enhanced features */ + sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_EFR_REG, + SC16IS7XX_EFR_ENABLE_BIT); + +- regcache_cache_bypass(s->regmap, false); ++ regcache_cache_bypass(regmaps[i], false); + + /* Restore access to general registers */ + sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_LCR_REG, 0x00); +@@ -1447,21 +1439,38 @@ static const struct of_device_id __maybe + MODULE_DEVICE_TABLE(of, sc16is7xx_dt_ids); + + static struct regmap_config regcfg = { +- .reg_bits = 7, +- .pad_bits = 1, ++ .reg_bits = 5, ++ .pad_bits = 3, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .volatile_reg = sc16is7xx_regmap_volatile, + .precious_reg = sc16is7xx_regmap_precious, + .writeable_noinc_reg = sc16is7xx_regmap_noinc, + .readable_noinc_reg = sc16is7xx_regmap_noinc, ++ .max_register = SC16IS7XX_EFCR_REG, + }; + ++static const char *sc16is7xx_regmap_name(unsigned int port_id) ++{ ++ static char buf[6]; ++ ++ snprintf(buf, sizeof(buf), "port%d", port_id); ++ ++ return buf; ++} ++ ++static unsigned int sc16is7xx_regmap_port_mask(unsigned int port_id) ++{ ++ /* CH1,CH0 are at bits 2:1. */ ++ return port_id << 1; ++} ++ + #ifdef CONFIG_SERIAL_SC16IS7XX_SPI + static int sc16is7xx_spi_probe(struct spi_device *spi) + { + const struct sc16is7xx_devtype *devtype; +- struct regmap *regmap; ++ struct regmap *regmaps[2]; ++ unsigned int i; + int ret; + + /* Setup SPI bus */ +@@ -1486,11 +1495,20 @@ static int sc16is7xx_spi_probe(struct sp + devtype = (struct sc16is7xx_devtype *)id_entry->driver_data; + } + +- regcfg.max_register = (0xf << SC16IS7XX_REG_SHIFT) | +- (devtype->nr_uart - 1); +- regmap = devm_regmap_init_spi(spi, ®cfg); ++ for (i = 0; i < devtype->nr_uart; i++) { ++ regcfg.name = sc16is7xx_regmap_name(i); ++ /* ++ * If read_flag_mask is 0, the regmap code sets it to a default ++ * of 0x80. Since we specify our own mask, we must add the READ ++ * bit ourselves: ++ */ ++ regcfg.read_flag_mask = sc16is7xx_regmap_port_mask(i) | ++ SC16IS7XX_SPI_READ_BIT; ++ regcfg.write_flag_mask = sc16is7xx_regmap_port_mask(i); ++ regmaps[i] = devm_regmap_init_spi(spi, ®cfg); ++ } + +- return sc16is7xx_probe(&spi->dev, devtype, regmap, spi->irq); ++ return sc16is7xx_probe(&spi->dev, devtype, regmaps, spi->irq); + } + + static int sc16is7xx_spi_remove(struct spi_device *spi) +@@ -1529,7 +1547,8 @@ static int sc16is7xx_i2c_probe(struct i2 + const struct i2c_device_id *id) + { + const struct sc16is7xx_devtype *devtype; +- struct regmap *regmap; ++ struct regmap *regmaps[2]; ++ unsigned int i; + + if (i2c->dev.of_node) { + devtype = device_get_match_data(&i2c->dev); +@@ -1539,11 +1558,14 @@ static int sc16is7xx_i2c_probe(struct i2 + devtype = (struct sc16is7xx_devtype *)id->driver_data; + } + +- regcfg.max_register = (0xf << SC16IS7XX_REG_SHIFT) | +- (devtype->nr_uart - 1); +- regmap = devm_regmap_init_i2c(i2c, ®cfg); ++ for (i = 0; i < devtype->nr_uart; i++) { ++ regcfg.name = sc16is7xx_regmap_name(i); ++ regcfg.read_flag_mask = sc16is7xx_regmap_port_mask(i); ++ regcfg.write_flag_mask = sc16is7xx_regmap_port_mask(i); ++ regmaps[i] = devm_regmap_init_i2c(i2c, ®cfg); ++ } + +- return sc16is7xx_probe(&i2c->dev, devtype, regmap, i2c->irq); ++ return sc16is7xx_probe(&i2c->dev, devtype, regmaps, i2c->irq); + } + + static int sc16is7xx_i2c_remove(struct i2c_client *client) diff --git a/queue-5.15/serial-sc16is7xx-remove-global-regmap-from-struct-sc16is7xx_port.patch b/queue-5.15/serial-sc16is7xx-remove-global-regmap-from-struct-sc16is7xx_port.patch new file mode 100644 index 00000000000..303936622f6 --- /dev/null +++ b/queue-5.15/serial-sc16is7xx-remove-global-regmap-from-struct-sc16is7xx_port.patch @@ -0,0 +1,64 @@ +From f6959c5217bd799bcb770b95d3c09b3244e175c6 Mon Sep 17 00:00:00 2001 +From: Hugo Villeneuve +Date: Mon, 11 Dec 2023 12:13:49 -0500 +Subject: serial: sc16is7xx: remove global regmap from struct sc16is7xx_port + +From: Hugo Villeneuve + +commit f6959c5217bd799bcb770b95d3c09b3244e175c6 upstream. + +Remove global struct regmap so that it is more obvious that this +regmap is to be used only in the probe function. + +Also add a comment to that effect in probe function. + +Fixes: 3837a0379533 ("serial: sc16is7xx: improve regmap debugfs by using one regmap per port") +Cc: +Suggested-by: Andy Shevchenko +Signed-off-by: Hugo Villeneuve +Link: https://lore.kernel.org/r/20231211171353.2901416-3-hugo@hugovil.com +[Hui: fixed some conflict when backporting to 5.15.y] +Signed-off-by: Hui Wang +Signed-off-by: Greg Kroah-Hartman +--- + drivers/tty/serial/sc16is7xx.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +--- a/drivers/tty/serial/sc16is7xx.c ++++ b/drivers/tty/serial/sc16is7xx.c +@@ -323,7 +323,6 @@ struct sc16is7xx_one { + + struct sc16is7xx_port { + const struct sc16is7xx_devtype *devtype; +- struct regmap *regmap; + struct clk *clk; + #ifdef CONFIG_GPIOLIB + struct gpio_chip gpio; +@@ -1222,6 +1221,10 @@ static int sc16is7xx_probe(struct device + * This device does not have an identification register that would + * tell us if we are really connected to the correct device. + * The best we can do is to check if communication is at all possible. ++ * ++ * Note: regmap[0] is used in the probe function to access registers ++ * common to all channels/ports, as it is guaranteed to be present on ++ * all variants. + */ + ret = regmap_read(regmaps[0], SC16IS7XX_LSR_REG, &val); + if (ret < 0) +@@ -1257,7 +1260,6 @@ static int sc16is7xx_probe(struct device + return -EINVAL; + } + +- s->regmap = regmaps[0]; + s->devtype = devtype; + dev_set_drvdata(dev, s); + mutex_init(&s->efr_lock); +@@ -1272,7 +1274,7 @@ static int sc16is7xx_probe(struct device + sched_set_fifo(s->kworker_task); + + /* reset device, purging any pending irq / data */ +- regmap_write(s->regmap, SC16IS7XX_IOCONTROL_REG, ++ regmap_write(regmaps[0], SC16IS7XX_IOCONTROL_REG, + SC16IS7XX_IOCONTROL_SRESET_BIT); + + for (i = 0; i < devtype->nr_uart; ++i) { diff --git a/queue-5.15/serial-sc16is7xx-remove-unused-line-structure-member.patch b/queue-5.15/serial-sc16is7xx-remove-unused-line-structure-member.patch new file mode 100644 index 00000000000..68dba99b5b5 --- /dev/null +++ b/queue-5.15/serial-sc16is7xx-remove-unused-line-structure-member.patch @@ -0,0 +1,40 @@ +From 41a308cbedb2a68a6831f0f2e992e296c4b8aff0 Mon Sep 17 00:00:00 2001 +From: Hugo Villeneuve +Date: Mon, 11 Dec 2023 12:13:50 -0500 +Subject: serial: sc16is7xx: remove unused line structure member + +From: Hugo Villeneuve + +commit 41a308cbedb2a68a6831f0f2e992e296c4b8aff0 upstream. + +Now that the driver has been converted to use one regmap per port, the line +structure member is no longer used, so remove it. + +Fixes: 3837a0379533 ("serial: sc16is7xx: improve regmap debugfs by using one regmap per port") +Cc: +Signed-off-by: Hugo Villeneuve +Link: https://lore.kernel.org/r/20231211171353.2901416-4-hugo@hugovil.com +Signed-off-by: Hui Wang +Signed-off-by: Greg Kroah-Hartman +--- + drivers/tty/serial/sc16is7xx.c | 2 -- + 1 file changed, 2 deletions(-) + +--- a/drivers/tty/serial/sc16is7xx.c ++++ b/drivers/tty/serial/sc16is7xx.c +@@ -313,7 +313,6 @@ struct sc16is7xx_one_config { + + struct sc16is7xx_one { + struct uart_port port; +- u8 line; + struct regmap *regmap; + struct kthread_work tx_work; + struct kthread_work reg_work; +@@ -1278,7 +1277,6 @@ static int sc16is7xx_probe(struct device + SC16IS7XX_IOCONTROL_SRESET_BIT); + + for (i = 0; i < devtype->nr_uart; ++i) { +- s->p[i].line = i; + /* Initialize port data */ + s->p[i].port.dev = dev; + s->p[i].port.irq = irq; diff --git a/queue-5.15/serial-sc16is7xx-remove-wasteful-static-buffer-in-sc16is7xx_regmap_name.patch b/queue-5.15/serial-sc16is7xx-remove-wasteful-static-buffer-in-sc16is7xx_regmap_name.patch new file mode 100644 index 00000000000..2cf804dd19e --- /dev/null +++ b/queue-5.15/serial-sc16is7xx-remove-wasteful-static-buffer-in-sc16is7xx_regmap_name.patch @@ -0,0 +1,54 @@ +From 6bcab3c8acc88e265c570dea969fd04f137c8a4c Mon Sep 17 00:00:00 2001 +From: Hugo Villeneuve +Date: Mon, 11 Dec 2023 12:13:48 -0500 +Subject: serial: sc16is7xx: remove wasteful static buffer in sc16is7xx_regmap_name() + +From: Hugo Villeneuve + +commit 6bcab3c8acc88e265c570dea969fd04f137c8a4c upstream. + +Using a static buffer inside sc16is7xx_regmap_name() was a convenient and +simple way to set the regmap name without having to allocate and free a +buffer each time it is called. The drawback is that the static buffer +wastes memory for nothing once regmap is fully initialized. + +Remove static buffer and use constant strings instead. + +This also avoids a truncation warning when using "%d" or "%u" in snprintf +which was flagged by kernel test robot. + +Fixes: 3837a0379533 ("serial: sc16is7xx: improve regmap debugfs by using one regmap per port") +Cc: # 6.1.x: 3837a03 serial: sc16is7xx: improve regmap debugfs by using one regmap per port +Suggested-by: Andy Shevchenko +Signed-off-by: Hugo Villeneuve +Link: https://lore.kernel.org/r/20231211171353.2901416-2-hugo@hugovil.com +Signed-off-by: Hui Wang +Signed-off-by: Greg Kroah-Hartman +--- + drivers/tty/serial/sc16is7xx.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +--- a/drivers/tty/serial/sc16is7xx.c ++++ b/drivers/tty/serial/sc16is7xx.c +@@ -1450,13 +1450,15 @@ static struct regmap_config regcfg = { + .max_register = SC16IS7XX_EFCR_REG, + }; + +-static const char *sc16is7xx_regmap_name(unsigned int port_id) ++static const char *sc16is7xx_regmap_name(u8 port_id) + { +- static char buf[6]; +- +- snprintf(buf, sizeof(buf), "port%d", port_id); +- +- return buf; ++ switch (port_id) { ++ case 0: return "port0"; ++ case 1: return "port1"; ++ default: ++ WARN_ON(true); ++ return NULL; ++ } + } + + static unsigned int sc16is7xx_regmap_port_mask(unsigned int port_id) diff --git a/queue-5.15/series b/queue-5.15/series index 3d06f154f92..afc3d9a732d 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -548,3 +548,18 @@ xhci-dbc-fix-stall-transfer-event-handling.patch mmc-mtk-sd-fix-error-handle-of-probe-function.patch drm-amd-display-check-bios-images-before-it-is-used.patch ocfs2-revert-ocfs2-fix-the-la-space-leak-when-unmounting-an-ocfs2-volume.patch +crypto-hisilicon-qm-inject-error-before-stopping-queue.patch +ima-fix-use-after-free-on-a-dentry-s-dname.name.patch +fou-remove-warn-in-gue_gro_receive-on-unsupported-protocol.patch +revert-drm-amdgpu-add-missing-size-check-in-amdgpu_debugfs_gprwave_read.patch +scsi-core-fix-scsi_mode_select-buffer-length-handling.patch +serial-sc16is7xx-improve-regmap-debugfs-by-using-one-regmap-per-port.patch +serial-sc16is7xx-remove-wasteful-static-buffer-in-sc16is7xx_regmap_name.patch +serial-sc16is7xx-remove-global-regmap-from-struct-sc16is7xx_port.patch +serial-sc16is7xx-remove-unused-line-structure-member.patch +serial-sc16is7xx-change-efr-lock-to-operate-on-each-channels.patch +gve-fixes-for-napi_poll-when-budget-is-0.patch +arm64-sve-discard-stale-cpu-state-when-handling-sve-traps.patch +arm64-smccc-remove-broken-support-for-smcccv1.3-sve-discard-hint.patch +bluetooth-l2cap-fix-uaf-in-l2cap_connect.patch +net-dsa-microchip-correct-ksz8795-static-mac-table-access.patch