From: Greg Kroah-Hartman Date: Mon, 1 Apr 2024 10:18:59 +0000 (+0200) Subject: 6.8-stable patches X-Git-Tag: v6.7.12~60 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2dbb04ba729f96723083a9e6b9d529a20959738b;p=thirdparty%2Fkernel%2Fstable-queue.git 6.8-stable patches added patches: usb-dwc2-gadget-fix-exiting-from-clock-gating.patch usb-dwc2-gadget-lpm-flow-fix.patch usb-dwc2-host-fix-hibernation-flow.patch usb-dwc2-host-fix-isoc-flow-in-ddma-mode.patch usb-dwc2-host-fix-remote-wakeup-from-hibernation.patch usb-typec-return-size-of-buffer-if-pd_set-operation-succeeds.patch usb-typec-tcpm-correct-port-source-pdo-array-in-pd_set-callback.patch usb-typec-tcpm-fix-double-free-issue-in-tcpm_port_unregister_pd.patch usb-typec-tcpm-update-pd-of-type-c-port-upon-pd_set.patch usb-typec-ucsi-ack-unsupported-commands.patch usb-typec-ucsi-check-for-notifications-after-init.patch usb-typec-ucsi-clear-event_pending-under-ppm-lock.patch usb-typec-ucsi-clear-ucsi_cci_reset_complete-before-reset.patch usb-typec-ucsi-fix-race-between-typec_switch-and-role_switch.patch usb-typec-ucsi_acpi-refactor-and-fix-dell-quirk.patch usb-udc-remove-warning-when-queue-disabled-ep.patch --- diff --git a/queue-6.8/series b/queue-6.8/series index 56559cd5532..241dce0dc1b 100644 --- a/queue-6.8/series +++ b/queue-6.8/series @@ -358,3 +358,19 @@ usb-dwc3-properly-set-system-wakeup.patch usb-core-fix-deadlock-in-usb_deauthorize_interface.patch usb-core-add-hub_get-and-hub_put-routines.patch usb-core-fix-deadlock-in-port-disable-sysfs-attribute.patch +usb-dwc2-host-fix-remote-wakeup-from-hibernation.patch +usb-dwc2-host-fix-hibernation-flow.patch +usb-dwc2-host-fix-isoc-flow-in-ddma-mode.patch +usb-dwc2-gadget-fix-exiting-from-clock-gating.patch +usb-dwc2-gadget-lpm-flow-fix.patch +usb-udc-remove-warning-when-queue-disabled-ep.patch +usb-typec-ucsi-fix-race-between-typec_switch-and-role_switch.patch +usb-typec-tcpm-fix-double-free-issue-in-tcpm_port_unregister_pd.patch +usb-typec-tcpm-correct-port-source-pdo-array-in-pd_set-callback.patch +usb-typec-tcpm-update-pd-of-type-c-port-upon-pd_set.patch +usb-typec-return-size-of-buffer-if-pd_set-operation-succeeds.patch +usb-typec-ucsi-clear-event_pending-under-ppm-lock.patch +usb-typec-ucsi-check-for-notifications-after-init.patch +usb-typec-ucsi-ack-unsupported-commands.patch +usb-typec-ucsi_acpi-refactor-and-fix-dell-quirk.patch +usb-typec-ucsi-clear-ucsi_cci_reset_complete-before-reset.patch diff --git a/queue-6.8/usb-dwc2-gadget-fix-exiting-from-clock-gating.patch b/queue-6.8/usb-dwc2-gadget-fix-exiting-from-clock-gating.patch new file mode 100644 index 00000000000..d0762b30c0b --- /dev/null +++ b/queue-6.8/usb-dwc2-gadget-fix-exiting-from-clock-gating.patch @@ -0,0 +1,97 @@ +From 31f42da31417bec88158f3cf62d19db836217f1e Mon Sep 17 00:00:00 2001 +From: Minas Harutyunyan +Date: Wed, 13 Mar 2024 09:22:01 +0000 +Subject: usb: dwc2: gadget: Fix exiting from clock gating + +From: Minas Harutyunyan + +commit 31f42da31417bec88158f3cf62d19db836217f1e upstream. + +Added exiting from the clock gating mode on USB Reset Detect interrupt +if core in the clock gating mode. +Added new condition to check core in clock gating mode or no. + +Fixes: 9b4965d77e11 ("usb: dwc2: Add exit clock gating from session request interrupt") +Fixes: 5d240efddc7f ("usb: dwc2: Add exit clock gating from wakeup interrupt") +Fixes: 16c729f90bdf ("usb: dwc2: Allow exit clock gating in urb enqueue") +Fixes: 401411bbc4e6 ("usb: dwc2: Add exit clock gating before removing driver") +CC: stable@vger.kernel.org +Signed-off-by: Minas Harutyunyan +Link: https://lore.kernel.org/r/cbcc2ccd37e89e339130797ed68ae4597db773ac.1708938774.git.Minas.Harutyunyan@synopsys.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/dwc2/core_intr.c | 9 ++++++--- + drivers/usb/dwc2/gadget.c | 6 ++++++ + drivers/usb/dwc2/hcd.c | 2 +- + drivers/usb/dwc2/platform.c | 2 +- + 4 files changed, 14 insertions(+), 5 deletions(-) + +--- a/drivers/usb/dwc2/core_intr.c ++++ b/drivers/usb/dwc2/core_intr.c +@@ -297,7 +297,8 @@ static void dwc2_handle_session_req_intr + + /* Exit gadget mode clock gating. */ + if (hsotg->params.power_down == +- DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended) ++ DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended && ++ !hsotg->params.no_clock_gating) + dwc2_gadget_exit_clock_gating(hsotg, 0); + } + +@@ -408,7 +409,8 @@ static void dwc2_handle_wakeup_detected_ + + /* Exit gadget mode clock gating. */ + if (hsotg->params.power_down == +- DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended) ++ DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended && ++ !hsotg->params.no_clock_gating) + dwc2_gadget_exit_clock_gating(hsotg, 0); + } else { + /* Change to L0 state */ +@@ -425,7 +427,8 @@ static void dwc2_handle_wakeup_detected_ + } + + if (hsotg->params.power_down == +- DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended) ++ DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended && ++ !hsotg->params.no_clock_gating) + dwc2_host_exit_clock_gating(hsotg, 1); + + /* +--- a/drivers/usb/dwc2/gadget.c ++++ b/drivers/usb/dwc2/gadget.c +@@ -3727,6 +3727,12 @@ irq_retry: + if (hsotg->in_ppd && hsotg->lx_state == DWC2_L2) + dwc2_exit_partial_power_down(hsotg, 0, true); + ++ /* Exit gadget mode clock gating. */ ++ if (hsotg->params.power_down == ++ DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended && ++ !hsotg->params.no_clock_gating) ++ dwc2_gadget_exit_clock_gating(hsotg, 0); ++ + hsotg->lx_state = DWC2_L0; + } + +--- a/drivers/usb/dwc2/hcd.c ++++ b/drivers/usb/dwc2/hcd.c +@@ -4657,7 +4657,7 @@ static int _dwc2_hcd_urb_enqueue(struct + } + + if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_NONE && +- hsotg->bus_suspended) { ++ hsotg->bus_suspended && !hsotg->params.no_clock_gating) { + if (dwc2_is_device_mode(hsotg)) + dwc2_gadget_exit_clock_gating(hsotg, 0); + else +--- a/drivers/usb/dwc2/platform.c ++++ b/drivers/usb/dwc2/platform.c +@@ -331,7 +331,7 @@ static void dwc2_driver_remove(struct pl + + /* Exit clock gating when driver is removed. */ + if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_NONE && +- hsotg->bus_suspended) { ++ hsotg->bus_suspended && !hsotg->params.no_clock_gating) { + if (dwc2_is_device_mode(hsotg)) + dwc2_gadget_exit_clock_gating(hsotg, 0); + else diff --git a/queue-6.8/usb-dwc2-gadget-lpm-flow-fix.patch b/queue-6.8/usb-dwc2-gadget-lpm-flow-fix.patch new file mode 100644 index 00000000000..140619d3720 --- /dev/null +++ b/queue-6.8/usb-dwc2-gadget-lpm-flow-fix.patch @@ -0,0 +1,150 @@ +From 5d69a3b54e5a630c90d82a4c2bdce3d53dc78710 Mon Sep 17 00:00:00 2001 +From: Minas Harutyunyan +Date: Wed, 13 Mar 2024 09:22:13 +0000 +Subject: usb: dwc2: gadget: LPM flow fix + +From: Minas Harutyunyan + +commit 5d69a3b54e5a630c90d82a4c2bdce3d53dc78710 upstream. + +Added functionality to exit from L1 state by device initiation +using remote wakeup signaling, in case when function driver queuing +request while core in L1 state. + +Fixes: 273d576c4d41 ("usb: dwc2: gadget: Add functionality to exit from LPM L1 state") +Fixes: 88b02f2cb1e1 ("usb: dwc2: Add core state checking") +CC: stable@vger.kernel.org +Signed-off-by: Minas Harutyunyan +Link: https://lore.kernel.org/r/b4d9de5382375dddbf7ef6049d9a82066ad87d5d.1710166393.git.Minas.Harutyunyan@synopsys.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/dwc2/core.h | 1 + drivers/usb/dwc2/core_intr.c | 65 ++++++++++++++++++++++++++++--------------- + drivers/usb/dwc2/gadget.c | 4 ++ + 3 files changed, 48 insertions(+), 22 deletions(-) + +--- a/drivers/usb/dwc2/core.h ++++ b/drivers/usb/dwc2/core.h +@@ -1336,6 +1336,7 @@ int dwc2_backup_global_registers(struct + int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg); + + void dwc2_enable_acg(struct dwc2_hsotg *hsotg); ++void dwc2_wakeup_from_lpm_l1(struct dwc2_hsotg *hsotg, bool remotewakeup); + + /* This function should be called on every hardware interrupt. */ + irqreturn_t dwc2_handle_common_intr(int irq, void *dev); +--- a/drivers/usb/dwc2/core_intr.c ++++ b/drivers/usb/dwc2/core_intr.c +@@ -323,10 +323,11 @@ static void dwc2_handle_session_req_intr + * @hsotg: Programming view of DWC_otg controller + * + */ +-static void dwc2_wakeup_from_lpm_l1(struct dwc2_hsotg *hsotg) ++void dwc2_wakeup_from_lpm_l1(struct dwc2_hsotg *hsotg, bool remotewakeup) + { + u32 glpmcfg; +- u32 i = 0; ++ u32 pcgctl; ++ u32 dctl; + + if (hsotg->lx_state != DWC2_L1) { + dev_err(hsotg->dev, "Core isn't in DWC2_L1 state\n"); +@@ -335,37 +336,57 @@ static void dwc2_wakeup_from_lpm_l1(stru + + glpmcfg = dwc2_readl(hsotg, GLPMCFG); + if (dwc2_is_device_mode(hsotg)) { +- dev_dbg(hsotg->dev, "Exit from L1 state\n"); ++ dev_dbg(hsotg->dev, "Exit from L1 state, remotewakeup=%d\n", remotewakeup); + glpmcfg &= ~GLPMCFG_ENBLSLPM; +- glpmcfg &= ~GLPMCFG_HIRD_THRES_EN; ++ glpmcfg &= ~GLPMCFG_HIRD_THRES_MASK; + dwc2_writel(hsotg, glpmcfg, GLPMCFG); + +- do { +- glpmcfg = dwc2_readl(hsotg, GLPMCFG); +- +- if (!(glpmcfg & (GLPMCFG_COREL1RES_MASK | +- GLPMCFG_L1RESUMEOK | GLPMCFG_SLPSTS))) +- break; ++ pcgctl = dwc2_readl(hsotg, PCGCTL); ++ pcgctl &= ~PCGCTL_ENBL_SLEEP_GATING; ++ dwc2_writel(hsotg, pcgctl, PCGCTL); ++ ++ glpmcfg = dwc2_readl(hsotg, GLPMCFG); ++ if (glpmcfg & GLPMCFG_ENBESL) { ++ glpmcfg |= GLPMCFG_RSTRSLPSTS; ++ dwc2_writel(hsotg, glpmcfg, GLPMCFG); ++ } + +- udelay(1); +- } while (++i < 200); ++ if (remotewakeup) { ++ if (dwc2_hsotg_wait_bit_set(hsotg, GLPMCFG, GLPMCFG_L1RESUMEOK, 1000)) { ++ dev_warn(hsotg->dev, "%s: timeout GLPMCFG_L1RESUMEOK\n", __func__); ++ goto fail; ++ return; ++ } ++ ++ dctl = dwc2_readl(hsotg, DCTL); ++ dctl |= DCTL_RMTWKUPSIG; ++ dwc2_writel(hsotg, dctl, DCTL); ++ ++ if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS, GINTSTS_WKUPINT, 1000)) { ++ dev_warn(hsotg->dev, "%s: timeout GINTSTS_WKUPINT\n", __func__); ++ goto fail; ++ return; ++ } ++ } + +- if (i == 200) { +- dev_err(hsotg->dev, "Failed to exit L1 sleep state in 200us.\n"); ++ glpmcfg = dwc2_readl(hsotg, GLPMCFG); ++ if (glpmcfg & GLPMCFG_COREL1RES_MASK || glpmcfg & GLPMCFG_SLPSTS || ++ glpmcfg & GLPMCFG_L1RESUMEOK) { ++ goto fail; + return; + } +- dwc2_gadget_init_lpm(hsotg); ++ ++ /* Inform gadget to exit from L1 */ ++ call_gadget(hsotg, resume); ++ /* Change to L0 state */ ++ hsotg->lx_state = DWC2_L0; ++ hsotg->bus_suspended = false; ++fail: dwc2_gadget_init_lpm(hsotg); + } else { + /* TODO */ + dev_err(hsotg->dev, "Host side LPM is not supported.\n"); + return; + } +- +- /* Change to L0 state */ +- hsotg->lx_state = DWC2_L0; +- +- /* Inform gadget to exit from L1 */ +- call_gadget(hsotg, resume); + } + + /* +@@ -386,7 +407,7 @@ static void dwc2_handle_wakeup_detected_ + dev_dbg(hsotg->dev, "%s lxstate = %d\n", __func__, hsotg->lx_state); + + if (hsotg->lx_state == DWC2_L1) { +- dwc2_wakeup_from_lpm_l1(hsotg); ++ dwc2_wakeup_from_lpm_l1(hsotg, false); + return; + } + +--- a/drivers/usb/dwc2/gadget.c ++++ b/drivers/usb/dwc2/gadget.c +@@ -1415,6 +1415,10 @@ static int dwc2_hsotg_ep_queue(struct us + ep->name, req, req->length, req->buf, req->no_interrupt, + req->zero, req->short_not_ok); + ++ if (hs->lx_state == DWC2_L1) { ++ dwc2_wakeup_from_lpm_l1(hs, true); ++ } ++ + /* Prevent new request submission when controller is suspended */ + if (hs->lx_state != DWC2_L0) { + dev_dbg(hs->dev, "%s: submit request only in active state\n", diff --git a/queue-6.8/usb-dwc2-host-fix-hibernation-flow.patch b/queue-6.8/usb-dwc2-host-fix-hibernation-flow.patch new file mode 100644 index 00000000000..b7ebbf58cdb --- /dev/null +++ b/queue-6.8/usb-dwc2-host-fix-hibernation-flow.patch @@ -0,0 +1,94 @@ +From 3c7b9856a82227db01a20171d2e24c7ce305d59b Mon Sep 17 00:00:00 2001 +From: Minas Harutyunyan +Date: Wed, 13 Mar 2024 09:21:11 +0000 +Subject: usb: dwc2: host: Fix hibernation flow + +From: Minas Harutyunyan + +commit 3c7b9856a82227db01a20171d2e24c7ce305d59b upstream. + +Added to backup/restore registers HFLBADDR, HCCHARi, HCSPLTi, +HCTSIZi, HCDMAi and HCDMABi. + +Fixes: 58e52ff6a6c3 ("usb: dwc2: Move register save and restore functions") +Fixes: d17ee77b3044 ("usb: dwc2: add controller hibernation support") +CC: stable@vger.kernel.org +Signed-off-by: Minas Harutyunyan +Link: https://lore.kernel.org/r/c2d10ee6098b9b009a8e94191e046004747d3bdd.1708945444.git.Minas.Harutyunyan@synopsys.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/dwc2/core.h | 12 ++++++++++++ + drivers/usb/dwc2/hcd.c | 18 ++++++++++++++++-- + 2 files changed, 28 insertions(+), 2 deletions(-) + +--- a/drivers/usb/dwc2/core.h ++++ b/drivers/usb/dwc2/core.h +@@ -729,8 +729,14 @@ struct dwc2_dregs_backup { + * struct dwc2_hregs_backup - Holds host registers state before + * entering partial power down + * @hcfg: Backup of HCFG register ++ * @hflbaddr: Backup of HFLBADDR register + * @haintmsk: Backup of HAINTMSK register ++ * @hcchar: Backup of HCCHAR register ++ * @hcsplt: Backup of HCSPLT register + * @hcintmsk: Backup of HCINTMSK register ++ * @hctsiz: Backup of HCTSIZ register ++ * @hdma: Backup of HCDMA register ++ * @hcdmab: Backup of HCDMAB register + * @hprt0: Backup of HPTR0 register + * @hfir: Backup of HFIR register + * @hptxfsiz: Backup of HPTXFSIZ register +@@ -738,8 +744,14 @@ struct dwc2_dregs_backup { + */ + struct dwc2_hregs_backup { + u32 hcfg; ++ u32 hflbaddr; + u32 haintmsk; ++ u32 hcchar[MAX_EPS_CHANNELS]; ++ u32 hcsplt[MAX_EPS_CHANNELS]; + u32 hcintmsk[MAX_EPS_CHANNELS]; ++ u32 hctsiz[MAX_EPS_CHANNELS]; ++ u32 hcidma[MAX_EPS_CHANNELS]; ++ u32 hcidmab[MAX_EPS_CHANNELS]; + u32 hprt0; + u32 hfir; + u32 hptxfsiz; +--- a/drivers/usb/dwc2/hcd.c ++++ b/drivers/usb/dwc2/hcd.c +@@ -5406,9 +5406,16 @@ int dwc2_backup_host_registers(struct dw + /* Backup Host regs */ + hr = &hsotg->hr_backup; + hr->hcfg = dwc2_readl(hsotg, HCFG); ++ hr->hflbaddr = dwc2_readl(hsotg, HFLBADDR); + hr->haintmsk = dwc2_readl(hsotg, HAINTMSK); +- for (i = 0; i < hsotg->params.host_channels; ++i) ++ for (i = 0; i < hsotg->params.host_channels; ++i) { ++ hr->hcchar[i] = dwc2_readl(hsotg, HCCHAR(i)); ++ hr->hcsplt[i] = dwc2_readl(hsotg, HCSPLT(i)); + hr->hcintmsk[i] = dwc2_readl(hsotg, HCINTMSK(i)); ++ hr->hctsiz[i] = dwc2_readl(hsotg, HCTSIZ(i)); ++ hr->hcidma[i] = dwc2_readl(hsotg, HCDMA(i)); ++ hr->hcidmab[i] = dwc2_readl(hsotg, HCDMAB(i)); ++ } + + hr->hprt0 = dwc2_read_hprt0(hsotg); + hr->hfir = dwc2_readl(hsotg, HFIR); +@@ -5442,10 +5449,17 @@ int dwc2_restore_host_registers(struct d + hr->valid = false; + + dwc2_writel(hsotg, hr->hcfg, HCFG); ++ dwc2_writel(hsotg, hr->hflbaddr, HFLBADDR); + dwc2_writel(hsotg, hr->haintmsk, HAINTMSK); + +- for (i = 0; i < hsotg->params.host_channels; ++i) ++ for (i = 0; i < hsotg->params.host_channels; ++i) { ++ dwc2_writel(hsotg, hr->hcchar[i], HCCHAR(i)); ++ dwc2_writel(hsotg, hr->hcsplt[i], HCSPLT(i)); + dwc2_writel(hsotg, hr->hcintmsk[i], HCINTMSK(i)); ++ dwc2_writel(hsotg, hr->hctsiz[i], HCTSIZ(i)); ++ dwc2_writel(hsotg, hr->hcidma[i], HCDMA(i)); ++ dwc2_writel(hsotg, hr->hcidmab[i], HCDMAB(i)); ++ } + + dwc2_writel(hsotg, hr->hprt0, HPRT0); + dwc2_writel(hsotg, hr->hfir, HFIR); diff --git a/queue-6.8/usb-dwc2-host-fix-isoc-flow-in-ddma-mode.patch b/queue-6.8/usb-dwc2-host-fix-isoc-flow-in-ddma-mode.patch new file mode 100644 index 00000000000..cc27819cc0c --- /dev/null +++ b/queue-6.8/usb-dwc2-host-fix-isoc-flow-in-ddma-mode.patch @@ -0,0 +1,134 @@ +From b258e42688501cadb1a6dd658d6f015df9f32d8f Mon Sep 17 00:00:00 2001 +From: Minas Harutyunyan +Date: Wed, 13 Mar 2024 09:21:32 +0000 +Subject: usb: dwc2: host: Fix ISOC flow in DDMA mode + +From: Minas Harutyunyan + +commit b258e42688501cadb1a6dd658d6f015df9f32d8f upstream. + +Fixed ISOC completion flow in DDMA mode. Added isoc +descriptor actual length value and update urb's start_frame +value. +Fixed initialization of ISOC DMA descriptors flow. + +Fixes: 56f5b1cff22a ("staging: Core files for the DWC2 driver") +Fixes: 20f2eb9c4cf8 ("staging: dwc2: add microframe scheduler from downstream Pi kernel") +Fixes: c17b337c1ea4 ("usb: dwc2: host: program descriptor for next frame") +Fixes: dc4c76e7b22c ("staging: HCD descriptor DMA support for the DWC2 driver") +Fixes: 762d3a1a9cd7 ("usb: dwc2: host: process all completed urbs") +CC: stable@vger.kernel.org +Signed-off-by: Minas Harutyunyan +Link: https://lore.kernel.org/r/a8b1e1711cc6cabfb45d92ede12e35445c66f06c.1708944698.git.Minas.Harutyunyan@synopsys.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/dwc2/hcd.c | 12 ++++++++++-- + drivers/usb/dwc2/hcd_ddma.c | 17 +++++++++++------ + drivers/usb/dwc2/hw.h | 2 +- + 3 files changed, 22 insertions(+), 9 deletions(-) + +--- a/drivers/usb/dwc2/hcd.c ++++ b/drivers/usb/dwc2/hcd.c +@@ -2701,8 +2701,11 @@ enum dwc2_transaction_type dwc2_hcd_sele + hsotg->available_host_channels--; + } + qh = list_entry(qh_ptr, struct dwc2_qh, qh_list_entry); +- if (dwc2_assign_and_init_hc(hsotg, qh)) ++ if (dwc2_assign_and_init_hc(hsotg, qh)) { ++ if (hsotg->params.uframe_sched) ++ hsotg->available_host_channels++; + break; ++ } + + /* + * Move the QH from the periodic ready schedule to the +@@ -2735,8 +2738,11 @@ enum dwc2_transaction_type dwc2_hcd_sele + hsotg->available_host_channels--; + } + +- if (dwc2_assign_and_init_hc(hsotg, qh)) ++ if (dwc2_assign_and_init_hc(hsotg, qh)) { ++ if (hsotg->params.uframe_sched) ++ hsotg->available_host_channels++; + break; ++ } + + /* + * Move the QH from the non-periodic inactive schedule to the +@@ -4143,6 +4149,8 @@ void dwc2_host_complete(struct dwc2_hsot + urb->actual_length); + + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { ++ if (!hsotg->params.dma_desc_enable) ++ urb->start_frame = qtd->qh->start_active_frame; + urb->error_count = dwc2_hcd_urb_get_error_count(qtd->urb); + for (i = 0; i < urb->number_of_packets; ++i) { + urb->iso_frame_desc[i].actual_length = +--- a/drivers/usb/dwc2/hcd_ddma.c ++++ b/drivers/usb/dwc2/hcd_ddma.c +@@ -559,7 +559,7 @@ static void dwc2_init_isoc_dma_desc(stru + idx = qh->td_last; + inc = qh->host_interval; + hsotg->frame_number = dwc2_hcd_get_frame_number(hsotg); +- cur_idx = dwc2_frame_list_idx(hsotg->frame_number); ++ cur_idx = idx; + next_idx = dwc2_desclist_idx_inc(qh->td_last, inc, qh->dev_speed); + + /* +@@ -866,6 +866,8 @@ static int dwc2_cmpl_host_isoc_dma_desc( + { + struct dwc2_dma_desc *dma_desc; + struct dwc2_hcd_iso_packet_desc *frame_desc; ++ u16 frame_desc_idx; ++ struct urb *usb_urb = qtd->urb->priv; + u16 remain = 0; + int rc = 0; + +@@ -878,8 +880,11 @@ static int dwc2_cmpl_host_isoc_dma_desc( + DMA_FROM_DEVICE); + + dma_desc = &qh->desc_list[idx]; ++ frame_desc_idx = (idx - qtd->isoc_td_first) & (usb_urb->number_of_packets - 1); + +- frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index_last]; ++ frame_desc = &qtd->urb->iso_descs[frame_desc_idx]; ++ if (idx == qtd->isoc_td_first) ++ usb_urb->start_frame = dwc2_hcd_get_frame_number(hsotg); + dma_desc->buf = (u32)(qtd->urb->dma + frame_desc->offset); + if (chan->ep_is_in) + remain = (dma_desc->status & HOST_DMA_ISOC_NBYTES_MASK) >> +@@ -900,7 +905,7 @@ static int dwc2_cmpl_host_isoc_dma_desc( + frame_desc->status = 0; + } + +- if (++qtd->isoc_frame_index == qtd->urb->packet_count) { ++ if (++qtd->isoc_frame_index == usb_urb->number_of_packets) { + /* + * urb->status is not used for isoc transfers here. The + * individual frame_desc status are used instead. +@@ -1005,11 +1010,11 @@ static void dwc2_complete_isoc_xfer_ddma + return; + idx = dwc2_desclist_idx_inc(idx, qh->host_interval, + chan->speed); +- if (!rc) ++ if (rc == 0) + continue; + +- if (rc == DWC2_CMPL_DONE) +- break; ++ if (rc == DWC2_CMPL_DONE || rc == DWC2_CMPL_STOP) ++ goto stop_scan; + + /* rc == DWC2_CMPL_STOP */ + +--- a/drivers/usb/dwc2/hw.h ++++ b/drivers/usb/dwc2/hw.h +@@ -698,7 +698,7 @@ + #define TXSTS_QTOP_TOKEN_MASK (0x3 << 25) + #define TXSTS_QTOP_TOKEN_SHIFT 25 + #define TXSTS_QTOP_TERMINATE BIT(24) +-#define TXSTS_QSPCAVAIL_MASK (0xff << 16) ++#define TXSTS_QSPCAVAIL_MASK (0x7f << 16) + #define TXSTS_QSPCAVAIL_SHIFT 16 + #define TXSTS_FSPCAVAIL_MASK (0xffff << 0) + #define TXSTS_FSPCAVAIL_SHIFT 0 diff --git a/queue-6.8/usb-dwc2-host-fix-remote-wakeup-from-hibernation.patch b/queue-6.8/usb-dwc2-host-fix-remote-wakeup-from-hibernation.patch new file mode 100644 index 00000000000..cc2cf8a7521 --- /dev/null +++ b/queue-6.8/usb-dwc2-host-fix-remote-wakeup-from-hibernation.patch @@ -0,0 +1,66 @@ +From bae2bc73a59c200db53b6c15fb26bb758e2c6108 Mon Sep 17 00:00:00 2001 +From: Minas Harutyunyan +Date: Wed, 13 Mar 2024 09:21:21 +0000 +Subject: usb: dwc2: host: Fix remote wakeup from hibernation + +From: Minas Harutyunyan + +commit bae2bc73a59c200db53b6c15fb26bb758e2c6108 upstream. + +Starting from core v4.30a changed order of programming +GPWRDN_PMUACTV to 0 in case of exit from hibernation on +remote wakeup signaling from device. + +Fixes: c5c403dc4336 ("usb: dwc2: Add host/device hibernation functions") +CC: stable@vger.kernel.org +Signed-off-by: Minas Harutyunyan +Link: https://lore.kernel.org/r/99385ec55ce73445b6fbd0f471c9bd40eb1c9b9e.1708939799.git.Minas.Harutyunyan@synopsys.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/dwc2/core.h | 1 + + drivers/usb/dwc2/hcd.c | 17 +++++++++++++---- + 2 files changed, 14 insertions(+), 4 deletions(-) + +--- a/drivers/usb/dwc2/core.h ++++ b/drivers/usb/dwc2/core.h +@@ -1086,6 +1086,7 @@ struct dwc2_hsotg { + bool needs_byte_swap; + + /* DWC OTG HW Release versions */ ++#define DWC2_CORE_REV_4_30a 0x4f54430a + #define DWC2_CORE_REV_2_71a 0x4f54271a + #define DWC2_CORE_REV_2_72a 0x4f54272a + #define DWC2_CORE_REV_2_80a 0x4f54280a +--- a/drivers/usb/dwc2/hcd.c ++++ b/drivers/usb/dwc2/hcd.c +@@ -5610,10 +5610,12 @@ int dwc2_host_exit_hibernation(struct dw + dwc2_writel(hsotg, hr->hcfg, HCFG); + + /* De-assert Wakeup Logic */ +- gpwrdn = dwc2_readl(hsotg, GPWRDN); +- gpwrdn &= ~GPWRDN_PMUACTV; +- dwc2_writel(hsotg, gpwrdn, GPWRDN); +- udelay(10); ++ if (!(rem_wakeup && hsotg->hw_params.snpsid >= DWC2_CORE_REV_4_30a)) { ++ gpwrdn = dwc2_readl(hsotg, GPWRDN); ++ gpwrdn &= ~GPWRDN_PMUACTV; ++ dwc2_writel(hsotg, gpwrdn, GPWRDN); ++ udelay(10); ++ } + + hprt0 = hr->hprt0; + hprt0 |= HPRT0_PWR; +@@ -5638,6 +5640,13 @@ int dwc2_host_exit_hibernation(struct dw + hprt0 |= HPRT0_RES; + dwc2_writel(hsotg, hprt0, HPRT0); + ++ /* De-assert Wakeup Logic */ ++ if ((rem_wakeup && hsotg->hw_params.snpsid >= DWC2_CORE_REV_4_30a)) { ++ gpwrdn = dwc2_readl(hsotg, GPWRDN); ++ gpwrdn &= ~GPWRDN_PMUACTV; ++ dwc2_writel(hsotg, gpwrdn, GPWRDN); ++ udelay(10); ++ } + /* Wait for Resume time and then program HPRT again */ + mdelay(100); + hprt0 &= ~HPRT0_RES; diff --git a/queue-6.8/usb-typec-return-size-of-buffer-if-pd_set-operation-succeeds.patch b/queue-6.8/usb-typec-return-size-of-buffer-if-pd_set-operation-succeeds.patch new file mode 100644 index 00000000000..43e7cfcf571 --- /dev/null +++ b/queue-6.8/usb-typec-return-size-of-buffer-if-pd_set-operation-succeeds.patch @@ -0,0 +1,46 @@ +From 53f5094fdf5deacd99b8655df692e9278506724d Mon Sep 17 00:00:00 2001 +From: Kyle Tso +Date: Tue, 19 Mar 2024 15:43:09 +0800 +Subject: usb: typec: Return size of buffer if pd_set operation succeeds + +From: Kyle Tso + +commit 53f5094fdf5deacd99b8655df692e9278506724d upstream. + +The attribute writing should return the number of bytes used from the +buffer on success. + +Fixes: a7cff92f0635 ("usb: typec: USB Power Delivery helpers for ports and partners") +Cc: stable@vger.kernel.org +Signed-off-by: Kyle Tso +Reviewed-by: Guenter Roeck +Reviewed-by: Heikki Krogerus +Link: https://lore.kernel.org/r/20240319074309.3306579-1-kyletso@google.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/typec/class.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- a/drivers/usb/typec/class.c ++++ b/drivers/usb/typec/class.c +@@ -1310,6 +1310,7 @@ static ssize_t select_usb_power_delivery + { + struct typec_port *port = to_typec_port(dev); + struct usb_power_delivery *pd; ++ int ret; + + if (!port->ops || !port->ops->pd_set) + return -EOPNOTSUPP; +@@ -1318,7 +1319,11 @@ static ssize_t select_usb_power_delivery + if (!pd) + return -EINVAL; + +- return port->ops->pd_set(port, pd); ++ ret = port->ops->pd_set(port, pd); ++ if (ret) ++ return ret; ++ ++ return size; + } + + static ssize_t select_usb_power_delivery_show(struct device *dev, diff --git a/queue-6.8/usb-typec-tcpm-correct-port-source-pdo-array-in-pd_set-callback.patch b/queue-6.8/usb-typec-tcpm-correct-port-source-pdo-array-in-pd_set-callback.patch new file mode 100644 index 00000000000..4f4d6d14eb3 --- /dev/null +++ b/queue-6.8/usb-typec-tcpm-correct-port-source-pdo-array-in-pd_set-callback.patch @@ -0,0 +1,33 @@ +From 893cd9469c68a89a34956121685617dbb37497b1 Mon Sep 17 00:00:00 2001 +From: Kyle Tso +Date: Mon, 11 Mar 2024 22:45:00 +0800 +Subject: usb: typec: tcpm: Correct port source pdo array in pd_set callback + +From: Kyle Tso + +commit 893cd9469c68a89a34956121685617dbb37497b1 upstream. + +In tcpm_pd_set, the array of port source capabilities is port->src_pdo, +not port->snk_pdo. + +Fixes: cd099cde4ed2 ("usb: typec: tcpm: Support multiple capabilities") +Cc: stable@vger.kernel.org +Signed-off-by: Kyle Tso +Acked-by: Heikki Krogerus +Link: https://lore.kernel.org/r/20240311144500.3694849-1-kyletso@google.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/typec/tcpm/tcpm.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/usb/typec/tcpm/tcpm.c ++++ b/drivers/usb/typec/tcpm/tcpm.c +@@ -6117,7 +6117,7 @@ static int tcpm_pd_set(struct typec_port + + if (data->source_desc.pdo[0]) { + for (i = 0; i < PDO_MAX_OBJECTS && data->source_desc.pdo[i]; i++) +- port->snk_pdo[i] = data->source_desc.pdo[i]; ++ port->src_pdo[i] = data->source_desc.pdo[i]; + port->nr_src_pdo = i + 1; + } + diff --git a/queue-6.8/usb-typec-tcpm-fix-double-free-issue-in-tcpm_port_unregister_pd.patch b/queue-6.8/usb-typec-tcpm-fix-double-free-issue-in-tcpm_port_unregister_pd.patch new file mode 100644 index 00000000000..1fa70f1a2b3 --- /dev/null +++ b/queue-6.8/usb-typec-tcpm-fix-double-free-issue-in-tcpm_port_unregister_pd.patch @@ -0,0 +1,58 @@ +From b63f90487bdf93a4223ce7853d14717e9d452856 Mon Sep 17 00:00:00 2001 +From: Xu Yang +Date: Mon, 11 Mar 2024 14:52:19 +0800 +Subject: usb: typec: tcpm: fix double-free issue in tcpm_port_unregister_pd() + +From: Xu Yang + +commit b63f90487bdf93a4223ce7853d14717e9d452856 upstream. + +When unregister pd capabilitie in tcpm, KASAN will capture below double +-free issue. The root cause is the same capabilitiy will be kfreed twice, +the first time is kfreed by pd_capabilities_release() and the second time +is explicitly kfreed by tcpm_port_unregister_pd(). + +[ 3.988059] BUG: KASAN: double-free in tcpm_port_unregister_pd+0x1a4/0x3dc +[ 3.995001] Free of addr ffff0008164d3000 by task kworker/u16:0/10 +[ 4.001206] +[ 4.002712] CPU: 2 PID: 10 Comm: kworker/u16:0 Not tainted 6.8.0-rc5-next-20240220-05616-g52728c567a55 #53 +[ 4.012402] Hardware name: Freescale i.MX8QXP MEK (DT) +[ 4.017569] Workqueue: events_unbound deferred_probe_work_func +[ 4.023456] Call trace: +[ 4.025920] dump_backtrace+0x94/0xec +[ 4.029629] show_stack+0x18/0x24 +[ 4.032974] dump_stack_lvl+0x78/0x90 +[ 4.036675] print_report+0xfc/0x5c0 +[ 4.040289] kasan_report_invalid_free+0xa0/0xc0 +[ 4.044937] __kasan_slab_free+0x124/0x154 +[ 4.049072] kfree+0xb4/0x1e8 +[ 4.052069] tcpm_port_unregister_pd+0x1a4/0x3dc +[ 4.056725] tcpm_register_port+0x1dd0/0x2558 +[ 4.061121] tcpci_register_port+0x420/0x71c +[ 4.065430] tcpci_probe+0x118/0x2e0 + +To fix the issue, this will remove kree() from tcpm_port_unregister_pd(). + +Fixes: cd099cde4ed2 ("usb: typec: tcpm: Support multiple capabilities") +cc: stable@vger.kernel.org +Suggested-by: Aisheng Dong +Signed-off-by: Xu Yang +Acked-by: Heikki Krogerus +Link: https://lore.kernel.org/r/20240311065219.777037-1-xu.yang_2@nxp.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/typec/tcpm/tcpm.c | 2 -- + 1 file changed, 2 deletions(-) + +--- a/drivers/usb/typec/tcpm/tcpm.c ++++ b/drivers/usb/typec/tcpm/tcpm.c +@@ -6199,9 +6199,7 @@ static void tcpm_port_unregister_pd(stru + port->port_source_caps = NULL; + for (i = 0; i < port->pd_count; i++) { + usb_power_delivery_unregister_capabilities(port->pd_list[i]->sink_cap); +- kfree(port->pd_list[i]->sink_cap); + usb_power_delivery_unregister_capabilities(port->pd_list[i]->source_cap); +- kfree(port->pd_list[i]->source_cap); + devm_kfree(port->dev, port->pd_list[i]); + port->pd_list[i] = NULL; + usb_power_delivery_unregister(port->pds[i]); diff --git a/queue-6.8/usb-typec-tcpm-update-pd-of-type-c-port-upon-pd_set.patch b/queue-6.8/usb-typec-tcpm-update-pd-of-type-c-port-upon-pd_set.patch new file mode 100644 index 00000000000..e310728b39c --- /dev/null +++ b/queue-6.8/usb-typec-tcpm-update-pd-of-type-c-port-upon-pd_set.patch @@ -0,0 +1,34 @@ +From 17af5050dead6cbcca12c1fcd17e0bb8bb284eae Mon Sep 17 00:00:00 2001 +From: Kyle Tso +Date: Tue, 12 Mar 2024 01:23:06 +0800 +Subject: usb: typec: tcpm: Update PD of Type-C port upon pd_set + +From: Kyle Tso + +commit 17af5050dead6cbcca12c1fcd17e0bb8bb284eae upstream. + +The PD of Type-C port needs to be updated in pd_set. Unlink the Type-C +port device to the old PD before linking it to a new one. + +Fixes: cd099cde4ed2 ("usb: typec: tcpm: Support multiple capabilities") +Cc: stable@vger.kernel.org +Signed-off-by: Kyle Tso +Acked-by: Heikki Krogerus +Link: https://lore.kernel.org/r/20240311172306.3911309-1-kyletso@google.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/typec/tcpm/tcpm.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/usb/typec/tcpm/tcpm.c ++++ b/drivers/usb/typec/tcpm/tcpm.c +@@ -6166,7 +6166,9 @@ static int tcpm_pd_set(struct typec_port + + port->port_source_caps = data->source_cap; + port->port_sink_caps = data->sink_cap; ++ typec_port_set_usb_power_delivery(p, NULL); + port->selected_pd = pd; ++ typec_port_set_usb_power_delivery(p, port->selected_pd); + unlock: + mutex_unlock(&port->lock); + return ret; diff --git a/queue-6.8/usb-typec-ucsi-ack-unsupported-commands.patch b/queue-6.8/usb-typec-ucsi-ack-unsupported-commands.patch new file mode 100644 index 00000000000..68ecbb1e7d6 --- /dev/null +++ b/queue-6.8/usb-typec-ucsi-ack-unsupported-commands.patch @@ -0,0 +1,40 @@ +From 6b5c85ddeea77d18c4b69e3bda60e9374a20c304 Mon Sep 17 00:00:00 2001 +From: "Christian A. Ehrhardt" +Date: Wed, 20 Mar 2024 08:39:24 +0100 +Subject: usb: typec: ucsi: Ack unsupported commands + +From: Christian A. Ehrhardt + +commit 6b5c85ddeea77d18c4b69e3bda60e9374a20c304 upstream. + +If a command completes the OPM must send an ack. This applies +to unsupported commands, too. + +Send the required ACK for unsupported commands. + +Signed-off-by: Christian A. Ehrhardt +Cc: stable +Reviewed-by: Heikki Krogerus +Tested-by: Neil Armstrong # on SM8550-QRD +Link: https://lore.kernel.org/r/20240320073927.1641788-4-lk@c--e.de +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/typec/ucsi/ucsi.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/drivers/usb/typec/ucsi/ucsi.c ++++ b/drivers/usb/typec/ucsi/ucsi.c +@@ -138,8 +138,12 @@ static int ucsi_exec_command(struct ucsi + if (!(cci & UCSI_CCI_COMMAND_COMPLETE)) + return -EIO; + +- if (cci & UCSI_CCI_NOT_SUPPORTED) ++ if (cci & UCSI_CCI_NOT_SUPPORTED) { ++ if (ucsi_acknowledge_command(ucsi) < 0) ++ dev_err(ucsi->dev, ++ "ACK of unsupported command failed\n"); + return -EOPNOTSUPP; ++ } + + if (cci & UCSI_CCI_ERROR) { + if (cmd == UCSI_GET_ERROR_STATUS) diff --git a/queue-6.8/usb-typec-ucsi-check-for-notifications-after-init.patch b/queue-6.8/usb-typec-ucsi-check-for-notifications-after-init.patch new file mode 100644 index 00000000000..c28c2d89dfb --- /dev/null +++ b/queue-6.8/usb-typec-ucsi-check-for-notifications-after-init.patch @@ -0,0 +1,64 @@ +From 808a8b9e0b87bbc72bcc1f7ddfe5d04746e7ce56 Mon Sep 17 00:00:00 2001 +From: "Christian A. Ehrhardt" +Date: Wed, 20 Mar 2024 08:39:23 +0100 +Subject: usb: typec: ucsi: Check for notifications after init + +From: Christian A. Ehrhardt + +commit 808a8b9e0b87bbc72bcc1f7ddfe5d04746e7ce56 upstream. + +The completion notification for the final SET_NOTIFICATION_ENABLE +command during initialization can include a connector change +notification. However, at the time this completion notification is +processed, the ucsi struct is not ready to handle this notification. +As a result the notification is ignored and the controller +never sends an interrupt again. + +Re-check CCI for a pending connector state change after +initialization is complete. Adjust the corresponding debug +message accordingly. + +Fixes: 71a1fa0df2a3 ("usb: typec: ucsi: Store the notification mask") +Cc: stable@vger.kernel.org +Signed-off-by: Christian A. Ehrhardt +Reviewed-by: Heikki Krogerus +Tested-by: Neil Armstrong # on SM8550-QRD +Link: https://lore.kernel.org/r/20240320073927.1641788-3-lk@c--e.de +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/typec/ucsi/ucsi.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +--- a/drivers/usb/typec/ucsi/ucsi.c ++++ b/drivers/usb/typec/ucsi/ucsi.c +@@ -958,7 +958,7 @@ void ucsi_connector_change(struct ucsi * + struct ucsi_connector *con = &ucsi->connector[num - 1]; + + if (!(ucsi->ntfy & UCSI_ENABLE_NTFY_CONNECTOR_CHANGE)) { +- dev_dbg(ucsi->dev, "Bogus connector change event\n"); ++ dev_dbg(ucsi->dev, "Early connector change event\n"); + return; + } + +@@ -1355,6 +1355,7 @@ static int ucsi_init(struct ucsi *ucsi) + { + struct ucsi_connector *con, *connector; + u64 command, ntfy; ++ u32 cci; + int ret; + int i; + +@@ -1407,6 +1408,13 @@ static int ucsi_init(struct ucsi *ucsi) + + ucsi->connector = connector; + ucsi->ntfy = ntfy; ++ ++ ret = ucsi->ops->read(ucsi, UCSI_CCI, &cci, sizeof(cci)); ++ if (ret) ++ return ret; ++ if (UCSI_CCI_CONNECTOR(READ_ONCE(cci))) ++ ucsi_connector_change(ucsi, cci); ++ + return 0; + + err_unregister: diff --git a/queue-6.8/usb-typec-ucsi-clear-event_pending-under-ppm-lock.patch b/queue-6.8/usb-typec-ucsi-clear-event_pending-under-ppm-lock.patch new file mode 100644 index 00000000000..5a19a869c4c --- /dev/null +++ b/queue-6.8/usb-typec-ucsi-clear-event_pending-under-ppm-lock.patch @@ -0,0 +1,44 @@ +From 15b2e71b4653b3e13df34695a29ebeee237c5af2 Mon Sep 17 00:00:00 2001 +From: "Christian A. Ehrhardt" +Date: Wed, 20 Mar 2024 08:39:22 +0100 +Subject: usb: typec: ucsi: Clear EVENT_PENDING under PPM lock + +From: Christian A. Ehrhardt + +commit 15b2e71b4653b3e13df34695a29ebeee237c5af2 upstream. + +Suppose we sleep on the PPM lock after clearing the EVENT_PENDING +bit because the thread for another connector is executing a command. +In this case the command completion of the other command will still +report the connector change for our connector. + +Clear the EVENT_PENDING bit under the PPM lock to avoid another +useless call to ucsi_handle_connector_change() in this case. + +Fixes: c9aed03a0a68 ("usb: ucsi: Add missing ppm_lock") +Cc: stable +Signed-off-by: Christian A. Ehrhardt +Reviewed-by: Heikki Krogerus +Tested-by: Neil Armstrong # on SM8550-QRD +Link: https://lore.kernel.org/r/20240320073927.1641788-2-lk@c--e.de +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/typec/ucsi/ucsi.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/usb/typec/ucsi/ucsi.c ++++ b/drivers/usb/typec/ucsi/ucsi.c +@@ -936,11 +936,11 @@ static void ucsi_handle_connector_change + if (con->status.change & UCSI_CONSTAT_CAM_CHANGE) + ucsi_partner_task(con, ucsi_check_altmodes, 1, 0); + +- clear_bit(EVENT_PENDING, &con->ucsi->flags); +- + mutex_lock(&ucsi->ppm_lock); ++ clear_bit(EVENT_PENDING, &con->ucsi->flags); + ret = ucsi_acknowledge_connector_change(ucsi); + mutex_unlock(&ucsi->ppm_lock); ++ + if (ret) + dev_err(ucsi->dev, "%s: ACK failed (%d)", __func__, ret); + diff --git a/queue-6.8/usb-typec-ucsi-clear-ucsi_cci_reset_complete-before-reset.patch b/queue-6.8/usb-typec-ucsi-clear-ucsi_cci_reset_complete-before-reset.patch new file mode 100644 index 00000000000..f544fb18e7a --- /dev/null +++ b/queue-6.8/usb-typec-ucsi-clear-ucsi_cci_reset_complete-before-reset.patch @@ -0,0 +1,74 @@ +From 3de4f996a0b5412aa451729008130a488f71563e Mon Sep 17 00:00:00 2001 +From: "Christian A. Ehrhardt" +Date: Wed, 20 Mar 2024 08:39:26 +0100 +Subject: usb: typec: ucsi: Clear UCSI_CCI_RESET_COMPLETE before reset + +From: Christian A. Ehrhardt + +commit 3de4f996a0b5412aa451729008130a488f71563e upstream. + +Check the UCSI_CCI_RESET_COMPLETE complete flag before starting +another reset. Use a UCSI_SET_NOTIFICATION_ENABLE command to clear +the flag if it is set. + +Signed-off-by: Christian A. Ehrhardt +Cc: stable +Reviewed-by: Heikki Krogerus +Tested-by: Neil Armstrong # on SM8550-QRD +Link: https://lore.kernel.org/r/20240320073927.1641788-6-lk@c--e.de +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/typec/ucsi/ucsi.c | 36 +++++++++++++++++++++++++++++++++++- + 1 file changed, 35 insertions(+), 1 deletion(-) + +--- a/drivers/usb/typec/ucsi/ucsi.c ++++ b/drivers/usb/typec/ucsi/ucsi.c +@@ -985,13 +985,47 @@ static int ucsi_reset_connector(struct u + + static int ucsi_reset_ppm(struct ucsi *ucsi) + { +- u64 command = UCSI_PPM_RESET; ++ u64 command; + unsigned long tmo; + u32 cci; + int ret; + + mutex_lock(&ucsi->ppm_lock); + ++ ret = ucsi->ops->read(ucsi, UCSI_CCI, &cci, sizeof(cci)); ++ if (ret < 0) ++ goto out; ++ ++ /* ++ * If UCSI_CCI_RESET_COMPLETE is already set we must clear ++ * the flag before we start another reset. Send a ++ * UCSI_SET_NOTIFICATION_ENABLE command to achieve this. ++ * Ignore a timeout and try the reset anyway if this fails. ++ */ ++ if (cci & UCSI_CCI_RESET_COMPLETE) { ++ command = UCSI_SET_NOTIFICATION_ENABLE; ++ ret = ucsi->ops->async_write(ucsi, UCSI_CONTROL, &command, ++ sizeof(command)); ++ if (ret < 0) ++ goto out; ++ ++ tmo = jiffies + msecs_to_jiffies(UCSI_TIMEOUT_MS); ++ do { ++ ret = ucsi->ops->read(ucsi, UCSI_CCI, ++ &cci, sizeof(cci)); ++ if (ret < 0) ++ goto out; ++ if (cci & UCSI_CCI_COMMAND_COMPLETE) ++ break; ++ if (time_is_before_jiffies(tmo)) ++ break; ++ msleep(20); ++ } while (1); ++ ++ WARN_ON(cci & UCSI_CCI_RESET_COMPLETE); ++ } ++ ++ command = UCSI_PPM_RESET; + ret = ucsi->ops->async_write(ucsi, UCSI_CONTROL, &command, + sizeof(command)); + if (ret < 0) diff --git a/queue-6.8/usb-typec-ucsi-fix-race-between-typec_switch-and-role_switch.patch b/queue-6.8/usb-typec-ucsi-fix-race-between-typec_switch-and-role_switch.patch new file mode 100644 index 00000000000..9f1852dfaa8 --- /dev/null +++ b/queue-6.8/usb-typec-ucsi-fix-race-between-typec_switch-and-role_switch.patch @@ -0,0 +1,93 @@ +From f5e9bda03aa50ffad36eccafe893d004ef213c43 Mon Sep 17 00:00:00 2001 +From: Krishna Kurapati +Date: Fri, 1 Mar 2024 09:39:14 +0530 +Subject: usb: typec: ucsi: Fix race between typec_switch and role_switch + +From: Krishna Kurapati + +commit f5e9bda03aa50ffad36eccafe893d004ef213c43 upstream. + +When orientation switch is enabled in ucsi glink, there is a xhci +probe failure seen when booting up in host mode in reverse +orientation. + +During bootup the following things happen in multiple drivers: + +a) DWC3 controller driver initializes the core in device mode when the +dr_mode is set to DRD. It relies on role_switch call to change role to +host. + +b) QMP driver initializes the lanes to TYPEC_ORIENTATION_NORMAL as a +normal routine. It relies on the typec_switch_set call to get notified +of orientation changes. + +c) UCSI core reads the UCSI_GET_CONNECTOR_STATUS via the glink and +provides initial role switch to dwc3 controller. + +When booting up in host mode with orientation TYPEC_ORIENTATION_REVERSE, +then we see the following things happening in order: + +a) UCSI gives initial role as host to dwc3 controller ucsi_register_port. +Upon receiving this notification, the dwc3 core needs to program GCTL from +PRTCAP_DEVICE to PRTCAP_HOST and as part of this change, it asserts GCTL +Core soft reset and waits for it to be completed before shifting it to +host. Only after the reset is done will the dwc3_host_init be invoked and +xhci is probed. DWC3 controller expects that the usb phy's are stable +during this process i.e., the phy init is already done. + +b) During the 100ms wait for GCTL core soft reset, the actual notification +from PPM is received by ucsi_glink via pmic glink for changing role to +host. The pmic_glink_ucsi_notify routine first sends the orientation +change to QMP and then sends role to dwc3 via ucsi framework. This is +happening exactly at the time GCTL core soft reset is being processed. + +c) When QMP driver receives typec switch to TYPEC_ORIENTATION_REVERSE, it +then re-programs the phy at the instant GCTL core soft reset has been +asserted by dwc3 controller due to which the QMP PLL lock fails in +qmp_combo_usb_power_on. + +d) After the 100ms of GCTL core soft reset is completed, the dwc3 core +goes for initializing the host mode and invokes xhci probe. But at this +point the QMP is non-responsive and as a result, the xhci plat probe fails +during xhci_reset. + +Fix this by passing orientation switch to available ucsi instances if +their gpio configuration is available before ucsi_register is invoked so +that by the time, the pmic_glink_ucsi_notify provides typec_switch to QMP, +the lane is already configured and the call would be a NOP thus not racing +with role switch. + +Cc: stable@vger.kernel.org +Fixes: c6165ed2f425 ("usb: ucsi: glink: use the connector orientation GPIO to provide switch events") +Suggested-by: Wesley Cheng +Signed-off-by: Krishna Kurapati +Acked-by: Heikki Krogerus +Link: https://lore.kernel.org/r/20240301040914.458492-1-quic_kriskura@quicinc.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/typec/ucsi/ucsi_glink.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +--- a/drivers/usb/typec/ucsi/ucsi_glink.c ++++ b/drivers/usb/typec/ucsi/ucsi_glink.c +@@ -255,6 +255,20 @@ static void pmic_glink_ucsi_notify(struc + static void pmic_glink_ucsi_register(struct work_struct *work) + { + struct pmic_glink_ucsi *ucsi = container_of(work, struct pmic_glink_ucsi, register_work); ++ int orientation; ++ int i; ++ ++ for (i = 0; i < PMIC_GLINK_MAX_PORTS; i++) { ++ if (!ucsi->port_orientation[i]) ++ continue; ++ orientation = gpiod_get_value(ucsi->port_orientation[i]); ++ ++ if (orientation >= 0) { ++ typec_switch_set(ucsi->port_switch[i], ++ orientation ? TYPEC_ORIENTATION_REVERSE ++ : TYPEC_ORIENTATION_NORMAL); ++ } ++ } + + ucsi_register(ucsi->ucsi); + } diff --git a/queue-6.8/usb-typec-ucsi_acpi-refactor-and-fix-dell-quirk.patch b/queue-6.8/usb-typec-ucsi_acpi-refactor-and-fix-dell-quirk.patch new file mode 100644 index 00000000000..89f85866b53 --- /dev/null +++ b/queue-6.8/usb-typec-ucsi_acpi-refactor-and-fix-dell-quirk.patch @@ -0,0 +1,163 @@ +From 6aaceb7d9cd00f3e065dc4b054ecfe52c5253b03 Mon Sep 17 00:00:00 2001 +From: "Christian A. Ehrhardt" +Date: Wed, 20 Mar 2024 08:39:25 +0100 +Subject: usb: typec: ucsi_acpi: Refactor and fix DELL quirk + +From: Christian A. Ehrhardt + +commit 6aaceb7d9cd00f3e065dc4b054ecfe52c5253b03 upstream. + +Some DELL systems don't like UCSI_ACK_CC_CI commands with the +UCSI_ACK_CONNECTOR_CHANGE but not the UCSI_ACK_COMMAND_COMPLETE +bit set. The current quirk still leaves room for races because +it requires two consecutive ACK commands to be sent. + +Refactor and significantly simplify the quirk to fix this: +Send a dummy command and bundle the connector change ack with the +command completion ack in a single UCSI_ACK_CC_CI command. +This removes the need to probe for the quirk. + +While there define flag bits for struct ucsi_acpi->flags in ucsi_acpi.c +and don't re-use definitions from ucsi.h for struct ucsi->flags. + +Fixes: f3be347ea42d ("usb: ucsi_acpi: Quirk to ack a connector change ack cmd") +Cc: stable@vger.kernel.org +Signed-off-by: Christian A. Ehrhardt +Reviewed-by: Heikki Krogerus +Tested-by: Neil Armstrong # on SM8550-QRD +Link: https://lore.kernel.org/r/20240320073927.1641788-5-lk@c--e.de +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/typec/ucsi/ucsi_acpi.c | 71 ++++++++++++++++--------------------- + 1 file changed, 31 insertions(+), 40 deletions(-) + +--- a/drivers/usb/typec/ucsi/ucsi_acpi.c ++++ b/drivers/usb/typec/ucsi/ucsi_acpi.c +@@ -23,10 +23,11 @@ struct ucsi_acpi { + void *base; + struct completion complete; + unsigned long flags; ++#define UCSI_ACPI_SUPPRESS_EVENT 0 ++#define UCSI_ACPI_COMMAND_PENDING 1 ++#define UCSI_ACPI_ACK_PENDING 2 + guid_t guid; + u64 cmd; +- bool dell_quirk_probed; +- bool dell_quirk_active; + }; + + static int ucsi_acpi_dsm(struct ucsi_acpi *ua, int func) +@@ -79,9 +80,9 @@ static int ucsi_acpi_sync_write(struct u + int ret; + + if (ack) +- set_bit(ACK_PENDING, &ua->flags); ++ set_bit(UCSI_ACPI_ACK_PENDING, &ua->flags); + else +- set_bit(COMMAND_PENDING, &ua->flags); ++ set_bit(UCSI_ACPI_COMMAND_PENDING, &ua->flags); + + ret = ucsi_acpi_async_write(ucsi, offset, val, val_len); + if (ret) +@@ -92,9 +93,9 @@ static int ucsi_acpi_sync_write(struct u + + out_clear_bit: + if (ack) +- clear_bit(ACK_PENDING, &ua->flags); ++ clear_bit(UCSI_ACPI_ACK_PENDING, &ua->flags); + else +- clear_bit(COMMAND_PENDING, &ua->flags); ++ clear_bit(UCSI_ACPI_COMMAND_PENDING, &ua->flags); + + return ret; + } +@@ -129,51 +130,40 @@ static const struct ucsi_operations ucsi + }; + + /* +- * Some Dell laptops expect that an ACK command with the +- * UCSI_ACK_CONNECTOR_CHANGE bit set is followed by a (separate) +- * ACK command that only has the UCSI_ACK_COMMAND_COMPLETE bit set. +- * If this is not done events are not delivered to OSPM and +- * subsequent commands will timeout. ++ * Some Dell laptops don't like ACK commands with the ++ * UCSI_ACK_CONNECTOR_CHANGE but not the UCSI_ACK_COMMAND_COMPLETE ++ * bit set. To work around this send a dummy command and bundle the ++ * UCSI_ACK_CONNECTOR_CHANGE with the UCSI_ACK_COMMAND_COMPLETE ++ * for the dummy command. + */ + static int + ucsi_dell_sync_write(struct ucsi *ucsi, unsigned int offset, + const void *val, size_t val_len) + { + struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); +- u64 cmd = *(u64 *)val, ack = 0; ++ u64 cmd = *(u64 *)val; ++ u64 dummycmd = UCSI_GET_CAPABILITY; + int ret; + +- if (UCSI_COMMAND(cmd) == UCSI_ACK_CC_CI && +- cmd & UCSI_ACK_CONNECTOR_CHANGE) +- ack = UCSI_ACK_CC_CI | UCSI_ACK_COMMAND_COMPLETE; ++ if (cmd == (UCSI_ACK_CC_CI | UCSI_ACK_CONNECTOR_CHANGE)) { ++ cmd |= UCSI_ACK_COMMAND_COMPLETE; + +- ret = ucsi_acpi_sync_write(ucsi, offset, val, val_len); +- if (ret != 0) +- return ret; +- if (ack == 0) +- return ret; +- +- if (!ua->dell_quirk_probed) { +- ua->dell_quirk_probed = true; ++ /* ++ * The UCSI core thinks it is sending a connector change ack ++ * and will accept new connector change events. We don't want ++ * this to happen for the dummy command as its response will ++ * still report the very event that the core is trying to clear. ++ */ ++ set_bit(UCSI_ACPI_SUPPRESS_EVENT, &ua->flags); ++ ret = ucsi_acpi_sync_write(ucsi, UCSI_CONTROL, &dummycmd, ++ sizeof(dummycmd)); ++ clear_bit(UCSI_ACPI_SUPPRESS_EVENT, &ua->flags); + +- cmd = UCSI_GET_CAPABILITY; +- ret = ucsi_acpi_sync_write(ucsi, UCSI_CONTROL, &cmd, +- sizeof(cmd)); +- if (ret == 0) +- return ucsi_acpi_sync_write(ucsi, UCSI_CONTROL, +- &ack, sizeof(ack)); +- if (ret != -ETIMEDOUT) ++ if (ret < 0) + return ret; +- +- ua->dell_quirk_active = true; +- dev_err(ua->dev, "Firmware bug: Additional ACK required after ACKing a connector change.\n"); +- dev_err(ua->dev, "Firmware bug: Enabling workaround\n"); + } + +- if (!ua->dell_quirk_active) +- return ret; +- +- return ucsi_acpi_sync_write(ucsi, UCSI_CONTROL, &ack, sizeof(ack)); ++ return ucsi_acpi_sync_write(ucsi, UCSI_CONTROL, &cmd, sizeof(cmd)); + } + + static const struct ucsi_operations ucsi_dell_ops = { +@@ -209,13 +199,14 @@ static void ucsi_acpi_notify(acpi_handle + if (ret) + return; + +- if (UCSI_CCI_CONNECTOR(cci)) ++ if (UCSI_CCI_CONNECTOR(cci) && ++ !test_bit(UCSI_ACPI_SUPPRESS_EVENT, &ua->flags)) + ucsi_connector_change(ua->ucsi, UCSI_CCI_CONNECTOR(cci)); + + if (cci & UCSI_CCI_ACK_COMPLETE && test_bit(ACK_PENDING, &ua->flags)) + complete(&ua->complete); + if (cci & UCSI_CCI_COMMAND_COMPLETE && +- test_bit(COMMAND_PENDING, &ua->flags)) ++ test_bit(UCSI_ACPI_COMMAND_PENDING, &ua->flags)) + complete(&ua->complete); + } + diff --git a/queue-6.8/usb-udc-remove-warning-when-queue-disabled-ep.patch b/queue-6.8/usb-udc-remove-warning-when-queue-disabled-ep.patch new file mode 100644 index 00000000000..1028f202415 --- /dev/null +++ b/queue-6.8/usb-udc-remove-warning-when-queue-disabled-ep.patch @@ -0,0 +1,44 @@ +From 2a587a035214fa1b5ef598aea0b81848c5b72e5e Mon Sep 17 00:00:00 2001 +From: yuan linyu +Date: Fri, 15 Mar 2024 10:01:44 +0800 +Subject: usb: udc: remove warning when queue disabled ep + +From: yuan linyu + +commit 2a587a035214fa1b5ef598aea0b81848c5b72e5e upstream. + +It is possible trigger below warning message from mass storage function, + +WARNING: CPU: 6 PID: 3839 at drivers/usb/gadget/udc/core.c:294 usb_ep_queue+0x7c/0x104 +pc : usb_ep_queue+0x7c/0x104 +lr : fsg_main_thread+0x494/0x1b3c + +Root cause is mass storage function try to queue request from main thread, +but other thread may already disable ep when function disable. + +As there is no function failure in the driver, in order to avoid effort +to fix warning, change WARN_ON_ONCE() in usb_ep_queue() to pr_debug(). + +Suggested-by: Alan Stern +Cc: stable@vger.kernel.org +Signed-off-by: yuan linyu +Reviewed-by: Alan Stern +Link: https://lore.kernel.org/r/20240315020144.2715575-1-yuanlinyu@hihonor.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/gadget/udc/core.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/usb/gadget/udc/core.c ++++ b/drivers/usb/gadget/udc/core.c +@@ -292,7 +292,9 @@ int usb_ep_queue(struct usb_ep *ep, + { + int ret = 0; + +- if (WARN_ON_ONCE(!ep->enabled && ep->address)) { ++ if (!ep->enabled && ep->address) { ++ pr_debug("USB gadget: queue request to disabled ep 0x%x (%s)\n", ++ ep->address, ep->name); + ret = -ESHUTDOWN; + goto out; + }