All of lore.kernel.org
 help / color / mirror / Atom feed
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

             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.