]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.1-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 28 Jul 2025 16:14:56 +0000 (18:14 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 28 Jul 2025 16:14:56 +0000 (18:14 +0200)
added patches:
drm-amdkfd-don-t-call-mmput-from-mmu-notifier-callback.patch
usb-typec-tcpm-allow-switching-to-mode-accessory-to-mux-properly.patch
usb-typec-tcpm-allow-to-use-sink-in-accessory-mode.patch
usb-typec-tcpm-apply-vbus-before-data-bringup-in-tcpm_src_attach.patch

queue-6.1/drm-amdkfd-don-t-call-mmput-from-mmu-notifier-callback.patch [new file with mode: 0644]
queue-6.1/series
queue-6.1/usb-typec-tcpm-allow-switching-to-mode-accessory-to-mux-properly.patch [new file with mode: 0644]
queue-6.1/usb-typec-tcpm-allow-to-use-sink-in-accessory-mode.patch [new file with mode: 0644]
queue-6.1/usb-typec-tcpm-apply-vbus-before-data-bringup-in-tcpm_src_attach.patch [new file with mode: 0644]

diff --git a/queue-6.1/drm-amdkfd-don-t-call-mmput-from-mmu-notifier-callback.patch b/queue-6.1/drm-amdkfd-don-t-call-mmput-from-mmu-notifier-callback.patch
new file mode 100644 (file)
index 0000000..3c14348
--- /dev/null
@@ -0,0 +1,204 @@
+From cf234231fcbc7d391e2135b9518613218cc5347f Mon Sep 17 00:00:00 2001
+From: Philip Yang <Philip.Yang@amd.com>
+Date: Fri, 20 Jun 2025 18:32:32 -0400
+Subject: drm/amdkfd: Don't call mmput from MMU notifier callback
+
+From: Philip Yang <Philip.Yang@amd.com>
+
+commit cf234231fcbc7d391e2135b9518613218cc5347f upstream.
+
+If the process is exiting, the mmput inside mmu notifier callback from
+compactd or fork or numa balancing could release the last reference
+of mm struct to call exit_mmap and free_pgtable, this triggers deadlock
+with below backtrace.
+
+The deadlock will leak kfd process as mmu notifier release is not called
+and cause VRAM leaking.
+
+The fix is to take mm reference mmget_non_zero when adding prange to the
+deferred list to pair with mmput in deferred list work.
+
+If prange split and add into pchild list, the pchild work_item.mm is not
+used, so remove the mm parameter from svm_range_unmap_split and
+svm_range_add_child.
+
+The backtrace of hung task:
+
+ INFO: task python:348105 blocked for more than 64512 seconds.
+ Call Trace:
+  __schedule+0x1c3/0x550
+  schedule+0x46/0xb0
+  rwsem_down_write_slowpath+0x24b/0x4c0
+  unlink_anon_vmas+0xb1/0x1c0
+  free_pgtables+0xa9/0x130
+  exit_mmap+0xbc/0x1a0
+  mmput+0x5a/0x140
+  svm_range_cpu_invalidate_pagetables+0x2b/0x40 [amdgpu]
+  mn_itree_invalidate+0x72/0xc0
+  __mmu_notifier_invalidate_range_start+0x48/0x60
+  try_to_unmap_one+0x10fa/0x1400
+  rmap_walk_anon+0x196/0x460
+  try_to_unmap+0xbb/0x210
+  migrate_page_unmap+0x54d/0x7e0
+  migrate_pages_batch+0x1c3/0xae0
+  migrate_pages_sync+0x98/0x240
+  migrate_pages+0x25c/0x520
+  compact_zone+0x29d/0x590
+  compact_zone_order+0xb6/0xf0
+  try_to_compact_pages+0xbe/0x220
+  __alloc_pages_direct_compact+0x96/0x1a0
+  __alloc_pages_slowpath+0x410/0x930
+  __alloc_pages_nodemask+0x3a9/0x3e0
+  do_huge_pmd_anonymous_page+0xd7/0x3e0
+  __handle_mm_fault+0x5e3/0x5f0
+  handle_mm_fault+0xf7/0x2e0
+  hmm_vma_fault.isra.0+0x4d/0xa0
+  walk_pmd_range.isra.0+0xa8/0x310
+  walk_pud_range+0x167/0x240
+  walk_pgd_range+0x55/0x100
+  __walk_page_range+0x87/0x90
+  walk_page_range+0xf6/0x160
+  hmm_range_fault+0x4f/0x90
+  amdgpu_hmm_range_get_pages+0x123/0x230 [amdgpu]
+  amdgpu_ttm_tt_get_user_pages+0xb1/0x150 [amdgpu]
+  init_user_pages+0xb1/0x2a0 [amdgpu]
+  amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu+0x543/0x7d0 [amdgpu]
+  kfd_ioctl_alloc_memory_of_gpu+0x24c/0x4e0 [amdgpu]
+  kfd_ioctl+0x29d/0x500 [amdgpu]
+
+Fixes: fa582c6f3684 ("drm/amdkfd: Use mmget_not_zero in MMU notifier")
+Signed-off-by: Philip Yang <Philip.Yang@amd.com>
+Reviewed-by: Felix Kuehling <felix.kuehling@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+(cherry picked from commit a29e067bd38946f752b0ef855f3dfff87e77bec7)
+Cc: stable@vger.kernel.org
+[ updated additional svm_range_add_child calls in svm_range_split_by_granularity to remove mm parameter ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/amd/amdkfd/kfd_svm.c |   47 ++++++++++++++++-------------------
+ 1 file changed, 22 insertions(+), 25 deletions(-)
+
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
+@@ -1076,13 +1076,12 @@ svm_range_split_head(struct svm_range *p
+ }
+ static void
+-svm_range_add_child(struct svm_range *prange, struct mm_struct *mm,
+-                  struct svm_range *pchild, enum svm_work_list_ops op)
++svm_range_add_child(struct svm_range *prange, struct svm_range *pchild, enum svm_work_list_ops op)
+ {
+       pr_debug("add child 0x%p [0x%lx 0x%lx] to prange 0x%p child list %d\n",
+                pchild, pchild->start, pchild->last, prange, op);
+-      pchild->work_item.mm = mm;
++      pchild->work_item.mm = NULL;
+       pchild->work_item.op = op;
+       list_add_tail(&pchild->child_list, &prange->child_list);
+ }
+@@ -1128,14 +1127,14 @@ svm_range_split_by_granularity(struct kf
+               r = svm_range_split(prange, start, prange->last, &head);
+               if (r)
+                       return r;
+-              svm_range_add_child(parent, mm, head, SVM_OP_ADD_RANGE);
++              svm_range_add_child(parent, head, SVM_OP_ADD_RANGE);
+       }
+       if (last < prange->last) {
+               r = svm_range_split(prange, prange->start, last, &tail);
+               if (r)
+                       return r;
+-              svm_range_add_child(parent, mm, tail, SVM_OP_ADD_RANGE);
++              svm_range_add_child(parent, tail, SVM_OP_ADD_RANGE);
+       }
+       /* xnack on, update mapping on GPUs with ACCESS_IN_PLACE */
+@@ -2265,15 +2264,17 @@ svm_range_add_list_work(struct svm_range
+                   prange->work_item.op != SVM_OP_UNMAP_RANGE)
+                       prange->work_item.op = op;
+       } else {
+-              prange->work_item.op = op;
+-
+-              /* Pairs with mmput in deferred_list_work */
+-              mmget(mm);
+-              prange->work_item.mm = mm;
+-              list_add_tail(&prange->deferred_list,
+-                            &prange->svms->deferred_range_list);
+-              pr_debug("add prange 0x%p [0x%lx 0x%lx] to work list op %d\n",
+-                       prange, prange->start, prange->last, op);
++              /* Pairs with mmput in deferred_list_work.
++               * If process is exiting and mm is gone, don't update mmu notifier.
++               */
++              if (mmget_not_zero(mm)) {
++                      prange->work_item.mm = mm;
++                      prange->work_item.op = op;
++                      list_add_tail(&prange->deferred_list,
++                                    &prange->svms->deferred_range_list);
++                      pr_debug("add prange 0x%p [0x%lx 0x%lx] to work list op %d\n",
++                               prange, prange->start, prange->last, op);
++              }
+       }
+       spin_unlock(&svms->deferred_list_lock);
+ }
+@@ -2287,8 +2288,7 @@ void schedule_deferred_list_work(struct
+ }
+ static void
+-svm_range_unmap_split(struct mm_struct *mm, struct svm_range *parent,
+-                    struct svm_range *prange, unsigned long start,
++svm_range_unmap_split(struct svm_range *parent, struct svm_range *prange, unsigned long start,
+                     unsigned long last)
+ {
+       struct svm_range *head;
+@@ -2309,12 +2309,12 @@ svm_range_unmap_split(struct mm_struct *
+               svm_range_split(tail, last + 1, tail->last, &head);
+       if (head != prange && tail != prange) {
+-              svm_range_add_child(parent, mm, head, SVM_OP_UNMAP_RANGE);
+-              svm_range_add_child(parent, mm, tail, SVM_OP_ADD_RANGE);
++              svm_range_add_child(parent, head, SVM_OP_UNMAP_RANGE);
++              svm_range_add_child(parent, tail, SVM_OP_ADD_RANGE);
+       } else if (tail != prange) {
+-              svm_range_add_child(parent, mm, tail, SVM_OP_UNMAP_RANGE);
++              svm_range_add_child(parent, tail, SVM_OP_UNMAP_RANGE);
+       } else if (head != prange) {
+-              svm_range_add_child(parent, mm, head, SVM_OP_UNMAP_RANGE);
++              svm_range_add_child(parent, head, SVM_OP_UNMAP_RANGE);
+       } else if (parent != prange) {
+               prange->work_item.op = SVM_OP_UNMAP_RANGE;
+       }
+@@ -2353,14 +2353,14 @@ svm_range_unmap_from_cpu(struct mm_struc
+               l = min(last, pchild->last);
+               if (l >= s)
+                       svm_range_unmap_from_gpus(pchild, s, l, trigger);
+-              svm_range_unmap_split(mm, prange, pchild, start, last);
++              svm_range_unmap_split(prange, pchild, start, last);
+               mutex_unlock(&pchild->lock);
+       }
+       s = max(start, prange->start);
+       l = min(last, prange->last);
+       if (l >= s)
+               svm_range_unmap_from_gpus(prange, s, l, trigger);
+-      svm_range_unmap_split(mm, prange, prange, start, last);
++      svm_range_unmap_split(prange, prange, start, last);
+       if (unmap_parent)
+               svm_range_add_list_work(svms, prange, mm, SVM_OP_UNMAP_RANGE);
+@@ -2403,8 +2403,6 @@ svm_range_cpu_invalidate_pagetables(stru
+       if (range->event == MMU_NOTIFY_RELEASE)
+               return true;
+-      if (!mmget_not_zero(mni->mm))
+-              return true;
+       start = mni->interval_tree.start;
+       last = mni->interval_tree.last;
+@@ -2431,7 +2429,6 @@ svm_range_cpu_invalidate_pagetables(stru
+       }
+       svm_range_unlock(prange);
+-      mmput(mni->mm);
+       return true;
+ }
index 5b3a2c5ebd1ebf005750412789525d03e9e411e2..5f772a76124efd78ece9986fadbabaf50ed60acb 100644 (file)
@@ -40,3 +40,7 @@ nilfs2-reject-invalid-file-types-when-reading-inodes.patch
 selftests-mptcp-connect-also-cover-alt-modes.patch
 selftests-mptcp-connect-also-cover-checksum.patch
 mm-zsmalloc-do-not-pass-__gfp_movable-if-config_compaction-n.patch
+drm-amdkfd-don-t-call-mmput-from-mmu-notifier-callback.patch
+usb-typec-tcpm-allow-to-use-sink-in-accessory-mode.patch
+usb-typec-tcpm-allow-switching-to-mode-accessory-to-mux-properly.patch
+usb-typec-tcpm-apply-vbus-before-data-bringup-in-tcpm_src_attach.patch
diff --git a/queue-6.1/usb-typec-tcpm-allow-switching-to-mode-accessory-to-mux-properly.patch b/queue-6.1/usb-typec-tcpm-allow-switching-to-mode-accessory-to-mux-properly.patch
new file mode 100644 (file)
index 0000000..102bfae
--- /dev/null
@@ -0,0 +1,120 @@
+From 8a50da849151e7e12b43c1d8fe7ad302223aef6b Mon Sep 17 00:00:00 2001
+From: Michael Grzeschik <m.grzeschik@pengutronix.de>
+Date: Fri, 4 Apr 2025 00:43:06 +0200
+Subject: usb: typec: tcpm: allow switching to mode accessory to mux properly
+
+From: Michael Grzeschik <m.grzeschik@pengutronix.de>
+
+commit 8a50da849151e7e12b43c1d8fe7ad302223aef6b upstream.
+
+The funciton tcpm_acc_attach is not setting the proper state when
+calling tcpm_set_role. The function tcpm_set_role is currently only
+handling TYPEC_STATE_USB. For the tcpm_acc_attach to switch into other
+modal states tcpm_set_role needs to be extended by an extra state
+parameter. This patch is handling the proper state change when calling
+tcpm_acc_attach.
+
+Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
+Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Link: https://lore.kernel.org/r/20250404-ml-topic-tcpm-v1-3-b99f44badce8@pengutronix.de
+Stable-dep-of: bec15191d523 ("usb: typec: tcpm: apply vbus before data bringup in tcpm_src_attach")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/typec/tcpm/tcpm.c |   27 ++++++++++++++++++---------
+ 1 file changed, 18 insertions(+), 9 deletions(-)
+
+--- a/drivers/usb/typec/tcpm/tcpm.c
++++ b/drivers/usb/typec/tcpm/tcpm.c
+@@ -1032,7 +1032,7 @@ static int tcpm_set_attached_state(struc
+                                    port->data_role);
+ }
+-static int tcpm_set_roles(struct tcpm_port *port, bool attached,
++static int tcpm_set_roles(struct tcpm_port *port, bool attached, int state,
+                         enum typec_role role, enum typec_data_role data)
+ {
+       enum typec_orientation orientation;
+@@ -1069,7 +1069,7 @@ static int tcpm_set_roles(struct tcpm_po
+               }
+       }
+-      ret = tcpm_mux_set(port, TYPEC_STATE_USB, usb_role, orientation);
++      ret = tcpm_mux_set(port, state, usb_role, orientation);
+       if (ret < 0)
+               return ret;
+@@ -3686,7 +3686,8 @@ static int tcpm_src_attach(struct tcpm_p
+       tcpm_enable_auto_vbus_discharge(port, true);
+-      ret = tcpm_set_roles(port, true, TYPEC_SOURCE, tcpm_data_role_for_source(port));
++      ret = tcpm_set_roles(port, true, TYPEC_STATE_USB,
++                           TYPEC_SOURCE, tcpm_data_role_for_source(port));
+       if (ret < 0)
+               return ret;
+@@ -3844,7 +3845,8 @@ static int tcpm_snk_attach(struct tcpm_p
+       tcpm_enable_auto_vbus_discharge(port, true);
+-      ret = tcpm_set_roles(port, true, TYPEC_SINK, tcpm_data_role_for_sink(port));
++      ret = tcpm_set_roles(port, true, TYPEC_STATE_USB,
++                           TYPEC_SINK, tcpm_data_role_for_sink(port));
+       if (ret < 0)
+               return ret;
+@@ -3868,6 +3870,7 @@ static int tcpm_acc_attach(struct tcpm_p
+       int ret;
+       enum typec_role role;
+       enum typec_data_role data;
++      int state = TYPEC_STATE_USB;
+       if (port->attached)
+               return 0;
+@@ -3876,7 +3879,13 @@ static int tcpm_acc_attach(struct tcpm_p
+       data = tcpm_port_is_sink(port) ? tcpm_data_role_for_sink(port)
+                                      : tcpm_data_role_for_source(port);
+-      ret = tcpm_set_roles(port, true, role, data);
++      if (tcpm_port_is_audio(port))
++              state = TYPEC_MODE_AUDIO;
++
++      if (tcpm_port_is_debug(port))
++              state = TYPEC_MODE_DEBUG;
++
++      ret = tcpm_set_roles(port, true, state, role, data);
+       if (ret < 0)
+               return ret;
+@@ -4556,7 +4565,7 @@ static void run_state_machine(struct tcp
+                */
+               tcpm_set_vconn(port, false);
+               tcpm_set_vbus(port, false);
+-              tcpm_set_roles(port, port->self_powered, TYPEC_SOURCE,
++              tcpm_set_roles(port, port->self_powered, TYPEC_STATE_USB, TYPEC_SOURCE,
+                              tcpm_data_role_for_source(port));
+               /*
+                * If tcpc fails to notify vbus off, TCPM will wait for PD_T_SAFE_0V +
+@@ -4588,7 +4597,7 @@ static void run_state_machine(struct tcp
+               tcpm_set_vconn(port, false);
+               if (port->pd_capable)
+                       tcpm_set_charge(port, false);
+-              tcpm_set_roles(port, port->self_powered, TYPEC_SINK,
++              tcpm_set_roles(port, port->self_powered, TYPEC_STATE_USB, TYPEC_SINK,
+                              tcpm_data_role_for_sink(port));
+               /*
+                * VBUS may or may not toggle, depending on the adapter.
+@@ -4693,10 +4702,10 @@ static void run_state_machine(struct tcp
+       case DR_SWAP_CHANGE_DR:
+               tcpm_unregister_altmodes(port);
+               if (port->data_role == TYPEC_HOST)
+-                      tcpm_set_roles(port, true, port->pwr_role,
++                      tcpm_set_roles(port, true, TYPEC_STATE_USB, port->pwr_role,
+                                      TYPEC_DEVICE);
+               else
+-                      tcpm_set_roles(port, true, port->pwr_role,
++                      tcpm_set_roles(port, true, TYPEC_STATE_USB, port->pwr_role,
+                                      TYPEC_HOST);
+               tcpm_ams_finish(port);
+               tcpm_set_state(port, ready_state(port), 0);
diff --git a/queue-6.1/usb-typec-tcpm-allow-to-use-sink-in-accessory-mode.patch b/queue-6.1/usb-typec-tcpm-allow-to-use-sink-in-accessory-mode.patch
new file mode 100644 (file)
index 0000000..c000241
--- /dev/null
@@ -0,0 +1,44 @@
+From 64843d0ba96d3eae297025562111d57585273366 Mon Sep 17 00:00:00 2001
+From: Michael Grzeschik <m.grzeschik@pengutronix.de>
+Date: Fri, 4 Apr 2025 00:43:04 +0200
+Subject: usb: typec: tcpm: allow to use sink in accessory mode
+
+From: Michael Grzeschik <m.grzeschik@pengutronix.de>
+
+commit 64843d0ba96d3eae297025562111d57585273366 upstream.
+
+Since the function tcpm_acc_attach is not setting the data and role for
+for the sink case we extend it to check for it first.
+
+Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
+Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Link: https://lore.kernel.org/r/20250404-ml-topic-tcpm-v1-1-b99f44badce8@pengutronix.de
+Stable-dep-of: bec15191d523 ("usb: typec: tcpm: apply vbus before data bringup in tcpm_src_attach")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/typec/tcpm/tcpm.c |    9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/typec/tcpm/tcpm.c
++++ b/drivers/usb/typec/tcpm/tcpm.c
+@@ -3866,12 +3866,17 @@ static void tcpm_snk_detach(struct tcpm_
+ static int tcpm_acc_attach(struct tcpm_port *port)
+ {
+       int ret;
++      enum typec_role role;
++      enum typec_data_role data;
+       if (port->attached)
+               return 0;
+-      ret = tcpm_set_roles(port, true, TYPEC_SOURCE,
+-                           tcpm_data_role_for_source(port));
++      role = tcpm_port_is_sink(port) ? TYPEC_SINK : TYPEC_SOURCE;
++      data = tcpm_port_is_sink(port) ? tcpm_data_role_for_sink(port)
++                                     : tcpm_data_role_for_source(port);
++
++      ret = tcpm_set_roles(port, true, role, data);
+       if (ret < 0)
+               return ret;
diff --git a/queue-6.1/usb-typec-tcpm-apply-vbus-before-data-bringup-in-tcpm_src_attach.patch b/queue-6.1/usb-typec-tcpm-apply-vbus-before-data-bringup-in-tcpm_src_attach.patch
new file mode 100644 (file)
index 0000000..5498936
--- /dev/null
@@ -0,0 +1,101 @@
+From bec15191d52300defa282e3fd83820f69e447116 Mon Sep 17 00:00:00 2001
+From: RD Babiera <rdbabiera@google.com>
+Date: Wed, 18 Jun 2025 23:06:04 +0000
+Subject: usb: typec: tcpm: apply vbus before data bringup in tcpm_src_attach
+
+From: RD Babiera <rdbabiera@google.com>
+
+commit bec15191d52300defa282e3fd83820f69e447116 upstream.
+
+This patch fixes Type-C compliance test TD 4.7.6 - Try.SNK DRP Connect
+SNKAS.
+
+tVbusON has a limit of 275ms when entering SRC_ATTACHED. Compliance
+testers can interpret the TryWait.Src to Attached.Src transition after
+Try.Snk as being in Attached.Src the entire time, so ~170ms is lost
+to the debounce timer.
+
+Setting the data role can be a costly operation in host mode, and when
+completed after 100ms can cause Type-C compliance test check TD 4.7.5.V.4
+to fail.
+
+Turn VBUS on before tcpm_set_roles to meet timing requirement.
+
+Fixes: f0690a25a140 ("staging: typec: USB Type-C Port Manager (tcpm)")
+Cc: stable <stable@kernel.org>
+Signed-off-by: RD Babiera <rdbabiera@google.com>
+Reviewed-by: Badhri Jagan Sridharan <badhri@google.com>
+Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Link: https://lore.kernel.org/r/20250618230606.3272497-2-rdbabiera@google.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/typec/tcpm/tcpm.c |   34 +++++++++++++++++-----------------
+ 1 file changed, 17 insertions(+), 17 deletions(-)
+
+--- a/drivers/usb/typec/tcpm/tcpm.c
++++ b/drivers/usb/typec/tcpm/tcpm.c
+@@ -3686,17 +3686,6 @@ static int tcpm_src_attach(struct tcpm_p
+       tcpm_enable_auto_vbus_discharge(port, true);
+-      ret = tcpm_set_roles(port, true, TYPEC_STATE_USB,
+-                           TYPEC_SOURCE, tcpm_data_role_for_source(port));
+-      if (ret < 0)
+-              return ret;
+-
+-      if (port->pd_supported) {
+-              ret = port->tcpc->set_pd_rx(port->tcpc, true);
+-              if (ret < 0)
+-                      goto out_disable_mux;
+-      }
+-
+       /*
+        * USB Type-C specification, version 1.2,
+        * chapter 4.5.2.2.8.1 (Attached.SRC Requirements)
+@@ -3706,13 +3695,24 @@ static int tcpm_src_attach(struct tcpm_p
+           (polarity == TYPEC_POLARITY_CC2 && port->cc1 == TYPEC_CC_RA)) {
+               ret = tcpm_set_vconn(port, true);
+               if (ret < 0)
+-                      goto out_disable_pd;
++                      return ret;
+       }
+       ret = tcpm_set_vbus(port, true);
+       if (ret < 0)
+               goto out_disable_vconn;
++      ret = tcpm_set_roles(port, true, TYPEC_STATE_USB, TYPEC_SOURCE,
++                           tcpm_data_role_for_source(port));
++      if (ret < 0)
++              goto out_disable_vbus;
++
++      if (port->pd_supported) {
++              ret = port->tcpc->set_pd_rx(port->tcpc, true);
++              if (ret < 0)
++                      goto out_disable_mux;
++      }
++
+       port->pd_capable = false;
+       port->partner = NULL;
+@@ -3722,14 +3722,14 @@ static int tcpm_src_attach(struct tcpm_p
+       return 0;
+-out_disable_vconn:
+-      tcpm_set_vconn(port, false);
+-out_disable_pd:
+-      if (port->pd_supported)
+-              port->tcpc->set_pd_rx(port->tcpc, false);
+ out_disable_mux:
+       tcpm_mux_set(port, TYPEC_STATE_SAFE, USB_ROLE_NONE,
+                    TYPEC_ORIENTATION_NONE);
++out_disable_vbus:
++      tcpm_set_vbus(port, false);
++out_disable_vconn:
++      tcpm_set_vconn(port, false);
++
+       return ret;
+ }