Skip to content

Commit f176a7c

Browse files
committed
Merge tag 'thunderbolt-for-v7.2-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/westeri/thunderbolt into usb-next
Mika writes: thunderbolt: Changes for v7.2 merge window This includes following USB4/Thunderbolt changes for the v7.2 merge window: - Make the driver more compliant with the connection manager guide. - Improvements over Thunderbolt XDomain service handling. - USB4STREAM driver. - Split out PCIe bits into pci.c to allow the driver to work on non-PCIe hosts as well. - Various fixes and improvements. All these have been in linux-next with no reported issues. * tag 'thunderbolt-for-v7.2-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/westeri/thunderbolt: (41 commits) thunderbolt: debugfs: Fix sideband write size check thunderbolt: debugfs: Fix margining error counter buffer leak thunderbolt: test: Release third DP tunnel thunderbolt: Prevent XDomain delayed work use-after-free on disconnect thunderbolt: test: Add KUnit tests for property parser bounds checks thunderbolt: Add some more descriptive probe error messages thunderbolt: Require nhi->ops be valid thunderbolt: Separate out common NHI bits thunderbolt: Move pci_device out of tb_nhi thunderbolt: Increase Notification Timeout to 255 ms for USB4 routers thunderbolt: Increase timeout for Configuration Ready bit thunderbolt: Verify Router Ready bit is set after router enumeration thunderbolt: Verify PCIe adapter in detect state before tunnel setup thunderbolt: Activate path hops from source to destination thunderbolt: Fix lane bonding log when bonding not possible thunderbolt: Don't access path config space on Lane 1 adapters in tb_switch_reset_host() thunderbolt: Improve multi-display DisplayPort tunnel allocation docs: admin-guide: thunderbolt: Add instructions how to use USB4STREAM thunderbolt: Add support for USB4STREAM thunderbolt: Add support for ConfigFS ...
2 parents 511e746 + c1bef05 commit f176a7c

31 files changed

Lines changed: 3710 additions & 919 deletions
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
What: /sys/kernel/config/thunderbolt/stream/<xdomain>.<service>
2+
Date: Sep 2026
3+
KernelVersion: v7.2
4+
Contact: Mika Westerberg <mika.westerberg@linux.intel.com>
5+
Description:
6+
Configuration group for a stream Thunderbolt/USB4
7+
service. It is possible to create groups even if there
8+
is no connection yet to the other host. Once a
9+
connection established and there is stream service on
10+
the remote side that matches, this configuration is
11+
applied to it.
12+
13+
To find the service name you can run tblist from tbtools [1]:
14+
15+
# tblist -A
16+
...
17+
Domain 0 Route 3 Index 0: stream
18+
19+
[1] https://github.com/intel/tbtools
20+
21+
What: /sys/kernel/config/thunderbolt/stream/<xdomain>.<service>/$name
22+
Date: Sep 2026
23+
KernelVersion: v7.2
24+
Contact: Mika Westerberg <mika.westerberg@linux.intel.com>
25+
Description:
26+
Creates new stream with $name and fills it with the
27+
default values. If there is an advertised remote stream
28+
with the same name, uses its values as the default.
29+
30+
What: /sys/kernel/config/thunderbolt/stream/<xdomain>.<service>/$name/index
31+
Date: Sep 2026
32+
KernelVersion: v7.2
33+
Contact: Mika Westerberg <mika.westerberg@linux.intel.com>
34+
Description:
35+
This matches the X in /dev/tbstreamX and allows userspace
36+
to map the configfs directory to the corresponding character
37+
device.
38+
39+
What: /sys/kernel/config/thunderbolt/stream/<xdomain>.<service>/$name/in_hopid
40+
Date: Sep 2026
41+
KernelVersion: v7.2
42+
Contact: Mika Westerberg <mika.westerberg@linux.intel.com>
43+
Description:
44+
In HopID used with the read path of the tunnel. Available HopIDs
45+
for tunneling start from 8. You can pass also -1 for automatic
46+
allocation. The allocated value can be read here. Writing 0 will
47+
de-allocate if the stream is not in use.
48+
49+
To figure out the maximum HopID you can run tbget from
50+
tbtools for the lane adapter. For example below we check
51+
for lane adapter number 1 (first USB4 port):
52+
53+
# tbget -r 0 -a 1 -D ADP_CS_5.Max\ Input\ HopID
54+
19
55+
56+
This allows to use anything between 8 and 19 inclusive.
57+
58+
What: /sys/kernel/config/thunderbolt/stream/<xdomain>.<service>/$name/out_hopid
59+
Date: Sep 2026
60+
KernelVersion: v7.2
61+
Contact: Mika Westerberg <mika.westerberg@linux.intel.com>
62+
Description:
63+
Out HopID used with the write path of the tunnel. Available HopIDs
64+
for tunneling start from 8. You can pass also -1 for automatic
65+
allocation. The allocated value can be read here. Writing 0 will
66+
de-allocate if the stream is not in use. See @in_hopid
67+
for how to figure out the maximum HopID.
68+
69+
What: /sys/kernel/config/thunderbolt/stream/<xdomain>.<service>/$name/ring_size
70+
Date: Sep 2026
71+
KernelVersion: v7.2
72+
Contact: Mika Westerberg <mika.westerberg@linux.intel.com>
73+
Description:
74+
Size of the TX/RX rings. Can be adjusted between 32 and
75+
4096. The default is 256.
76+
77+
What: /sys/kernel/config/thunderbolt/stream/<xdomain>.<service>/$name/throttling
78+
Date: Sep 2026
79+
KernelVersion: v7.2
80+
Contact: Mika Westerberg <mika.westerberg@linux.intel.com>
81+
Description:
82+
Interrupt throttling rate in ns. Lower values can give
83+
better latency. The default is 8192 ns.

