forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 141
Fix/atcphy pipehandler #503
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
milijan
wants to merge
2
commits into
AsahiLinux:asahi
Choose a base branch
from
milijan:fix/atcphy-pipehandler
base: asahi
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+36
−13
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -922,23 +922,25 @@ static void atcphy_apply_tunables(struct apple_atcphy *atcphy, enum atcphy_mode | |
|
|
||
| static int atcphy_pipehandler_lock(struct apple_atcphy *atcphy) | ||
| { | ||
| int ret; | ||
| int ret, retries = 10; | ||
| u32 reg; | ||
|
|
||
| if (readl(atcphy->regs.pipehandler + PIPEHANDLER_LOCK_REQ) & PIPEHANDLER_LOCK_EN) { | ||
| dev_warn(atcphy->dev, "Pipehandler already locked\n"); | ||
| return 0; | ||
| } | ||
|
|
||
| set32(atcphy->regs.pipehandler + PIPEHANDLER_LOCK_REQ, PIPEHANDLER_LOCK_EN); | ||
|
|
||
| ret = readl_poll_timeout(atcphy->regs.pipehandler + PIPEHANDLER_LOCK_ACK, reg, | ||
| reg & PIPEHANDLER_LOCK_EN, 10, PIPEHANDLER_LOCK_ACK_TIMEOUT_US); | ||
| if (ret) { | ||
| clear32(atcphy->regs.pipehandler + PIPEHANDLER_LOCK_REQ, 1); | ||
| dev_warn(atcphy->dev, "Pipehandler lock not acked.\n"); | ||
| } | ||
| do { | ||
| set32(atcphy->regs.pipehandler + PIPEHANDLER_LOCK_REQ, PIPEHANDLER_LOCK_EN); | ||
| ret = readl_poll_timeout(atcphy->regs.pipehandler + PIPEHANDLER_LOCK_ACK, reg, | ||
| reg & PIPEHANDLER_LOCK_EN, 10, PIPEHANDLER_LOCK_ACK_TIMEOUT_US); | ||
| if (!ret) | ||
| return 0; | ||
| clear32(atcphy->regs.pipehandler + PIPEHANDLER_LOCK_REQ, PIPEHANDLER_LOCK_EN); | ||
| usleep_range(5000, 10000); | ||
| } while (--retries); | ||
|
|
||
| dev_warn(atcphy->dev, "Pipehandler lock not acked.\n"); | ||
| return ret; | ||
| } | ||
|
|
||
|
|
@@ -2081,6 +2083,7 @@ static int atcphy_mux_set(struct typec_mux_dev *mux, struct typec_mux_state *sta | |
| { | ||
| struct apple_atcphy *atcphy = typec_mux_get_drvdata(mux); | ||
| enum atcphy_mode target_mode; | ||
| int ret; | ||
|
|
||
| guard(mutex)(&atcphy->lock); | ||
|
|
||
|
|
@@ -2138,11 +2141,31 @@ static int atcphy_mux_set(struct typec_mux_dev *mux, struct typec_mux_state *sta | |
| return 0; | ||
|
|
||
| /* | ||
| * If the pipehandler is still/already up here there's a bug somewhere so make sure to | ||
| * complain loudly. We can still try to switch modes and hope for the best though, | ||
| * in the worst case the hardware will fall back to USB2-only. | ||
| * If the pipehandler is still up and the target mode uses the dummy PIPE | ||
| * state (DP, USB2, TBT, OFF), tear it down before reconfiguring the lanes. | ||
| * Normally atcphy_usb3_power_off() does this, but a TypeC mux switch to | ||
| * DP alt mode can race the DWC3 PHY teardown on hotplug. By the time the | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. how does this race actually happen? can you describe this in more detail? the fix here may be correct but I want to be sure we can't fix this at another level (e.g. the type c controller) |
||
| * kernel TypeC stack reaches here the USB PD Enter_Mode handshake is | ||
| * complete and the SS lanes are already being repurposed, so switching the | ||
| * pipehandler to dummy is safe even if DWC3 has not yet called phy_power_off. | ||
| */ | ||
| if (atcphy->pipehandler_up && | ||
| atcphy_modes[target_mode].pipehandler_state == ATCPHY_PIPEHANDLER_STATE_DUMMY) { | ||
| ret = atcphy_configure_pipehandler_dummy(atcphy); | ||
| if (ret) | ||
| dev_warn(atcphy->dev, | ||
| "Failed to clear pipehandler before mode switch: %d\n", ret); | ||
| else | ||
| atcphy->pipehandler_up = false; | ||
| } | ||
|
|
||
| /* | ||
| * For modes that keep the pipehandler in USB3 state (e.g. USB3_DP), | ||
| * pipehandler_up being true here is expected and correct. Only warn | ||
| * if we tried to tear down the pipehandler above but failed. | ||
| */ | ||
| WARN_ON_ONCE(atcphy->pipehandler_up); | ||
| WARN_ON_ONCE(atcphy->pipehandler_up && | ||
| atcphy_modes[target_mode].pipehandler_state == ATCPHY_PIPEHANDLER_STATE_DUMMY); | ||
| return atcphy_configure(atcphy, target_mode); | ||
| } | ||
|
|
||
|
|
||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've never seen macos do this in traces and I highly suspect we're doing something else that's wrong here. have you seen this in traces or is this something you worked out by just playing with the hardware?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly try and error. My use case is using an M1 air in clamshell mode with fedora remix server (low idle power compute node for my homelab). So I need an Ethernet adapter. While it works fine when Hot Plugging the adapter, it fails on reboot (no phy detected/initialised). This was a defensive retry code attempt that seemed to work. But I agree with you something else is going on. Further testing shows that it is not reliable and if I removed some debug traces it would change the timing and fail again. Will probably move this issue to the forum before making further changes. Need to also understand some iboot behaviour differences between m1 and newer chips and assumptions made for how long it takes to load necessary firmwares. Thanks for reviewing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, that's what I was afraid of :( atcphy shouldn't have any firmware fwiw
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes but some usb hubs also have an external display (dcpext) which requires some lane allocation, initialisation and firmware (video modes). Not sure how all this is orchestrated to work in a generic way for typeC hubs in non-macOS and macOS systems. Any idea?