From: Ismail Tarim <ismailtarim7@gmail.com>
To: linux-usb@vger.kernel.org
Cc: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Subject: [BUG] ucsi_acpi: unstable GET_ALTERNATE_MODES(SOP) response prevents DP Alt Mode binding on ASUS K3605ZV
Date: Mon, 7 Sep 2026 20:18:42 +0300 [thread overview]
Message-ID: <20260907171909.1657882-1-ismailtarim7@gmail.com> (raw)
Hi,
On an ASUS Vivobook K3605ZV (Alder Lake-P, UCSI over ACPI), USB-C
DisplayPort Alt Mode is never established on hot-plug, while attaching
the cable before boot gives a working display.
Repeated GET_ALTERNATE_MODES queries for the SOP recipient return two
different six-byte payloads in exact alternation. Under the record
layout Linux expects, these produce two distinct driver-visible failure
modes, but they may well have a single underlying ordering or
serialisation cause - I describe an alternative reading of the same
bytes below and I cannot currently decide between them.
The payload instability is reproducible through UCSI debugfs without a
patched kernel. I used a kretprobe on ucsi_send_command() only to
confirm that the CCI data length was 6 on every call.
System
------
Machine ASUSTeK Vivobook_ASUSLaptop K3605ZV_K3605ZV
BIOS K3605ZV.317, 05/12/2026
CPU Intel Core i7-12650H (Alder Lake-P)
Kernel 7.2.3 (Arch), CONFIG_TYPEC_UCSI=m, CONFIG_UCSI_ACPI=m,
CONFIG_TYPEC_DP_ALTMODE=m
UCSI transport ucsi_acpi, platform device USBC000:00
Type-C port port0, data role host, bound to usb3-port3,
usb2-port1 and usb4_port1 (connector_ops [thunderbolt])
Display sink Gigabyte M27UA (3840x2160). Connected with a cable
whose DisplayPort end plugs into the monitor and whose
USB-C end plugs into the laptop, so the laptop is the
DP source over USB-C.
External DRM all on the Intel iGPU (card1: DP-1, DP-2, HDMI-A-1)
Loaded Type-C modules: typec, typec_ucsi, ucsi_acpi, typec_displayport,
roles, thunderbolt. I can supply GET_CAPABILITY output or anything else
on request.
Symptom
-------
Hot-plugging the USB-C cable never brings up DP-1: the connector stays
"disconnected" with a 0-byte EDID and typec_displayport binds to
nothing.
In a controlled test, attaching the same cable before boot resulted in
a working 3840x2160 display. Separately, 71 retained boot journals
report DP-1 connected; those historical records do not by themselves
establish the attachment sequence for each boot.
Observation 1: the SOP payload alternates between two values
------------------------------------------------------------
Issuing the same GET_ALTERNATE_MODES(recipient=SOP, connector=1,
offset=0) repeatedly through /sys/kernel/debug/usb/ucsi/USBC000:00/
returns two payloads in strict alternation. 40 reads per inter-call
spacing, 120 reads in one continuous run, zero deviation:
back-to-back : ABABABABABABABABABABABABABABABABABABABAB
200 ms apart : ABABABABABABABABABABABABABABABABABABABAB
1 s apart : ABABABABABABABABABABABABABABABABABABABAB
A = 01 ff 00 00 01 ff
B = 05 04 00 00 01 ff
Only bytes 0..1 differ; bytes 2..5 are identical. Every one of the 120
calls returned a CCI data length of 6.
The corresponding query with recipient=CON returned one identical
six-byte response in 40 reads. So the alternation was not observed in
this same-sized control, though that does not by itself locate the
fault between the PPM and the ACPI transport.
Limitation of the spacing test: the response stays locked to
transaction parity across the tested 0-1 s inter-call intervals, which
makes a simple wall-clock or probabilistic race less likely. It does
NOT distinguish PPM payload state from a deterministic
completion/ACK/MESSAGE_IN ordering problem, because those delays occur
after ucsi_send_command() has already read MESSAGE_IN. Testing that
boundary would need a delay between command completion and
read_message_in(), or two reads of MESSAGE_IN after a single
completion. Also, the three blocks were consecutive and of even length,
so they are effectively one 120-call sequence rather than three
independent phase trials.
The second value is not constant across attachments: in an attach
session five minutes earlier it was 0a 00 00 00 01 ff instead of
05 04 00 00 01 ff. It was stable within each session.
Observation 2: two readings of the same bytes
---------------------------------------------
Parsed as the packed record Linux uses,
struct ucsi_altmode { u16 svid; u32 mid; } __packed :
A -> svid=0xff01 mid=0xff010000
B -> svid=0x0405 mid=0xff010000
(earlier session) -> svid=0x000a mid=0xff010000
so the SVID alternates and the MID is constant but useless as a DP
capability VDO.
Parsed with the two members in the opposite order, { u32 mid; u16 svid }:
A -> mid=0x0000ff01 svid=0xff01
B -> mid=0x00000405 svid=0xff01
(earlier session) -> mid=0x0000000a svid=0xff01
Under that reading the SVID is 0xff01 in every payload I have ever
captured, and it is the MID that alternates. 0x00000405 decodes as a
plausible DP sink capability: UFP_D capable, DP v1.3 signalling, UFP_D
pin assignment C. 0x0000ff01 looks instead like the SVID duplicated
into the MID slot.
I cannot decide between these. The CON record is unambiguously in the
Linux/UCSI order (reading it reversed yields svid=0x0000, i.e. an
end-of-list marker, which is nonsense given it is the DP mode), so the
producer is at least inconsistent between recipients under the reversed
hypothesis. Bytes past the CCI length of 6 are not part of the response
and cannot disambiguate it.
Effect on the driver
--------------------
ucsi_register_altmodes() registers whichever payload it happened to
read, and the SOP early-out
if (recipient == UCSI_RECIPIENT_SOP && con->partner_altmode[0])
return 0;
then prevents any further read for the lifetime of the partner, so the
first result is latched.
If the registered SVID is not 0xff01, the Type-C bus match against
typec_displayport's typec:idFF01 alias never succeeds and
dp_altmode_probe() is not reached. This is the state after a hot-plug,
captured before I issued any debugfs command, so it is not an artefact
of my probing:
/sys/class/typec/port0-partner/port0-partner.0/svid = 0405
/sys/class/typec/port0-partner/port0-partner.0/vdo = 0xff010000
/sys/class/typec/port0-partner/port0-partner.0/driver : absent
/sys/class/drm/card1-DP-1/status : disconnected
If instead the payload with svid=0xff01 is registered, the driver
matches but dp_altmode_probe() rejects it. With port0.0/vdo =
0x001c1c46 and the partner VDO as Linux parses it (0xff010000, whose
raw DFP_D pin-assignment field bits 15:8 = 0x00 and raw UFP_D
pin-assignment field bits 23:16 = 0x01, with the receptacle bit clear,
giving Linux's helper results UFP_D=0x00 and DFP_D=0x01):
DP_CAP_PIN_ASSIGN_DFP_D(0x001c1c46) & DP_CAP_PIN_ASSIGN_UFP_D(0xff010000)
= 0x1c & 0x00 = 0
DP_CAP_PIN_ASSIGN_UFP_D(0x001c1c46) & DP_CAP_PIN_ASSIGN_DFP_D(0xff010000)
= 0x1c & 0x01 = 0
-> -ENODEV
So neither of the two alternating payloads leads to a bound DP alt
mode.
For reference, the raw CON response to the same command is
01 ff 06 1c 00 00 len=6
and ucsi_register_displayport() turns mid=0x00001c06 into
0x1c06 | DP_CAP_RECEPTACLE | 0x1c<<8 | 0x1c<<16 = 0x001c1c46, which is
what port0.0/vdo reads. That sanity-checks my byte decoding and shows
how the current kernel transforms the CON record; it does not establish
that the SOP producer uses the same member ordering.
Other observations
------------------
* The PPM returned one six-byte record at offset 0 and zero length at
offsets 1 and 2.
* After a hot-plug, GET_CURRENT_CAM(connector=1) returned 0x01 rather
than the 0xff "none" sentinel, while GET_CAM_SUPPORTED returned
0x01. Those two are mutually inconsistent under Linux's zero-based
index interpretation. I mention it only as a further sign that this
PPM's alt-mode reporting is unreliable.
* No intel_pmc_mux device can bind on this firmware: neither INTC105C
nor the Alder Lake IOM INTC1079 is present in ACPI, and
/sys/class/typec_mux is empty. I therefore do not know whether
correcting the alt-mode registration alone would be enough to light
the display, or whether the PPM would also have to be driven into
the CAM.
Regression status: not established
----------------------------------
The user-visible history is that hot-plug used to work, so I looked for
a kernel change.
The relevant struct ucsi_altmode layout and the dp_altmode_probe()
rejection logic are unchanged across every kernel this machine has run
(v7.0.5 through v7.2.3), and I found no direct change to the UCSI
alt-mode read path between 7.1.9 and 7.2.3 - the changes there are the
msg_out/write_message_out plumbing, an unregister refactor and lockdep
annotations.
This is only a source audit. Indirect timing or ordering changes
elsewhere, and firmware state, remain possible. I have not yet run the
same unplugged-boot-then-hot-plug procedure under an older kernel, so I
am not claiming a regression and I have not copied
regressions@lists.linux.dev.
Reproduction
------------
With the cable attached, as root:
D=/sys/kernel/debug/usb/ucsi/USBC000:00
for i in $(seq 1 10); do
echo 0x101000c > $D/command # GET_ALTERNATE_MODES, SOP, con 1, off 0
cat $D/response
done
The responses alternate. Substituting 0x100000c (recipient CON) gives a
stable response. The debugfs "status" file only records negative
errors, so the positive return value (the data length) is not exposed
there; I used a kretprobe on ucsi_send_command() for that.
Questions
---------
1. Has an SOP-only member ordering, or an alternating offset-0
response, been seen from other UCSI PPMs? Is there a reading of
these six bytes that I have missed?
2. Which capture would best distinguish PPM payload corruption from
an ACPI completion/MESSAGE_IN ordering problem: a debug patch that
delays or repeats read_message_in() after a single completion, a
PD Discover Modes trace from an analyser, or data from the working
boot-attached case?
3. If the correct partner record can be established independently,
would a DMI-scoped fixup in ucsi_acpi's sync_control be the right
layer, or should this stay a firmware-only issue?
I have the machine available and am happy to run debug patches or
further captures.
Thanks,
Ismail Tarim
next reply other threads:[~2026-09-07 17:20 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-07 17:18 Ismail Tarim [this message]
2026-09-09 13:59 ` [BUG] ucsi_acpi: unstable GET_ALTERNATE_MODES(SOP) response prevents DP Alt Mode binding on ASUS K3605ZV Heikki Krogerus
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260907171909.1657882-1-ismailtarim7@gmail.com \
--to=ismailtarim7@gmail.com \
--cc=heikki.krogerus@linux.intel.com \
--cc=linux-usb@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.