Documentation/admin-guide/thunderbolt.rst

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,67 @@ port which are named like ``thunderbolt0`` and so on. From this point
373373
you can either use standard userspace tools like ``ip`` to
374374
configure the interface or let your GUI handle it automatically.
375375

376+
Streaming data directly over Thunderbolt cable
377+
----------------------------------------------
378+
In addition to Thunderbolt networking (aka. USB4NET) Linux supports
379+
streaming data directly over a cable as well (aka. USB4STREAM). This is
380+
possible through ``thunderbolt-stream`` driver.
381+
382+
Similarly to ``thunderbolt-net`` you load the driver first on one end::
383+
384+
host1 # modprobe thunderbolt-stream
385+
386+
Then you configure it via ``ConfigFS``::
387+
388+
host1 # cd /sys/kernel/config/thunderbolt/stream
389+
host1 # mkdir -p 0-1.0/data
390+
host1 # cd 0-1.0
391+
host1 # echo -1 > data/in_hopid
392+
host1 # echo -1 > data/out_hopid
393+
394+
This information is automatically announced to the other side via
395+
XDomain properties so if you have cable connected the other side knows
396+
that there is a stream named ``data`` available and can configure it for
397+
you automatically::
398+
399+
host2 # cd /sys/kernel/config/thunderbolt/stream
400+
host2 # mkdir -p 0-3.0/data
401+
402+
Here we used auto-configuration but you can configure it manually too.
403+
In that case you need to fill ``in_hopid`` and ``out_hopid`` accordingly.
404+
If you set them to ``-1`` the next available HopID is used which is
405+
typically what we want.
406+
407+
Once they are configured you can use ``/dev/tbstreamX`` on both sides to
408+
transfer data::
409+
410+
host2 # cat /dev/tbstream0
411+
host1 # dmesg > /dev/tbstream0
412+
413+
Once you are done with the stream you can remove them::
414+
415+
host2 # cd /sys/kernel/config/thunderbolt/stream
416+
host2 # rmdir -p 0-1.0/data
417+
host1 # cd /sys/kernel/config/thunderbolt/stream
418+
host1 # rmdir -p 0-3.0/data
419+
420+
Since streams are essentially files you can use any existing application
421+
that supports ``read(2)`` and ``write(2)`` in some form.
422+
423+
It is possible to have more than one stream and you can have both stream
424+
and ``thunderbolt-net`` in use simultaneously. For example we can create
425+
two streams with name ``control`` and ``data`` like this::
426+
427+
host1 # cd /sys/kernel/config/thunderbolt/stream
428+
host1 # mkdir 0-1.0
429+
host1 # cd 0-1.0
430+
host1 # mkdir control
431+
host1 # mkdir data
432+
433+
Then you have ``/dev/tbstream0`` for ``control`` and ``/dev/tbstream1``
434+
for ``data``. Before you can use them you need to configure them as
435+
shown above for the one stream case.
436+
376437
Forcing power
377438
-------------
378439
Many OEMs include a method that can be used to force the power of a

drivers/net/thunderbolt/main.c

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,12 @@
3434
#define TBNET_RING_SIZE 256
3535
#define TBNET_LOGIN_RETRIES 60
3636
#define TBNET_LOGOUT_RETRIES 10
37+
#define TBNET_THROTTLING 128000
3738
#define TBNET_E2E BIT(0)
3839
#define TBNET_MATCH_FRAGS_ID BIT(1)
3940
#define TBNET_64K_FRAMES BIT(2)
4041
#define TBNET_MAX_MTU SZ_64K
41-
#define TBNET_FRAME_SIZE SZ_4K
42+
#define TBNET_FRAME_SIZE TB_MAX_FRAME_SIZE
4243
#define TBNET_MAX_PAYLOAD_SIZE \
4344
(TBNET_FRAME_SIZE - sizeof(struct thunderbolt_ip_frame_header))
4445
/* Rx packets need to hold space for skb_shared_info */
@@ -327,11 +328,6 @@ static void stop_login(struct tbnet *net)
327328
netdev_dbg(net->dev, "login stopped\n");
328329
}
329330

330-
static inline unsigned int tbnet_frame_size(const struct tbnet_frame *tf)
331-
{
332-
return tf->frame.size ? : TBNET_FRAME_SIZE;
333-
}
334-
335331
static void tbnet_free_buffers(struct tbnet_ring *ring)
336332
{
337333
unsigned int i;
@@ -562,7 +558,7 @@ static struct tbnet_frame *tbnet_get_tx_buffer(struct tbnet *net)
562558
tf->frame.size = 0;
563559

564560
dma_sync_single_for_cpu(dma_dev, tf->frame.buffer_phy,
565-
tbnet_frame_size(tf), DMA_TO_DEVICE);
561+
tb_ring_frame_size(&tf->frame), DMA_TO_DEVICE);
566562

567563
return tf;
568564
}
@@ -744,7 +740,7 @@ static bool tbnet_check_frame(struct tbnet *net, const struct tbnet_frame *tf,
744740
}
745741

746742
/* Should be greater than just header i.e. contains data */
747-
size = tbnet_frame_size(tf);
743+
size = tb_ring_frame_size(&tf->frame);
748744
if (size <= sizeof(*hdr)) {
749745
net->stats.rx_length_errors++;
750746
return false;
@@ -961,6 +957,9 @@ static int tbnet_open(struct net_device *dev)
961957
}
962958
net->rx_ring.ring = ring;
963959

960+
tb_ring_throttling(net->tx_ring.ring, TBNET_THROTTLING);
961+
tb_ring_throttling(net->rx_ring.ring, TBNET_THROTTLING);
962+
964963
napi_enable(&net->napi);
965964
start_login(net);
966965

@@ -1011,7 +1010,8 @@ static bool tbnet_xmit_csum_and_map(struct tbnet *net, struct sk_buff *skb,
10111010
hdr->frame_index, hdr->frame_count);
10121011
dma_sync_single_for_device(dma_dev,
10131012
frames[i]->frame.buffer_phy,
1014-
tbnet_frame_size(frames[i]), DMA_TO_DEVICE);
1013+
tb_ring_frame_size(&frames[i]->frame),
1014+
DMA_TO_DEVICE);
10151015
}
10161016

10171017
return true;
@@ -1085,7 +1085,7 @@ static bool tbnet_xmit_csum_and_map(struct tbnet *net, struct sk_buff *skb,
10851085
*/
10861086
for (i = 0; i < frame_count; i++) {
10871087
dma_sync_single_for_device(dma_dev, frames[i]->frame.buffer_phy,
1088-
tbnet_frame_size(frames[i]), DMA_TO_DEVICE);
1088+
tb_ring_frame_size(&frames[i]->frame), DMA_TO_DEVICE);
10891089
}
10901090

10911091
return true;

drivers/thunderbolt/Kconfig

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ menuconfig USB4
1818

1919
if USB4
2020

21+
config USB4_CONFIGFS
22+
def_tristate USB4
23+
depends on CONFIGFS_FS && !(USB4=y && CONFIGFS_FS=m)
24+
2125
config USB4_DEBUGFS_WRITE
2226
bool "Enable write by debugfs to configuration spaces (DANGEROUS)"
2327
help
@@ -60,4 +64,15 @@ config USB4_DMA_TEST
6064
To compile this driver a module, choose M here. The module will be
6165
called thunderbolt_dma_test.
6266

67+
config USB4_STREAM
68+
tristate "Stream data over Thunderbolt/USB4 cable"
69+
depends on USB4_CONFIGFS
70+
help
71+
This adds support for USB4STREAM protocol that allows two
72+
hosts to stream data directly over Thunderbolt/USB4 cable
73+
through /dev/tbstreamX devices.
74+
75+
To compile this driver a module, choose M here. The module will be
76+
called thunderbolt_stream.
77+
6378
endif # USB4

drivers/thunderbolt/Makefile

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
# SPDX-License-Identifier: GPL-2.0-only
22
ccflags-y := -I$(src)
33
obj-${CONFIG_USB4} := thunderbolt.o
4-
thunderbolt-objs := nhi.o nhi_ops.o ctl.o tb.o switch.o cap.o path.o tunnel.o eeprom.o
4+
thunderbolt-objs := nhi.o ctl.o tb.o switch.o cap.o pci.o path.o tunnel.o eeprom.o
55
thunderbolt-objs += domain.o dma_port.o icm.o property.o xdomain.o lc.o tmu.o usb4.o
66
thunderbolt-objs += usb4_port.o nvm.o retimer.o quirks.o clx.o
77

88
thunderbolt-${CONFIG_ACPI} += acpi.o
99
thunderbolt-$(CONFIG_DEBUG_FS) += debugfs.o
10+
thunderbolt-$(CONFIG_USB4_CONFIGFS) += configfs.o
1011
thunderbolt-${CONFIG_USB4_KUNIT_TEST} += test.o
1112
CFLAGS_test.o += $(DISABLE_STRUCTLEAK_PLUGIN)
1213

1314
thunderbolt_dma_test-${CONFIG_USB4_DMA_TEST} += dma_test.o
1415
obj-$(CONFIG_USB4_DMA_TEST) += thunderbolt_dma_test.o
16+
17+
thunderbolt_stream-${CONFIG_USB4_STREAM} += stream.o
18+
obj-$(CONFIG_USB4_STREAM) += thunderbolt_stream.o

