From: Heikki Krogerus <heikki.krogerus@linux.intel.com>
To: "Chia-Lin Kao (AceLan)" <acelan.kao@canonical.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
Andrei Kuchynski <akuchynski@chromium.org>,
Johan Hovold <johan@kernel.org>,
Jameson Thies <jthies@google.com>,
Pooja Katiyar <pooja.katiyar@intel.com>,
Hsin-Te Yuan <yuanhsinte@chromium.org>,
Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>,
linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH v7 1/3] usb: typec: ucsi: Detect and skip duplicate altmodes from buggy firmware
Date: Mon, 13 Jul 2026 12:53:59 +0300 [thread overview]
Message-ID: <alS1tywaoP_0ECVl@kuha> (raw)
In-Reply-To: <20260713084323.287516-1-acelan.kao@canonical.com>
On Mon, Jul 13, 2026 at 04:43:21PM +0800, Chia-Lin Kao (AceLan) wrote:
> Some firmware implementations incorrectly return the same altmode
> multiple times at different offsets when queried via
> UCSI_GET_ALTERNATE_MODES. This causes sysfs duplicate filename errors
> and kernel call traces when the driver attempts to register the same
> altmode twice:
>
> sysfs: cannot create duplicate filename '/devices/.../typec/port0/port0.0/partner'
> typec-thunderbolt port0-partner.1: failed to create symlinks
> typec-thunderbolt port0-partner.1: probe with driver typec-thunderbolt failed with error -17
>
> The matching rules differ by recipient:
>
> - UCSI_RECIPIENT_CON (port) and UCSI_RECIPIENT_SOP_P (plug):
> Two altmodes with identical SVID and VDO are byte-for-byte
> duplicates and the second has no observable function, so drop it.
>
> - UCSI_RECIPIENT_SOP (partner):
> The typec class binds each partner altmode to a port altmode of
> the same SVID via altmode_match()/device_find_child(), which
> returns the first port altmode with a matching SVID. If the
> partner advertises more altmodes for SVID X than the port
> advertises, the surplus partner altmode(s) collapse onto an
> already-paired port altmode and trigger the
> "duplicate filename .../partner" sysfs error during
> typec_altmode_create_links(). Use the port-side altmode count for
> SVID X as the authoritative cap and reject any partner altmode
> that would exceed it. This preserves legitimate multi-Mode
> partner altmodes (vendor SVIDs that the port really does
> advertise more than once) while filtering the firmware-generated
> duplicates that have no port counterpart, and is therefore
> stricter than a plain SVID+VDO comparison (which still admits the
> Thunderbolt case where firmware reports the same SVID twice with
> different VDOs) without being over-broad like a plain SVID match
> (which would falsely drop legitimate vendor multi-Mode entries).
>
> If a duplicate is detected, skip it and emit a clean warning instead
> of generating a kernel call trace:
>
> ucsi_acpi USBC000:00: con2: Firmware bug: duplicate partner altmode SVID 0x8087 at offset 1, ignoring.
> ucsi_acpi USBC000:00: con2: VDO mismatch: 0x8087a043 vs 0x00000001
>
> The duplicate detection logic lives in a reusable helper
> ucsi_altmode_is_duplicate() and is invoked from
> ucsi_register_altmodes(). It applies to all three recipient types:
> partner (SOP), port (CON), and plug (SOP_P) altmodes.
>
> Fixes: a79f16efcd00 ("usb: typec: ucsi: Add support for the partner USB Modes")
> Cc: stable@vger.kernel.org
> Signed-off-by: Chia-Lin Kao (AceLan) <acelan.kao@canonical.com>
Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
> --
> v7. - Rephrase the warning message ", ignoring." to ", ignoring but
> please contact the BIOS vendor to fix this issue."
> v6. - New helper ucsi_altmode_count_svid() counts altmodes with a given
> SVID in any of the per-connector altmode arrays.
> - ucsi_altmode_is_duplicate() for UCSI_RECIPIENT_SOP no longer asks
> "have I seen this SVID before". It now checks whether
> partner_count_for(svid) >= port_count_for(svid) and rejects only the
> surplus.
> - For UCSI_RECIPIENT_CON and UCSI_RECIPIENT_SOP_P, behavior is
> unchanged: still SVID+VDO exact-dup match.
> - Commit message rewritten to spell out the per-recipient rules and
> why partner needs the cardinality cap (avoids both the SVID-only
> false positives that hurt the legitimate Dell 0x413c case and the
> SVID+VDO false negatives that let the Thunderbolt 0x8087 firmware
> bug through).
> ---
> drivers/usb/typec/ucsi/ucsi.c | 132 ++++++++++++++++++++++++++++++++++
> 1 file changed, 132 insertions(+)
>
> diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
> index 642acc09d861..b9343bf67357 100644
> --- a/drivers/usb/typec/ucsi/ucsi.c
> +++ b/drivers/usb/typec/ucsi/ucsi.c
> @@ -550,6 +550,129 @@ static int ucsi_register_altmode(struct ucsi_connector *con,
> return ret;
> }
>
> +static void ucsi_dump_duplicate_altmode(struct ucsi_connector *con,
> + u8 recipient, u16 svid,
> + u32 existing_vdo, u32 new_vdo,
> + int offset)
> +{
> + static const char * const recipient_names[] = {
> + [UCSI_RECIPIENT_CON] = "port",
> + [UCSI_RECIPIENT_SOP] = "partner",
> + [UCSI_RECIPIENT_SOP_P] = "plug",
> + [UCSI_RECIPIENT_SOP_PP] = "cable plug prime",
> + };
> +
> + dev_warn(con->ucsi->dev,
> + "con%d: Firmware bug: duplicate %s altmode SVID 0x%04x at offset %d, ignoring but please contact the BIOS vendor to fix this issue.\n",
> + con->num, recipient_names[recipient], svid, offset);
> +
> + if (existing_vdo != new_vdo)
> + dev_warn(con->ucsi->dev,
> + "con%d: VDO mismatch: 0x%08x vs 0x%08x\n",
> + con->num, existing_vdo, new_vdo);
> +}
> +
> +/* Count altmodes in @altmodes that advertise @svid. */
> +static int ucsi_altmode_count_svid(struct typec_altmode **altmodes, u16 svid)
> +{
> + int count = 0;
> + int k;
> +
> + for (k = 0; k < UCSI_MAX_ALTMODES; k++) {
> + if (!altmodes[k])
> + break;
> + if (altmodes[k]->svid == svid)
> + count++;
> + }
> +
> + return count;
> +}
> +
> +/*
> + * Check if an altmode is a duplicate. Some firmware implementations
> + * incorrectly return the same altmode multiple times, causing sysfs errors.
> + * Returns true if the altmode should be skipped.
> + *
> + * The matching rules differ by recipient:
> + *
> + * - UCSI_RECIPIENT_CON (port) and UCSI_RECIPIENT_SOP_P (plug):
> + * Two altmodes with identical SVID and VDO are byte-for-byte duplicates
> + * and the second has no observable function. Drop them.
> + *
> + * - UCSI_RECIPIENT_SOP (partner):
> + * The typec class binds each partner altmode to a port altmode of the
> + * same SVID via altmode_match()/device_find_child(), which returns the
> + * first port altmode with a matching SVID. If the partner advertises
> + * more altmodes for SVID X than the port advertises, the surplus
> + * partner altmode(s) collapse onto an already-paired port altmode and
> + * trigger a "duplicate filename .../partner" sysfs error during
> + * typec_altmode_create_links(). Use the port-side altmode count for
> + * SVID X as the authoritative cap and reject any partner altmode that
> + * would exceed it. This preserves legitimate multi-Mode partner
> + * altmodes (e.g. vendor SVIDs that the port really does advertise
> + * twice) while filtering the firmware-generated duplicates that have
> + * no port counterpart.
> + */
> +static bool ucsi_altmode_is_duplicate(struct ucsi_connector *con, u8 recipient,
> + const struct ucsi_altmode *alt_batch, int batch_idx,
> + u16 svid, u32 vdo, int offset)
> +{
> + struct typec_altmode **altmodes;
> + int port_count, partner_count;
> + int k;
> +
> + /* Check for duplicates within the current batch first */
> + for (k = 0; k < batch_idx; k++) {
> + if (alt_batch[k].svid == svid && alt_batch[k].mid == vdo) {
> + ucsi_dump_duplicate_altmode(con, recipient, svid,
> + vdo, vdo, offset);
> + return true;
> + }
> + }
> +
> + switch (recipient) {
> + case UCSI_RECIPIENT_SOP:
> + /*
> + * Cap partner altmodes per SVID by the port-side count:
> + * any further partner altmode for that SVID would alias an
> + * already-paired port altmode and break typec sysfs.
> + */
> + port_count = ucsi_altmode_count_svid(con->port_altmode, svid);
> + partner_count = ucsi_altmode_count_svid(con->partner_altmode,
> + svid);
> + if (port_count && partner_count >= port_count) {
> + ucsi_dump_duplicate_altmode(con, recipient, svid,
> + con->partner_altmode[partner_count - 1]->vdo,
> + vdo, offset);
> + return true;
> + }
> + return false;
> + case UCSI_RECIPIENT_CON:
> + altmodes = con->port_altmode;
> + break;
> + case UCSI_RECIPIENT_SOP_P:
> + altmodes = con->plug_altmode;
> + break;
> + default:
> + return false;
> + }
> +
> + /* CON and SOP_P: drop only exact SVID+VDO duplicates. */
> + for (k = 0; k < UCSI_MAX_ALTMODES; k++) {
> + if (!altmodes[k])
> + break;
> +
> + if (altmodes[k]->svid != svid || altmodes[k]->vdo != vdo)
> + continue;
> +
> + ucsi_dump_duplicate_altmode(con, recipient, svid,
> + altmodes[k]->vdo, vdo, offset);
> + return true;
> + }
> +
> + return false;
> +}
> +
> static int
> ucsi_register_altmodes_nvidia(struct ucsi_connector *con, u8 recipient)
> {
> @@ -674,6 +797,15 @@ static int ucsi_register_altmodes(struct ucsi_connector *con, u8 recipient)
> if (!alt[j].svid)
> return 0;
>
> + /*
> + * Check for duplicates in current batch and already
> + * registered altmodes. Skip if duplicate found.
> + */
> + if (ucsi_altmode_is_duplicate(con, recipient, alt, j,
> + alt[j].svid, alt[j].mid,
> + i - num + j))
> + continue;
> +
> memset(&desc, 0, sizeof(desc));
> desc.vdo = alt[j].mid;
> desc.svid = alt[j].svid;
> --
> 2.53.0
>
--
heikki
prev parent reply other threads:[~2026-07-13 9:54 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-13 8:43 [PATCH v7 1/3] usb: typec: ucsi: Detect and skip duplicate altmodes from buggy firmware Chia-Lin Kao (AceLan)
2026-07-13 8:43 ` [PATCH v7 2/3] usb: typec: ucsi: Add duplicate detection to nvidia registration path Chia-Lin Kao (AceLan)
2026-07-13 8:43 ` [PATCH v7 3/3] usb: typec: ucsi: yoga_c630: Remove redundant duplicate altmode handling Chia-Lin Kao (AceLan)
2026-07-13 9:53 ` Heikki Krogerus [this message]
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=alS1tywaoP_0ECVl@kuha \
--to=heikki.krogerus@linux.intel.com \
--cc=acelan.kao@canonical.com \
--cc=akuchynski@chromium.org \
--cc=dmitry.baryshkov@oss.qualcomm.com \
--cc=gregkh@linuxfoundation.org \
--cc=johan@kernel.org \
--cc=jthies@google.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-usb@vger.kernel.org \
--cc=pooja.katiyar@intel.com \
--cc=yuanhsinte@chromium.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.