Skip to content

USB4/Thunderbolt imported prerequisites - #1

Open
DjDeveloperr wants to merge 33 commits into
aurora-wipfrom
usb4-base
Open

DjDeveloperr wants to merge 33 commits into
aurora-wipfrom
usb4-base

Conversation

@DjDeveloperr

@DjDeveloperr DjDeveloperr commented Sep 5, 2026

Copy link
Copy Markdown

Imported prerequisites for the USB4/Thunderbolt work, split out as a base branch so the driver PR on top shows only our own commits.

svenpeter42 and others added 30 commits September 5, 2026 14:36
The Intel VID status register is actually 9 bytes long and doesn't
contain the raw VDOs but only the upper 16bits for device mode and enter
mode. Shift those two fields into place and reconstruct the cable
discover mode VDO from the data status registers instead.

Link: https://www.ti.com/lit/ug/slvubh2b/slvubh2b.pdf
Fixes: 0b31c97 ("usb: typec: tipd: Read USB4, Thunderbolt and DisplayPort status for cd321x")
Fixes: 82432bb ("usb: typec: tipd: Handle mode transitions for CD321x")
Cc: stable@vger.kernel.org
Signed-off-by: Sven Peter <sven@kernel.org>
Table F-10 of the USB Type-C Cable and Connector Specification R2.5 on
page 412 defines bit 16 of the TBT3 Device Discover Mode VDO as 0 = TBT3
Adapter and 1 = TBT2 Legacy Adapter. Linux has those two swapped since
their original introduction in commit ca469c2 ("usb: typec: Add
definitions for Thunderbolt 3 Alternate Mode").

ChromiumOS EC's include/usb_pd_tbt.h has them the correct way around
and references the USB Type-C ECN "Thunderbolt 3 Compatibility Updates"
as fixing an error where they were originally swapped which is presumably
where the wrong order originally came from.

I've also confirmed the correct mapping with an Apple Thunderbolt 3
to Thunderbolt 2 adapter which does set bit 16 in that VDO.

Swap the two values and update all users. Also rename the old defines
so that no user accidentally ends up with an inverted value.
No functional change.

Link: https://usb.org/document-library/usb-type-cr-cable-and-connector-specification-release-25
Link: https://chromium.googlesource.com/chromiumos/platform/ec/+/db93814b6e73c8545d23714fe0674c10814d901a/include/usb_pd_tbt.h#90
Signed-off-by: Sven Peter <sven@kernel.org>
---
I ran into this when bringing up thunderbolt for Apple Silicon SoCs and
was very confused why the condition for "tbt2 adapter" vs "tbt3 adapter"
seemed to be backwards.
I think the qcom pmic_glink_altmode.c actually has a bug there that was
hidden and/or caused by the wrong values: It used to always set
TBT_ADAPTER_TBT3 which sounds plausible but actually claims to be a
legacy TBT2 adapter on the wire. I don't have the hardware or know the
intention there though.
The other users look correct to me since they just pass the value
through.
The CIO (USB4/Thunderbolt) blocks on Apple Silicon SoCs have a reset
inside the power manager that has to be deasserted before their
co-processor can be booted. On t8103 each port comes with a dedicated
register page, represented as a standalone node. On t600x a single
register shared by all ports of a die is located in the middle of the
PMGR MMIO region instead, represented as a sub-node of the PMGR syscon.

Signed-off-by: Sven Peter <sven@kernel.org>
Add a driver for the reset of the CIO (USB4/Thunderbolt) blocks on
Apple Silicon SoCs which has to be deasserted before their
co-processor can be booted. On t8103 each port comes with a dedicated
register page while t600x uses a single register with one request bit
per port shared by all ports of a die inside the PMGR MMIO region.

Signed-off-by: Sven Peter <sven@kernel.org>
Add the reset controllers used to start the CIO (USB4/Thunderbolt)
blocks on t8103 and t600x. On t8103 each port comes with a dedicated
register page represented as a standalone node. On t600x a single
register shared by all ports of a die is located in the middle of the
PMGR MMIO region and represented as a sub-node of its syscon.

Signed-off-by: Sven Peter <sven@kernel.org>
The USB4/Thunderbolt host routers on Apple Silicon SoCs require cable
and mode details to be provided out-of-band by the Type-C port controller.
Add a thunderbolt-switch property next to the existing orientation and mode
switches which marks a node as handler of these notifications.

Signed-off-by: Sven Peter <sven@kernel.org>
…dler

For both Thunderbolt and DisplayPort atcphy_configure_pipehandler is
reached with a request to switch to the DUMMY state (i.e. usb2 only).
With the current code this breaks USB2 when all four SS lanes are used
for DisplayPort AltMode because the -EINVAL is passed all the way back
to the phy_set_mode() call which results in tearing down xhci and dwc3
again.
Let's actually handle that case correctly and also drop the default from
the switch such that we get a compiler warning if another pipehandler
state is ever added and forgotten here.

Reported-by: Paul Cristian <p4ulcristian@gmail.com>
Closes: AsahiLinux#515
Fixes: 8e98ca1 ("phy: apple: Add Apple Type-C PHY")
Cc: stable@vger.kernel.org
Signed-off-by: Sven Peter <sven@kernel.org>
This sequence is already used in three places and we're about to add a
fourth copy so let's factor it out to a helper. No functional change.

Signed-off-by: Sven Peter <sven@kernel.org>
USB3 tunneled via USB4 requires dwc3's PIPE interface to be switched to
the USB4 NHI which will take care of the tunneling. Add the required
bringup sequence such that USB3 tunnels work once the USB4 NHI is
upstream.

Signed-off-by: Sven Peter <sven@kernel.org>
On Apple Silicon the USB4/Thunderbolt host router can only be brought
up after a cable has been plugged in and requires the cable details
known only to the Type-C port controller. Add a thunderbolt switch
similar to the existing orientation and mode switches which Type-C port
drivers can use to forward these details out-of-band. Unlike those
switches only a single handler per connection is supported since the
cable details always go to exactly one host router.

Signed-off-by: Sven Peter <sven@kernel.org>
Look up the thunderbolt switch on Apple platforms and forward cable details
whenever a Thunderbolt or USB4 connection comes up or disappears.

Signed-off-by: Sven Peter <sven@kernel.org>
The Native Host Interface (NHI) provides the TX and RX rings used by the
software connection manager on Apple Silicon SoCs.

The NHI is part of the ACIO host router and is exposed to the main SoC
bus while the ACIO co-processor is running.

T6000 and T6020 use one DART stream for the TX and RX control rings and
one shared by all other rings, which are used for XDomain connections.
This likely improves the isolation of those host-to-host connections.

The M3 generation uses a slightly insane set of 24 IOMMU entries. These
are probably one DART stream for each TX and RX ring.

Signed-off-by: Sven Peter <sven@kernel.org>
Each Type-C port with USB4/Thunderbolt support on Apple Silicon SoCs
comes with a host router called ACIO. It contains a Cortex-M3
co-processor and the hardware blocks implementing the USB4 router. The
co-processor exposes the NHI and its DART to the main SoC bus while it is
running.

ACIO can only be powered on after the Type-C PHY has been switched to
USB4/Thunderbolt mode. The Type-C controller provides the cable
information required to boot it through the thunderbolt-switch
connection.

Signed-off-by: Sven Peter <sven@kernel.org>
On Apple Silicon SoCs the DROM is provided by a device tree property.
Try reading from that property first.

Signed-off-by: Sven Peter <sven@kernel.org>
On Apple Silicon the host router's UID comes from the DROM provided by
the device tree and is already known by the time tb_switch_set_uuid()
runs. Skip reading it from the config space again in that case.

For other USB4 hosts this only drops a duplicate read because
tb_drom_host_read() has already filled in the UID from ROUTER_CS_7
before tb_switch_set_uuid() runs. Device routers keep reading it
unconditionally.

Signed-off-by: Sven Peter <sven@kernel.org>
The Apple NHI has one interrupt per ring and request_ring_irq picks it
based on ring->hop which is still -1 at this point for rings allocated
with an automatic HopID. Allocate the HopID first and release it again
if the interrupt request fails.

Signed-off-by: Sven Peter <sven@kernel.org>
The Apple NHI enables and disables ring interrupts differently. Add an
optional tb_nhi_ops hook to override ring_interrupt_active which falls
back to the standard USB4 method when it is not set.

Signed-off-by: Sven Peter <sven@kernel.org>
The ring descriptor and options registers are laid out differently on
the Apple NHI. Describe their offsets and strides with a
tb_nhi_ring_layout struct that NHI drivers can override.

Signed-off-by: Sven Peter <sven@kernel.org>
Masking ring interrupts works differently on the Apple NHI as well. Add
an optional tb_nhi_ops hook for it which falls back to the standard
USB4 NHI method when it is not set.

Signed-off-by: Sven Peter <sven@kernel.org>
Signed-off-by: Sven Peter <sven@kernel.org>
Apple Silicon machines load and update the host router firmware with a separate, proprietary mechanism and have no DMA port. Add a quirk to skip its initialization.

Signed-off-by: Sven Peter <sven@kernel.org>
The host routers on Apple Silicon do not implement USB3 bandwidth
allocation registers: the CMR bit set in ADP_USB3_CS_2 by
usb4_usb3_port_cm_request() is never acknowledged and every USB3 tunnel
bringup fails there after the timeout:

  [   49.259325] thunderbolt-apple-nhi 501f00000.nhi: 1:16: available bandwidth for new USB3 tunnel 18000/18000 Mb/s
  [   49.265869] thunderbolt-apple-nhi 501f00000.nhi: 1:16: maximum required bandwidth for USB3 tunnel 9000 Mb/s
  [   49.267894] thunderbolt-apple-nhi 501f00000.nhi: 0:4 <-> 1:16 (USB3): activating
  [   49.269410] thunderbolt-apple-nhi 501f00000.nhi: 0:4 <-> 1:16 (USB3): allocating initial bandwidth 9000/9000 Mb/s
  [   50.771764] thunderbolt-apple-nhi 501f00000.nhi: 1:16: USB3 tunnel activation failed, aborting

Add a quirk to skip bandwidth allocation entirely but keep tracking
the initial allocation in software for the consumed bandwidth
calculation. Discovered tunnels book 90% of the maximum link rate instead
of reading back an allocation that does not exist. This is only done for
correctness and mirrors what tb_tunnel_alloc_usb3() does since on Apple
Silicon there can never be any pre-existing tunnels.

Signed-off-by: Sven Peter <sven@kernel.org>
The driver for the ACIO host router complex on Apple Silicon SoCs can
be built as a module and needs tb_probe() and the domain functions to
register its NHI with the software connection manager as well as
tb_switch_find_vse_cap(), tb_cfg_write() and tb_port_unlock() to
configure the cable details for its co-processor and to unlock the
lane ports. Export these symbols in the USB4 namespace.

Signed-off-by: Sven Peter <sven@kernel.org>
Not all USB4/TB implementations are based on a PCIe-attached
controller. In order to make way for these, start off with moving the
pci_device reference out of the main tb_nhi structure.

Encapsulate the existing struct in a new tb_nhi_pci, that shall also
house all properties that relate to the parent bus. Similarly, any
other type of controller will be expected to contain tb_nhi as a
member.

Signed-off-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Add a new file encapsulating most of the PCI NHI specifics
(intentionally leaving some odd cookies behind to make the layering
simpler). Most notably, separate out nhi_probe() to make it easier to
register other types of NHIs.

Also, fold in Intel Icelake (nhi_ops.c) support to contain all
PCIe-related bits in pci.c.

Signed-off-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
…ng used

Both Woody and Marek reported following crash:

 BUG: unable to handle page fault for address: fffffffffffffff8
 Call Trace:
  <TASK>
  device_release+0x43/0x90
  kobject_cleanup+0x3c/0x180
  icm_probe+0x19c/0x550 [thunderbolt]
  nhi_probe+0x1a4/0x370 [thunderbolt]
  local_pci_probe+0x41/0x90
  pci_call_probe+0x5b/0x1a0
  ...

This only triggers on the error path when icm_probe() fails and the
domain structure is released, it tries to complete() uninitialized
completion.

Fix this by initializing the completion earlier.

Reported-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
Closes: https://lore.kernel.org/linux-usb/amdezCBiW4fd_DuB@mail-itl/
Reported-by: Woody Suwalski <terraluna977@gmail.com>
Tested_by: Woody Suwalski <terraluna977@gmail.com>
Closes: https://lore.kernel.org/linux-usb/62caf7f8-b403-d0dd-15bc-b31b56f71c28@gmail.com/
Fixes: f5cc545 ("thunderbolt: Wait for tb_domain_release() to complete when driver is removed")
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Add a driver for the ACIO host complex and USB Native Host Interface
found on Apple Silicon SoCs.

Signed-off-by: Sven Peter <sven@kernel.org>
Add the ACIO host router, NHI, DART and M3 mailbox nodes for both
Type-C ports on t8103 and connect the host routers to the Type-C
connectors.

Signed-off-by: Sven Peter <sven@kernel.org>
Add the ACIO host router, NHI, DART and mailbox nodes for both Type-C
ports on t8112 and connect the host routers to the Type-C connectors.

Signed-off-by: Sven Peter <sven@kernel.org>
Add the ACIO host router, NHI, DART and mailbox nodes for the four ATC
instances on each t600x and t602x die and connect the host routers to
the Type-C connectors on the MacBook Pro (j314/j316 and j414/j416), Mac
Studio (j375 and j475), Mac mini (j474) and Mac Pro (j180d) boards.

Signed-off-by: Sven Peter <sven@kernel.org>
jannau and others added 3 commits September 5, 2026 14:36
depends on "iommu: apple-dart: Support specifying the DMA aperture in
the DT" series.

Signed-off-by: Janne Grunau <j@jannau.net>
…removed

We should not call nhi_shutdown() before the domain structure and the
control channel rings are completely released. Otherwise we might
release resources like the nhi->msix_ida that are still referenced in
tb_domain_release(). For this reason wait for the tb_domain_release() to
be completed before continuing to nhi_shutdown() and eventually
releasing of the rest of the data structures.

Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
…ling

Instead of the core driver programming fixed value for throttling let
the service drivers to specify the interval if they need this.

Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
DjDeveloperr pushed a commit that referenced this pull request Sep 12, 2026
…mode list (#4)

* usb: typec: tipd: fix partner identity use-after-free on CD321x

cd321x_update_work() points desc.identity at st.partner_identity, where
"st" is a stack local. typec_register_partner() stores that pointer in
partner->identity rather than copying the structure, so once the work
function returns the partner is left referencing a freed stack page.

Any later read of the partner's PD identity then dereferences it. On a
MacBook Pro (16-inch, M2 Max) reading

  /sys/class/typec/port0-partner/type

as an unprivileged user is enough:

  Unable to handle kernel paging request at virtual address ffff800083a87d0c
  Internal error: Oops: 0000000096000007 [#1] SMP
  CPU: 10 UID: 1000 PID: 83017 Comm: cat
  pc : get_pd_product_type+0x54/0xa4 [typec]
  lr : type_show+0x14/0x3c [typec]

get_pd_product_type() NULL-checks partner->identity and then reads
id->id_header, which is the faulting access; the pointer is not NULL,
just dangling. With VMAP_STACK the dead stack is unmapped, hence the
vmalloc-range fault address.

The driver already keeps a persistent copy in cd321x->cur_partner_identity,
but only assigns it after registration. Fill it in first and register the
partner against that instead. The generic tps6598x path already does the
equivalent, pointing desc.identity at tps->partner_identity.

Fixes: 82432bb ("usb: typec: tipd: Handle mode transitions for CD321x")
Signed-off-by: Marcelo <marcelo@omarchy.org>

* usb: typec: fix sysfs_emit_at() offset underflow on an empty mode list

usb_mode_show() and usb_capability_show() build a space-separated list
and then overwrite the trailing space with a newline:

	sysfs_emit_at(buf, len - 1, "\n");

When the partner or port advertises none of USB2/USB3/USB4 the loop body
never runs, len stays 0, and the call is made with at == -1:

  invalid sysfs_emit_at: buf:00000000ffaad2a3 at:-1
  WARNING: fs/sysfs/file.c:785 at sysfs_emit_at+0x54/0xd4, CPU#1: cat/892

sysfs_emit_at() rejects the negative offset, so the attribute also reads
back empty rather than as a newline like every other list attribute.

Seen on a MacBook Pro (16-inch, M2 Max), where one of the Type-C partners
registered by the CD321x has no USB capability bits set, by reading

  /sys/class/typec/port1-partner/usb_mode

Return a bare newline when nothing was written.

Fixes: 2140a95 ("usb: typec: Add attribute file showing the USB Modes of the partner")
Signed-off-by: Marcelo <marcelo@omarchy.org>

---------

Signed-off-by: Marcelo <marcelo@omarchy.org>
Co-authored-by: Marcelo <marcelo@omarchy.org>
DjDeveloperr pushed a commit that referenced this pull request Sep 12, 2026
cd321x_update_work() points desc.identity at st.partner_identity, where
"st" is a stack local. typec_register_partner() stores that pointer in
partner->identity rather than copying the structure, so once the work
function returns the partner is left referencing a freed stack page.

Any later read of the partner's PD identity then dereferences it. On a
MacBook Pro (16-inch, M2 Max) reading

  /sys/class/typec/port0-partner/type

as an unprivileged user is enough:

  Unable to handle kernel paging request at virtual address ffff800083a87d0c
  Internal error: Oops: 0000000096000007 [#1] SMP
  CPU: 10 UID: 1000 PID: 83017 Comm: cat
  pc : get_pd_product_type+0x54/0xa4 [typec]
  lr : type_show+0x14/0x3c [typec]

get_pd_product_type() NULL-checks partner->identity and then reads
id->id_header, which is the faulting access; the pointer is not NULL,
just dangling. With VMAP_STACK the dead stack is unmapped, hence the
vmalloc-range fault address.

The driver already keeps a persistent copy in cd321x->cur_partner_identity,
but only assigns it after registration. Fill it in first and register the
partner against that instead. The generic tps6598x path already does the
equivalent, pointing desc.identity at tps->partner_identity.

Fixes: 82432bb ("usb: typec: tipd: Handle mode transitions for CD321x")
Signed-off-by: Marcelo <marcelo@omarchy.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants