usb: typec: class: fix typec_altmode_put_partner to put plugs
Subsystems (3)
PATCH v4 1/1 usb: typec: class: fix typec_altmode_put_partner to put plugs
When typec_altmode_put_partner is called by a plug altmode upon release, the port altmode the plug belongs to will not remove its reference to the plug. The check to see if the altmode being released is a plug evaluates against the released altmode's partner instead of the calling altmode, so change adev in typec_altmode_put_partner to properly refer to the altmode being released.
Because typec_altmode_set_partner calls get_device() on the port altmode, add partner_adev that points to the port altmode in typec_put_partner to call put_device() on. typec_altmode_set_partner is not called for port altmodes, so add a check in typec_altmode_release to prevent typec_altmode_put_partner() calls on port altmode release.
---
Changes since v3:
* added partner_adev to properly put_device() on port altmode.
--- drivers/usb/typec/class.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
drivers/usb/typec/class.c +6 -3
@@ -263,11 +263,13 @@ static void typec_altmode_put_partner(struct altmode *altmode) {struct altmode *partner = altmode->partner;struct typec_altmode *adev; +struct typec_altmode *partner_adev;if (!partner)return ; - adev = &partner->adev; + adev = &altmode->adev; + partner_adev = &partner->adev;if (is_typec_plug (adev->dev.parent)) {struct typec_plug *plug =to_typec_plug (adev->dev.parent);
@@ -276,7 +278,7 @@ static void typec_altmode_put_partner(struct altmode *altmode) }else { partner->partner =NULL ; } -put_device (&adev->dev); +put_device (&partner_adev->dev); }/**
@@ -497,7 +499,8 @@ static void typec_altmode_release(struct device *dev) {struct altmode *alt =to_altmode (to_typec_altmode (dev)); -typec_altmode_put_partner (alt); +if (!is_typec_port (dev->parent)) +typec_altmode_put_partner (alt);altmode_id_remove (alt->adev.dev.parent, alt->id);kfree (alt);
base-commit: e7d3b9f28654dbfce7e09f8028210489adaf6a33
Signature · 1 line
2.43.0.472.g3155946c3a-goog
Quoted 13 lines · RD Babiera
When
typec_altmode_put_partneris called by a plug altmode upon release, the port altmode the plug belongs to will not remove its reference to the plug. The check to see if the altmode being released is a plug evaluates against the released altmode's partner instead of the calling altmode, so change adev intypec_altmode_put_partnerto properly refer to the altmode being released.Because
typec_altmode_set_partnercallsget_device()on the port altmode, addpartner_adevthat points to the port altmode intypec_put_partnerto callput_device()on.typec_altmode_set_partneris not called for port altmodes, so add a check intypec_altmode_releaseto preventtypec_altmode_put_partner()calls on port altmode release.
Quoted 5 lines
Fixes 8a37d87d72f0 ("usb: typec: Bus type for alternate modes")Co-developed-by Christian A. Ehrhardt <[email protected]>Signed-off-by Christian A. Ehrhardt <[email protected]>Signed-off-by RD Babiera <[email protected]>
I was able to reproduce the bug of the original report from here
https://lore.kernel.org/all/CAP-bSRb3SXpgo_BEdqZB-p1K5625fMegRZ17ZkPE1J8ZYgEHDg@mail.gmail.com/
(with some hacks) and verified that this change on top of a revert of b17b7fe6dd (already in linux-usb) fixes the original bug. The test does not excercise the code that deals with cable plugs, though. Thus:
Given that this is otherwise a 6.7 regression it might be a good idea to consider this for 6.7?
Quoted 46 lines
---
Changes since v3:
* addedpartner_adevto properlyput_device()on port altmode.--- drivers/usb/typec/class.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)drivers/usb/typec/class.c +6
-3@@ -263,11 +263,13 @@ static void typec_altmode_put_partner(struct altmode *altmode) {struct altmode *partner = altmode->partner;struct typec_altmode *adev; +struct typec_altmode *partner_adev;if (!partner)return ; - adev = &partner->adev; + adev = &altmode->adev; + partner_adev = &partner->adev;if (is_typec_plug (adev->dev.parent)) {struct typec_plug *plug =to_typec_plug (adev->dev.parent);@@ -276,7 +278,7 @@ static void typec_altmode_put_partner(struct altmode *altmode) }else { partner->partner =NULL ; } -put_device (&adev->dev); +put_device (&partner_adev->dev); }/** @@ -497,7 +499,8 @@ static void typec_altmode_release(struct device *dev) {struct altmode *alt =to_altmode (to_typec_altmode (dev)); -typec_altmode_put_partner (alt); +if (!is_typec_port (dev->parent)) +typec_altmode_put_partner (alt);altmode_id_remove (alt->adev.dev.parent, alt->id);kfree (alt);
Quoted 5 lines
base-commit:
e7d3b9f28654dbfce7e09f8028210489adaf6a33Signature · 1 line
2.43.0.472.g3155946c3a-goog
regards Christian
Quoted 13 lines · RD Babiera
When
typec_altmode_put_partneris called by a plug altmode upon release, the port altmode the plug belongs to will not remove its reference to the plug. The check to see if the altmode being released is a plug evaluates against the released altmode's partner instead of the calling altmode, so change adev intypec_altmode_put_partnerto properly refer to the altmode being released.Because
typec_altmode_set_partnercallsget_device()on the port altmode, addpartner_adevthat points to the port altmode intypec_put_partnerto callput_device()on.typec_altmode_set_partneris not called for port altmodes, so add a check intypec_altmode_releaseto preventtypec_altmode_put_partner()calls on port altmode release.
Quoted 5 lines
Fixes 8a37d87d72f0 ("usb: typec: Bus type for alternate modes")Co-developed-by Christian A. Ehrhardt <[email protected]>Signed-off-by Christian A. Ehrhardt <[email protected]>Signed-off-by RD Babiera <[email protected]>
Quoted 49 lines
---
Changes since v3:
* addedpartner_adevto properlyput_device()on port altmode.--- drivers/usb/typec/class.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)drivers/usb/typec/class.c +6
-3@@ -263,11 +263,13 @@ static void typec_altmode_put_partner(struct altmode *altmode) {struct altmode *partner = altmode->partner;struct typec_altmode *adev; +struct typec_altmode *partner_adev;if (!partner)return ; - adev = &partner->adev; + adev = &altmode->adev; + partner_adev = &partner->adev;if (is_typec_plug (adev->dev.parent)) {struct typec_plug *plug =to_typec_plug (adev->dev.parent);@@ -276,7 +278,7 @@ static void typec_altmode_put_partner(struct altmode *altmode) }else { partner->partner =NULL ; } -put_device (&adev->dev); +put_device (&partner_adev->dev); }/** @@ -497,7 +499,8 @@ static void typec_altmode_release(struct device *dev) {struct altmode *alt =to_altmode (to_typec_altmode (dev)); -typec_altmode_put_partner (alt); +if (!is_typec_port (dev->parent)) +typec_altmode_put_partner (alt);altmode_id_remove (alt->adev.dev.parent, alt->id);kfree (alt);base-commit:
e7d3b9f28654dbfce7e09f8028210489adaf6a33Signature · 1 line
2.43.0.472.g3155946c3a-goog
Signature · 1 line
heikki