drivers/thunderbolt/acpi.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ static acpi_status tb_acpi_add_link(acpi_handle handle, u32 level, void *data,
2828
return AE_OK;
2929

3030
/* It needs to reference this NHI */
31-
if (dev_fwnode(&nhi->pdev->dev) != fwnode)
31+
if (dev_fwnode(nhi->dev) != fwnode)
3232
goto out_put;
3333

3434
/*
@@ -57,16 +57,16 @@ static acpi_status tb_acpi_add_link(acpi_handle handle, u32 level, void *data,
5757
*/
5858
pm_runtime_get_sync(&pdev->dev);
5959

60-
link = device_link_add(&pdev->dev, &nhi->pdev->dev,
60+
link = device_link_add(&pdev->dev, nhi->dev,
6161
DL_FLAG_AUTOREMOVE_SUPPLIER |
6262
DL_FLAG_RPM_ACTIVE |
6363
DL_FLAG_PM_RUNTIME);
6464
if (link) {
65-
dev_dbg(&nhi->pdev->dev, "created link from %s\n",
65+
dev_dbg(nhi->dev, "created link from %s\n",
6666
dev_name(&pdev->dev));
6767
*(bool *)ret = true;
6868
} else {
69-
dev_warn(&nhi->pdev->dev, "device link creation from %s failed\n",
69+
dev_warn(nhi->dev, "device link creation from %s failed\n",
7070
dev_name(&pdev->dev));
7171
}
7272

@@ -93,7 +93,7 @@ bool tb_acpi_add_links(struct tb_nhi *nhi)
9393
acpi_status status;
9494
bool ret = false;
9595

96-
if (!has_acpi_companion(&nhi->pdev->dev))
96+
if (!has_acpi_companion(nhi->dev))
9797
return false;
9898

9999
/*
@@ -103,7 +103,7 @@ bool tb_acpi_add_links(struct tb_nhi *nhi)
103103
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 32,
104104
tb_acpi_add_link, NULL, nhi, (void **)&ret);
105105
if (ACPI_FAILURE(status)) {
106-
dev_warn(&nhi->pdev->dev, "failed to enumerate tunneled ports\n");
106+
dev_warn(nhi->dev, "failed to enumerate tunneled ports\n");
107107
return false;
108108
}
109109

@@ -305,7 +305,7 @@ static struct acpi_device *tb_acpi_switch_find_companion(struct tb_switch *sw)
305305
struct tb_nhi *nhi = sw->tb->nhi;
306306
struct acpi_device *parent_adev;
307307

308-
parent_adev = ACPI_COMPANION(&nhi->pdev->dev);
308+
parent_adev = ACPI_COMPANION(nhi->dev);
309309
if (parent_adev)
310310
adev = acpi_find_child_device(parent_adev, 0, false);
311311
}

drivers/thunderbolt/configfs.c

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* ConfigFS support
4+
*
5+
* Copyright (C) 2026, Intel Corporation
6+
* Author: Mika Westerberg <mika.westerberg@linux.intel.com>
7+
*/
8+
9+
#include <linux/configfs.h>
10+
#include <linux/export.h>
11+
12+
#include "tb.h"
13+
14+
static const struct config_item_type tb_root_group_type = {
15+
.ct_owner = THIS_MODULE,
16+
};
17+
18+
static struct configfs_subsystem tb_configfs = {
19+
.su_group = {
20+
.cg_item = {
21+
.ci_namebuf = "thunderbolt",
22+
.ci_type = &tb_root_group_type,
23+
},
24+
},
25+
};
26+
27+
/**
28+
* tb_configfs_register_group() - Register Thunderbolt ConfigFS group
29+
* @group: Group to register.
30+
*
31+
* Registers the new @group under Thunderbolt subsystem ConfigFS.
32+
*
33+
* Return: 0% in case of success, negative errno otherwise.
34+
*/
35+
int tb_configfs_register_group(struct config_group *group)
36+
{
37+
return configfs_register_group(&tb_configfs.su_group, group);
38+
}
39+
EXPORT_SYMBOL_GPL(tb_configfs_register_group);
40+
41+
/**
42+
* tb_configfs_unregister_group() - Unregister previously registered group
43+
* @group: Group to unregister.
44+
*/
45+
void tb_configfs_unregister_group(struct config_group *group)
46+
{
47+
configfs_unregister_group(group);
48+
}
49+
EXPORT_SYMBOL_GPL(tb_configfs_unregister_group);
50+
51+
int tb_configfs_init(void)
52+
{
53+
config_group_init(&tb_configfs.su_group);
54+
mutex_init(&tb_configfs.su_mutex);
55+
return configfs_register_subsystem(&tb_configfs);
56+
}
57+
58+
void tb_configfs_exit(void)
59+
{
60+
configfs_unregister_subsystem(&tb_configfs);
61+
}

0 commit comments

Comments
 (0)