From: Greg Kroah-Hartman Date: Sun, 15 Dec 2024 08:30:42 +0000 (+0100) Subject: 6.12-stable patches X-Git-Tag: v5.4.288~67 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=3ff4c858e3033e43b21059c72f6e8a21fea1ba3e;p=thirdparty%2Fkernel%2Fstable-queue.git 6.12-stable patches added patches: ata-sata_highbank-fix-of-node-reference-leak-in-highbank_initialize_phys.patch bpf-revert-bpf-mark-raw_tp-arguments-with-ptr_maybe_null.patch scsi-ufs-core-update-compl_time_stamp_local_clock-after-completing-a-cqe.patch usb-dwc2-fix-hcd-port-connection-race.patch usb-dwc2-fix-hcd-resume.patch usb-dwc2-hcd-fix-getportstatus-setportfeature.patch --- diff --git a/queue-6.12/ata-sata_highbank-fix-of-node-reference-leak-in-highbank_initialize_phys.patch b/queue-6.12/ata-sata_highbank-fix-of-node-reference-leak-in-highbank_initialize_phys.patch new file mode 100644 index 00000000000..fc727385f01 --- /dev/null +++ b/queue-6.12/ata-sata_highbank-fix-of-node-reference-leak-in-highbank_initialize_phys.patch @@ -0,0 +1,30 @@ +From 676fe1f6f74db988191dab5df3bf256908177072 Mon Sep 17 00:00:00 2001 +From: Joe Hattori +Date: Thu, 5 Dec 2024 19:30:14 +0900 +Subject: ata: sata_highbank: fix OF node reference leak in highbank_initialize_phys() + +From: Joe Hattori + +commit 676fe1f6f74db988191dab5df3bf256908177072 upstream. + +The OF node reference obtained by of_parse_phandle_with_args() is not +released on early return. Add a of_node_put() call before returning. + +Fixes: 8996b89d6bc9 ("ata: add platform driver for Calxeda AHCI controller") +Signed-off-by: Joe Hattori +Signed-off-by: Damien Le Moal +Signed-off-by: Greg Kroah-Hartman +--- + drivers/ata/sata_highbank.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/ata/sata_highbank.c ++++ b/drivers/ata/sata_highbank.c +@@ -348,6 +348,7 @@ static int highbank_initialize_phys(stru + phy_nodes[phy] = phy_data.np; + cphy_base[phy] = of_iomap(phy_nodes[phy], 0); + if (cphy_base[phy] == NULL) { ++ of_node_put(phy_data.np); + return 0; + } + phy_count += 1; diff --git a/queue-6.12/bpf-revert-bpf-mark-raw_tp-arguments-with-ptr_maybe_null.patch b/queue-6.12/bpf-revert-bpf-mark-raw_tp-arguments-with-ptr_maybe_null.patch new file mode 100644 index 00000000000..ae493907c0c --- /dev/null +++ b/queue-6.12/bpf-revert-bpf-mark-raw_tp-arguments-with-ptr_maybe_null.patch @@ -0,0 +1,331 @@ +From c00d738e1673ab801e1577e4e3c780ccf88b1a5b Mon Sep 17 00:00:00 2001 +From: Kumar Kartikeya Dwivedi +Date: Fri, 13 Dec 2024 14:19:27 -0800 +Subject: bpf: Revert "bpf: Mark raw_tp arguments with PTR_MAYBE_NULL" + +From: Kumar Kartikeya Dwivedi + +commit c00d738e1673ab801e1577e4e3c780ccf88b1a5b upstream. + +This patch reverts commit +cb4158ce8ec8 ("bpf: Mark raw_tp arguments with PTR_MAYBE_NULL"). The +patch was well-intended and meant to be as a stop-gap fixing branch +prediction when the pointer may actually be NULL at runtime. Eventually, +it was supposed to be replaced by an automated script or compiler pass +detecting possibly NULL arguments and marking them accordingly. + +However, it caused two main issues observed for production programs and +failed to preserve backwards compatibility. First, programs relied on +the verifier not exploring == NULL branch when pointer is not NULL, thus +they started failing with a 'dereference of scalar' error. Next, +allowing raw_tp arguments to be modified surfaced the warning in the +verifier that warns against reg->off when PTR_MAYBE_NULL is set. + +More information, context, and discusson on both problems is available +in [0]. Overall, this approach had several shortcomings, and the fixes +would further complicate the verifier's logic, and the entire masking +scheme would have to be removed eventually anyway. + +Hence, revert the patch in preparation of a better fix avoiding these +issues to replace this commit. + + [0]: https://lore.kernel.org/bpf/20241206161053.809580-1-memxor@gmail.com + +Reported-by: Manu Bretelle +Fixes: cb4158ce8ec8 ("bpf: Mark raw_tp arguments with PTR_MAYBE_NULL") +Signed-off-by: Kumar Kartikeya Dwivedi +Link: https://lore.kernel.org/r/20241213221929.3495062-2-memxor@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/bpf.h | 6 - + kernel/bpf/btf.c | 5 + kernel/bpf/verifier.c | 79 +-------------- + tools/testing/selftests/bpf/progs/test_tp_btf_nullable.c | 6 - + 4 files changed, 9 insertions(+), 87 deletions(-) + +--- a/include/linux/bpf.h ++++ b/include/linux/bpf.h +@@ -3471,10 +3471,4 @@ static inline bool bpf_is_subprog(const + return prog->aux->func_idx != 0; + } + +-static inline bool bpf_prog_is_raw_tp(const struct bpf_prog *prog) +-{ +- return prog->type == BPF_PROG_TYPE_TRACING && +- prog->expected_attach_type == BPF_TRACE_RAW_TP; +-} +- + #endif /* _LINUX_BPF_H */ +--- a/kernel/bpf/btf.c ++++ b/kernel/bpf/btf.c +@@ -6564,10 +6564,7 @@ bool btf_ctx_access(int off, int size, e + if (prog_args_trusted(prog)) + info->reg_type |= PTR_TRUSTED; + +- /* Raw tracepoint arguments always get marked as maybe NULL */ +- if (bpf_prog_is_raw_tp(prog)) +- info->reg_type |= PTR_MAYBE_NULL; +- else if (btf_param_match_suffix(btf, &args[arg], "__nullable")) ++ if (btf_param_match_suffix(btf, &args[arg], "__nullable")) + info->reg_type |= PTR_MAYBE_NULL; + + if (tgt_prog) { +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -418,25 +418,6 @@ static struct btf_record *reg_btf_record + return rec; + } + +-static bool mask_raw_tp_reg_cond(const struct bpf_verifier_env *env, struct bpf_reg_state *reg) { +- return reg->type == (PTR_TO_BTF_ID | PTR_TRUSTED | PTR_MAYBE_NULL) && +- bpf_prog_is_raw_tp(env->prog) && !reg->ref_obj_id; +-} +- +-static bool mask_raw_tp_reg(const struct bpf_verifier_env *env, struct bpf_reg_state *reg) +-{ +- if (!mask_raw_tp_reg_cond(env, reg)) +- return false; +- reg->type &= ~PTR_MAYBE_NULL; +- return true; +-} +- +-static void unmask_raw_tp_reg(struct bpf_reg_state *reg, bool result) +-{ +- if (result) +- reg->type |= PTR_MAYBE_NULL; +-} +- + static bool subprog_is_global(const struct bpf_verifier_env *env, int subprog) + { + struct bpf_func_info_aux *aux = env->prog->aux->func_info_aux; +@@ -6618,7 +6599,6 @@ static int check_ptr_to_btf_access(struc + const char *field_name = NULL; + enum bpf_type_flag flag = 0; + u32 btf_id = 0; +- bool mask; + int ret; + + if (!env->allow_ptr_leaks) { +@@ -6690,21 +6670,7 @@ static int check_ptr_to_btf_access(struc + + if (ret < 0) + return ret; +- /* For raw_tp progs, we allow dereference of PTR_MAYBE_NULL +- * trusted PTR_TO_BTF_ID, these are the ones that are possibly +- * arguments to the raw_tp. Since internal checks in for trusted +- * reg in check_ptr_to_btf_access would consider PTR_MAYBE_NULL +- * modifier as problematic, mask it out temporarily for the +- * check. Don't apply this to pointers with ref_obj_id > 0, as +- * those won't be raw_tp args. +- * +- * We may end up applying this relaxation to other trusted +- * PTR_TO_BTF_ID with maybe null flag, since we cannot +- * distinguish PTR_MAYBE_NULL tagged for arguments vs normal +- * tagging, but that should expand allowed behavior, and not +- * cause regression for existing behavior. +- */ +- mask = mask_raw_tp_reg(env, reg); ++ + if (ret != PTR_TO_BTF_ID) { + /* just mark; */ + +@@ -6765,13 +6731,8 @@ static int check_ptr_to_btf_access(struc + clear_trusted_flags(&flag); + } + +- if (atype == BPF_READ && value_regno >= 0) { ++ if (atype == BPF_READ && value_regno >= 0) + mark_btf_ld_reg(env, regs, value_regno, ret, reg->btf, btf_id, flag); +- /* We've assigned a new type to regno, so don't undo masking. */ +- if (regno == value_regno) +- mask = false; +- } +- unmask_raw_tp_reg(reg, mask); + + return 0; + } +@@ -7146,7 +7107,7 @@ static int check_mem_access(struct bpf_v + if (!err && t == BPF_READ && value_regno >= 0) + mark_reg_unknown(env, regs, value_regno); + } else if (base_type(reg->type) == PTR_TO_BTF_ID && +- (mask_raw_tp_reg_cond(env, reg) || !type_may_be_null(reg->type))) { ++ !type_may_be_null(reg->type)) { + err = check_ptr_to_btf_access(env, regs, regno, off, size, t, + value_regno); + } else if (reg->type == CONST_PTR_TO_MAP) { +@@ -8844,7 +8805,6 @@ static int check_func_arg(struct bpf_ver + enum bpf_reg_type type = reg->type; + u32 *arg_btf_id = NULL; + int err = 0; +- bool mask; + + if (arg_type == ARG_DONTCARE) + return 0; +@@ -8885,11 +8845,11 @@ static int check_func_arg(struct bpf_ver + base_type(arg_type) == ARG_PTR_TO_SPIN_LOCK) + arg_btf_id = fn->arg_btf_id[arg]; + +- mask = mask_raw_tp_reg(env, reg); + err = check_reg_type(env, regno, arg_type, arg_btf_id, meta); ++ if (err) ++ return err; + +- err = err ?: check_func_arg_reg_off(env, reg, regno, arg_type); +- unmask_raw_tp_reg(reg, mask); ++ err = check_func_arg_reg_off(env, reg, regno, arg_type); + if (err) + return err; + +@@ -9684,17 +9644,14 @@ static int btf_check_func_arg_match(stru + return ret; + } else if (base_type(arg->arg_type) == ARG_PTR_TO_BTF_ID) { + struct bpf_call_arg_meta meta; +- bool mask; + int err; + + if (register_is_null(reg) && type_may_be_null(arg->arg_type)) + continue; + + memset(&meta, 0, sizeof(meta)); /* leave func_id as zero */ +- mask = mask_raw_tp_reg(env, reg); + err = check_reg_type(env, regno, arg->arg_type, &arg->btf_id, &meta); + err = err ?: check_func_arg_reg_off(env, reg, regno, arg->arg_type); +- unmask_raw_tp_reg(reg, mask); + if (err) + return err; + } else { +@@ -12009,7 +11966,6 @@ static int check_kfunc_args(struct bpf_v + enum bpf_arg_type arg_type = ARG_DONTCARE; + u32 regno = i + 1, ref_id, type_size; + bool is_ret_buf_sz = false; +- bool mask = false; + int kf_arg_type; + + t = btf_type_skip_modifiers(btf, args[i].type, NULL); +@@ -12068,15 +12024,12 @@ static int check_kfunc_args(struct bpf_v + return -EINVAL; + } + +- mask = mask_raw_tp_reg(env, reg); + if ((is_kfunc_trusted_args(meta) || is_kfunc_rcu(meta)) && + (register_is_null(reg) || type_may_be_null(reg->type)) && + !is_kfunc_arg_nullable(meta->btf, &args[i])) { + verbose(env, "Possibly NULL pointer passed to trusted arg%d\n", i); +- unmask_raw_tp_reg(reg, mask); + return -EACCES; + } +- unmask_raw_tp_reg(reg, mask); + + if (reg->ref_obj_id) { + if (is_kfunc_release(meta) && meta->ref_obj_id) { +@@ -12134,24 +12087,16 @@ static int check_kfunc_args(struct bpf_v + if (!is_kfunc_trusted_args(meta) && !is_kfunc_rcu(meta)) + break; + +- /* Allow passing maybe NULL raw_tp arguments to +- * kfuncs for compatibility. Don't apply this to +- * arguments with ref_obj_id > 0. +- */ +- mask = mask_raw_tp_reg(env, reg); + if (!is_trusted_reg(reg)) { + if (!is_kfunc_rcu(meta)) { + verbose(env, "R%d must be referenced or trusted\n", regno); +- unmask_raw_tp_reg(reg, mask); + return -EINVAL; + } + if (!is_rcu_reg(reg)) { + verbose(env, "R%d must be a rcu pointer\n", regno); +- unmask_raw_tp_reg(reg, mask); + return -EINVAL; + } + } +- unmask_raw_tp_reg(reg, mask); + fallthrough; + case KF_ARG_PTR_TO_CTX: + case KF_ARG_PTR_TO_DYNPTR: +@@ -12174,9 +12119,7 @@ static int check_kfunc_args(struct bpf_v + + if (is_kfunc_release(meta) && reg->ref_obj_id) + arg_type |= OBJ_RELEASE; +- mask = mask_raw_tp_reg(env, reg); + ret = check_func_arg_reg_off(env, reg, regno, arg_type); +- unmask_raw_tp_reg(reg, mask); + if (ret < 0) + return ret; + +@@ -12353,7 +12296,6 @@ static int check_kfunc_args(struct bpf_v + ref_tname = btf_name_by_offset(btf, ref_t->name_off); + fallthrough; + case KF_ARG_PTR_TO_BTF_ID: +- mask = mask_raw_tp_reg(env, reg); + /* Only base_type is checked, further checks are done here */ + if ((base_type(reg->type) != PTR_TO_BTF_ID || + (bpf_type_has_unsafe_modifiers(reg->type) && !is_rcu_reg(reg))) && +@@ -12362,11 +12304,9 @@ static int check_kfunc_args(struct bpf_v + verbose(env, "expected %s or socket\n", + reg_type_str(env, base_type(reg->type) | + (type_flag(reg->type) & BPF_REG_TRUSTED_MODIFIERS))); +- unmask_raw_tp_reg(reg, mask); + return -EINVAL; + } + ret = process_kf_arg_ptr_to_btf_id(env, reg, ref_t, ref_tname, ref_id, meta, i); +- unmask_raw_tp_reg(reg, mask); + if (ret < 0) + return ret; + break; +@@ -13336,7 +13276,7 @@ static int sanitize_check_bounds(struct + */ + static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, + struct bpf_insn *insn, +- struct bpf_reg_state *ptr_reg, ++ const struct bpf_reg_state *ptr_reg, + const struct bpf_reg_state *off_reg) + { + struct bpf_verifier_state *vstate = env->cur_state; +@@ -13350,7 +13290,6 @@ static int adjust_ptr_min_max_vals(struc + struct bpf_sanitize_info info = {}; + u8 opcode = BPF_OP(insn->code); + u32 dst = insn->dst_reg; +- bool mask; + int ret; + + dst_reg = ®s[dst]; +@@ -13377,14 +13316,11 @@ static int adjust_ptr_min_max_vals(struc + return -EACCES; + } + +- mask = mask_raw_tp_reg(env, ptr_reg); + if (ptr_reg->type & PTR_MAYBE_NULL) { + verbose(env, "R%d pointer arithmetic on %s prohibited, null-check it first\n", + dst, reg_type_str(env, ptr_reg->type)); +- unmask_raw_tp_reg(ptr_reg, mask); + return -EACCES; + } +- unmask_raw_tp_reg(ptr_reg, mask); + + switch (base_type(ptr_reg->type)) { + case PTR_TO_CTX: +@@ -19934,7 +19870,6 @@ static int convert_ctx_accesses(struct b + * for this case. + */ + case PTR_TO_BTF_ID | MEM_ALLOC | PTR_UNTRUSTED: +- case PTR_TO_BTF_ID | PTR_TRUSTED | PTR_MAYBE_NULL: + if (type == BPF_READ) { + if (BPF_MODE(insn->code) == BPF_MEM) + insn->code = BPF_LDX | BPF_PROBE_MEM | +--- a/tools/testing/selftests/bpf/progs/test_tp_btf_nullable.c ++++ b/tools/testing/selftests/bpf/progs/test_tp_btf_nullable.c +@@ -7,11 +7,7 @@ + #include "bpf_misc.h" + + SEC("tp_btf/bpf_testmod_test_nullable_bare") +-/* This used to be a failure test, but raw_tp nullable arguments can now +- * directly be dereferenced, whether they have nullable annotation or not, +- * and don't need to be explicitly checked. +- */ +-__success ++__failure __msg("R1 invalid mem access 'trusted_ptr_or_null_'") + int BPF_PROG(handle_tp_btf_nullable_bare1, struct bpf_testmod_test_read_ctx *nullable_ctx) + { + return nullable_ctx->len; diff --git a/queue-6.12/scsi-ufs-core-update-compl_time_stamp_local_clock-after-completing-a-cqe.patch b/queue-6.12/scsi-ufs-core-update-compl_time_stamp_local_clock-after-completing-a-cqe.patch new file mode 100644 index 00000000000..e1a2fc93d5f --- /dev/null +++ b/queue-6.12/scsi-ufs-core-update-compl_time_stamp_local_clock-after-completing-a-cqe.patch @@ -0,0 +1,42 @@ +From f103396ae31851d00b561ff9f8a32a441953ff8b Mon Sep 17 00:00:00 2001 +From: liuderong +Date: Fri, 6 Dec 2024 15:29:42 +0800 +Subject: scsi: ufs: core: Update compl_time_stamp_local_clock after completing a cqe + +From: liuderong + +commit f103396ae31851d00b561ff9f8a32a441953ff8b upstream. + +lrbp->compl_time_stamp_local_clock is set to zero after sending a sqe +but it is not updated after completing a cqe. Thus the printed +information in ufshcd_print_tr() will always be zero. + +Update lrbp->cmpl_time_stamp_local_clock after completing a cqe. + +Log sample: + +ufshcd-qcom 1d84000.ufshc: UPIU[8] - issue time 8750227249 us +ufshcd-qcom 1d84000.ufshc: UPIU[8] - complete time 0 us + +Fixes: c30d8d010b5e ("scsi: ufs: core: Prepare for completion in MCQ") +Reviewed-by: Bean Huo +Reviewed-by: Peter Wang +Signed-off-by: liuderong +Link: https://lore.kernel.org/r/1733470182-220841-1-git-send-email-liuderong@oppo.com +Reviewed-by: Avri Altman +Signed-off-by: Martin K. Petersen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/ufs/core/ufshcd.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/ufs/core/ufshcd.c ++++ b/drivers/ufs/core/ufshcd.c +@@ -5566,6 +5566,7 @@ void ufshcd_compl_one_cqe(struct ufs_hba + + lrbp = &hba->lrb[task_tag]; + lrbp->compl_time_stamp = ktime_get(); ++ lrbp->compl_time_stamp_local_clock = local_clock(); + cmd = lrbp->cmd; + if (cmd) { + if (unlikely(ufshcd_should_inform_monitor(hba, lrbp))) diff --git a/queue-6.12/series b/queue-6.12/series index 1671f9c33d6..930df99310c 100644 --- a/queue-6.12/series +++ b/queue-6.12/series @@ -36,3 +36,9 @@ gpio-graniterapids-fix-invalid-rxevcfg-register-bitmask.patch gpio-graniterapids-determine-if-gpio-pad-can-be-used-by-driver.patch gpio-graniterapids-check-if-gpio-line-can-be-used-for-irqs.patch usb-core-hcd-only-check-primary-hcd-skip_phy_initialization.patch +bpf-revert-bpf-mark-raw_tp-arguments-with-ptr_maybe_null.patch +ata-sata_highbank-fix-of-node-reference-leak-in-highbank_initialize_phys.patch +usb-dwc2-fix-hcd-resume.patch +usb-dwc2-hcd-fix-getportstatus-setportfeature.patch +usb-dwc2-fix-hcd-port-connection-race.patch +scsi-ufs-core-update-compl_time_stamp_local_clock-after-completing-a-cqe.patch diff --git a/queue-6.12/usb-dwc2-fix-hcd-port-connection-race.patch b/queue-6.12/usb-dwc2-fix-hcd-port-connection-race.patch new file mode 100644 index 00000000000..c01e9e28c70 --- /dev/null +++ b/queue-6.12/usb-dwc2-fix-hcd-port-connection-race.patch @@ -0,0 +1,68 @@ +From 1cf1bd88f129f3bd647fead4dca270a5894274bb Mon Sep 17 00:00:00 2001 +From: Stefan Wahren +Date: Mon, 2 Dec 2024 01:16:31 +0100 +Subject: usb: dwc2: Fix HCD port connection race + +From: Stefan Wahren + +commit 1cf1bd88f129f3bd647fead4dca270a5894274bb upstream. + +On Raspberry Pis without onboard USB hub frequent device reconnects +can trigger a interrupt storm after DWC2 entered host clock gating. +This is caused by a race between _dwc2_hcd_suspend() and the port +interrupt, which sets port_connect_status. The issue occurs if +port_connect_status is still 1, but there is no connection anymore: + +usb 1-1: USB disconnect, device number 25 +dwc2 3f980000.usb: _dwc2_hcd_suspend: port_connect_status: 1 +dwc2 3f980000.usb: Entering host clock gating. +Disabling IRQ #66 +irq 66: nobody cared (try booting with the "irqpoll" option) +CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Not tainted 6.12.0-gc1bb81b13202-dirty #322 +Hardware name: BCM2835 +Call trace: + unwind_backtrace from show_stack+0x10/0x14 + show_stack from dump_stack_lvl+0x50/0x64 + dump_stack_lvl from __report_bad_irq+0x38/0xc0 + __report_bad_irq from note_interrupt+0x2ac/0x2f4 + note_interrupt from handle_irq_event+0x88/0x8c + handle_irq_event from handle_level_irq+0xb4/0x1ac + handle_level_irq from generic_handle_domain_irq+0x24/0x34 + generic_handle_domain_irq from bcm2836_chained_handle_irq+0x24/0x28 + bcm2836_chained_handle_irq from generic_handle_domain_irq+0x24/0x34 + generic_handle_domain_irq from generic_handle_arch_irq+0x34/0x44 + generic_handle_arch_irq from __irq_svc+0x88/0xb0 + Exception stack(0xc1d01f20 to 0xc1d01f68) + 1f20: 0004ef3c 00000001 00000000 00000000 c1d09780 c1f6bb5c c1d04e54 c1c60ca8 + 1f40: c1d04e94 00000000 00000000 c1d092a8 c1f6af20 c1d01f70 c1211b98 c1212f40 + 1f60: 60000013 ffffffff + __irq_svc from default_idle_call+0x1c/0xb0 + default_idle_call from do_idle+0x21c/0x284 + do_idle from cpu_startup_entry+0x28/0x2c + cpu_startup_entry from kernel_init+0x0/0x12c +handlers: + [] dwc2_handle_common_intr + [<58bf98a3>] usb_hcd_irq +Disabling IRQ #66 + +So avoid this by reading the connection status directly. + +Fixes: 113f86d0c302 ("usb: dwc2: Update partial power down entering by system suspend") +Signed-off-by: Stefan Wahren +Link: https://lore.kernel.org/r/20241202001631.75473-4-wahrenst@gmx.net +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/dwc2/hcd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/usb/dwc2/hcd.c ++++ b/drivers/usb/dwc2/hcd.c +@@ -4345,7 +4345,7 @@ static int _dwc2_hcd_suspend(struct usb_ + if (hsotg->bus_suspended) + goto skip_power_saving; + +- if (hsotg->flags.b.port_connect_status == 0) ++ if (!(dwc2_read_hprt0(hsotg) & HPRT0_CONNSTS)) + goto skip_power_saving; + + switch (hsotg->params.power_down) { diff --git a/queue-6.12/usb-dwc2-fix-hcd-resume.patch b/queue-6.12/usb-dwc2-fix-hcd-resume.patch new file mode 100644 index 00000000000..09d6c69f414 --- /dev/null +++ b/queue-6.12/usb-dwc2-fix-hcd-resume.patch @@ -0,0 +1,71 @@ +From 336f72d3cbf5cc17df2947bbbd2ba6e2509f17e8 Mon Sep 17 00:00:00 2001 +From: Stefan Wahren +Date: Mon, 2 Dec 2024 01:16:29 +0100 +Subject: usb: dwc2: Fix HCD resume + +From: Stefan Wahren + +commit 336f72d3cbf5cc17df2947bbbd2ba6e2509f17e8 upstream. + +The Raspberry Pi can suffer on interrupt storms on HCD resume. The dwc2 +driver sometimes misses to enable HCD_FLAG_HW_ACCESSIBLE before re-enabling +the interrupts. This causes a situation where both handler ignore a incoming +port interrupt and force the upper layers to disable the dwc2 interrupt +line. This leaves the USB interface in a unusable state: + +irq 66: nobody cared (try booting with the "irqpoll" option) +CPU: 0 PID: 0 Comm: swapper/0 Tainted: G W 6.10.0-rc3 +Hardware name: BCM2835 +Call trace: +unwind_backtrace from show_stack+0x10/0x14 +show_stack from dump_stack_lvl+0x50/0x64 +dump_stack_lvl from __report_bad_irq+0x38/0xc0 +__report_bad_irq from note_interrupt+0x2ac/0x2f4 +note_interrupt from handle_irq_event+0x88/0x8c +handle_irq_event from handle_level_irq+0xb4/0x1ac +handle_level_irq from generic_handle_domain_irq+0x24/0x34 +generic_handle_domain_irq from bcm2836_chained_handle_irq+0x24/0x28 +bcm2836_chained_handle_irq from generic_handle_domain_irq+0x24/0x34 +generic_handle_domain_irq from generic_handle_arch_irq+0x34/0x44 +generic_handle_arch_irq from __irq_svc+0x88/0xb0 +Exception stack(0xc1b01f20 to 0xc1b01f68) +1f20: 0005c0d4 00000001 00000000 00000000 c1b09780 c1d6b32c c1b04e54 c1a5eae8 +1f40: c1b04e90 00000000 00000000 00000000 c1d6a8a0 c1b01f70 c11d2da8 c11d4160 +1f60: 60000013 ffffffff +__irq_svc from default_idle_call+0x1c/0xb0 +default_idle_call from do_idle+0x21c/0x284 +do_idle from cpu_startup_entry+0x28/0x2c +cpu_startup_entry from kernel_init+0x0/0x12c +handlers: +[] dwc2_handle_common_intr +[<75cd278b>] usb_hcd_irq +Disabling IRQ #66 + +So enable the HCD_FLAG_HW_ACCESSIBLE flag in case there is a port +connection. + +Fixes: c74c26f6e398 ("usb: dwc2: Fix partial power down exiting by system resume") +Closes: https://lore.kernel.org/linux-usb/3fd0c2fb-4752-45b3-94eb-42352703e1fd@gmx.net/T/ +Link: https://lore.kernel.org/all/5e8cbce0-3260-2971-484f-fc73a3b2bd28@synopsys.com/ +Signed-off-by: Stefan Wahren +Link: https://lore.kernel.org/r/20241202001631.75473-2-wahrenst@gmx.net +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/dwc2/hcd.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c +index cb54390e7de4..26a320c1979a 100644 +--- a/drivers/usb/dwc2/hcd.c ++++ b/drivers/usb/dwc2/hcd.c +@@ -4431,6 +4431,7 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd) + * Power Down mode. + */ + if (hprt0 & HPRT0_CONNSTS) { ++ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + hsotg->lx_state = DWC2_L0; + goto unlock; + } +-- +2.47.1 + diff --git a/queue-6.12/usb-dwc2-hcd-fix-getportstatus-setportfeature.patch b/queue-6.12/usb-dwc2-hcd-fix-getportstatus-setportfeature.patch new file mode 100644 index 00000000000..bcd1ed5c838 --- /dev/null +++ b/queue-6.12/usb-dwc2-hcd-fix-getportstatus-setportfeature.patch @@ -0,0 +1,66 @@ +From a8d3e4a734599c7d0f6735f8db8a812e503395dd Mon Sep 17 00:00:00 2001 +From: Stefan Wahren +Date: Mon, 2 Dec 2024 01:16:30 +0100 +Subject: usb: dwc2: hcd: Fix GetPortStatus & SetPortFeature + +From: Stefan Wahren + +commit a8d3e4a734599c7d0f6735f8db8a812e503395dd upstream. + +On Rasperry Pis without onboard USB hub the power cycle during +power connect init only disable the port but never enabled it again: + + usb usb1-port1: attempt power cycle + +The port relevant part in dwc2_hcd_hub_control() is skipped in case +port_connect_status = 0 under the assumption the core is or will be soon +in device mode. But this assumption is wrong, because after ClearPortFeature +USB_PORT_FEAT_POWER the port_connect_status will also be 0 and +SetPortFeature (incl. USB_PORT_FEAT_POWER) will be a no-op. + +Fix the behavior of dwc2_hcd_hub_control() by replacing the +port_connect_status check with dwc2_is_device_mode(). + +Link: https://github.com/raspberrypi/linux/issues/6247 +Fixes: 7359d482eb4d ("staging: HCD files for the DWC2 driver") +Signed-off-by: Stefan Wahren +Link: https://lore.kernel.org/r/20241202001631.75473-3-wahrenst@gmx.net +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/dwc2/hcd.c | 16 ++++++---------- + 1 file changed, 6 insertions(+), 10 deletions(-) + +--- a/drivers/usb/dwc2/hcd.c ++++ b/drivers/usb/dwc2/hcd.c +@@ -3546,11 +3546,9 @@ static int dwc2_hcd_hub_control(struct d + port_status |= USB_PORT_STAT_C_OVERCURRENT << 16; + } + +- if (!hsotg->flags.b.port_connect_status) { ++ if (dwc2_is_device_mode(hsotg)) { + /* +- * The port is disconnected, which means the core is +- * either in device mode or it soon will be. Just +- * return 0's for the remainder of the port status ++ * Just return 0's for the remainder of the port status + * since the port register can't be read if the core + * is in device mode. + */ +@@ -3620,13 +3618,11 @@ static int dwc2_hcd_hub_control(struct d + if (wvalue != USB_PORT_FEAT_TEST && (!windex || windex > 1)) + goto error; + +- if (!hsotg->flags.b.port_connect_status) { ++ if (dwc2_is_device_mode(hsotg)) { + /* +- * The port is disconnected, which means the core is +- * either in device mode or it soon will be. Just +- * return without doing anything since the port +- * register can't be written if the core is in device +- * mode. ++ * Just return 0's for the remainder of the port status ++ * since the port register can't be read if the core ++ * is in device mode. + */ + break; + }