NetworkNews

Linux 7.3 Adds a Busy Poll Switch to USB4 Data Streams

On this page
  1. The reasoning is one sentence long
  2. You have seen this trade before
  3. The costs are stated, and both of them matter
  4. Where the knob lives
  5. What we would do
  6. Sources and further reading

Linux 7.3 is set to gain a busy poll option for USB4STREAM, the Intel protocol that moves raw data packets between two hosts joined by a USB4 or Thunderbolt cable. The patch, from Intel Thunderbolt maintainer Mika Westerberg, adds a ConfigFS attribute that switches the data transfer rings from interrupt driven delivery to polling. The reasoning in the patch is blunt: interrupts and scheduled workers add latency, and some applications would rather not pay it. The cost is spelled out just as plainly. You burn CPU cycles continuously, and you give up the ability to use poll(2) on the interface. The code sits in the thunderbolt tree waiting for the merge window.

The short answer

USB4STREAM is Intel's protocol for moving raw packets between two hosts joined by a USB4 or Thunderbolt cable. A patch from Intel's Mika Westerberg, queued for Linux 7.3, adds a ConfigFS attribute that switches a stream's transfer rings from interrupt driven delivery to busy polling. The patch states the reasoning directly: interrupts and scheduled workers add latency that latency critical applications may want to avoid. The costs are stated just as directly, namely continuous CPU consumption and the loss of poll(2) on that interface. No latency figures were published.

7.3target kernel, patches queued in the thunderbolt next branch
busy_pollnew ConfigFS attribute, set per stream and per peer
no poll(2)the documented cost, alongside continuous CPU use
Answer card: a patch queued in the thunderbolt tree for Linux 7.3 adds a busy poll ConfigFS attribute to USB4STREAM, switching data transfer rings from interrupt driven delivery to polling for lower host to host latency, at the cost of continuous CPU consumption and the loss of poll(2) support on the interface.
The USB4STREAM busy poll option at a glance. Source: Phoronix reporting on the thunderbolt.git patches, August 5, 2026. PNG

Two machines and a Thunderbolt cable is one of the fastest links you can build without buying a switch, and Linux has been quietly getting better at using it for something other than storage. A patch queued for Linux 7.3 pushes that a little further, and it does so by offering a trade every network engineer has already made somewhere else.

The subject is USB4STREAM, Intel's protocol for moving raw data packets between two hosts over a USB4 or Thunderbolt connection. The change, from Intel's Mika Westerberg, adds a single ConfigFS attribute that switches a stream's data transfer rings into polling mode.

The reasoning is one sentence long

The patch does not dress it up. Using interrupts and scheduling workers increases latency, so latency critical applications may want to avoid that.

Unpack the default path and you can see where the time goes. Data lands in the transfer ring. The hardware raises an interrupt. The kernel handles the interrupt and schedules a worker. The worker eventually runs and the data becomes visible to your process. Every step is cheap. None is free. Together they set a floor under how fast your application can react, and no amount of tuning above that layer gets under it.

Busy polling deletes the chain. A CPU sits in a loop asking the ring whether anything arrived, so the data is available the moment the hardware produces it. There is no interrupt to service and no worker to schedule because nobody is waiting for anything.

You have seen this trade before

If this feels familiar it is because networking made peace with it a long time ago.

NAPI busy polling does the same thing for network device queues. The SO_BUSY_POLL socket option exposes it per socket. The kernel bypass frameworks that telecom and trading workloads adopted years ago took the idea to its conclusion by removing the kernel from the data path entirely. Every one of those is the same bargain: spend a CPU continuously to stop waiting for the machine to tell you something happened.

What is new here is the surface, not the idea. This is a per stream toggle on a point to point cable between two hosts, which is a narrower and more controllable place to make the trade than a shared network interface. You are deciding for one link with one peer.

Terminal card showing where the USB4STREAM busy poll attribute lives in ConfigFS under the thunderbolt stream hierarchy, how the xdomain and service components identify the remote host, and how enabling it changes the delivery path from interrupt driven to polling.
The knob is a file. The path names the peer and the service, so the decision stays scoped to one link. PNG

The costs are stated, and both of them matter

The first is obvious and gets mentioned everywhere: a core spins whether or not traffic is flowing. Idle costs the same as saturated. On a laptop that is heat and battery. On a server it is a core removed from the pool for as long as the stream exists.

The second cost is the one worth stopping on. Enabling busy poll means you cannot use poll(2) on that interface.

That is not a performance note, it is a constraint on how the program is written. An application built around an event loop waiting on a set of file descriptors cannot simply have this turned on underneath it, because the mechanism it uses to wait is the thing being removed. If your data path already runs a dedicated thread doing tight reads, you were spending the CPU anyway and this costs you nothing new. If your stream is one descriptor among fifty inside an epoll loop, adopting busy poll means restructuring, not configuring.

Where the knob lives

It is ConfigFS, so it is a file, at a path shaped like /sys/kernel/config/thunderbolt/stream/[xdomain].[service]/$name/busy_poll. The xdomain component identifies the remote host discovered across the cable and the service component identifies what the two ends agreed to speak. Writing the attribute switches the rings for that stream and nothing else.

The granularity is the good part. This is not a boot parameter or a module option that changes behaviour for everything. One stream, one peer, one decision.

What we would do

Nothing, unless you have already measured the problem this solves.

Busy polling is the correct answer to a specific and verifiable condition: your workload is latency bound, and you have traced the latency to interrupt and scheduling overhead rather than to something above it. If you have not measured that, turning it on gives you a permanently occupied core and no benefit, and the poll(2) restriction may quietly force a rewrite you did not budget for.

The wider point is worth keeping even if you never touch a Thunderbolt cable. Host to host links over USB4 are becoming a real transport for people who need two machines close together and fast, and the kernel is now giving them the same latency controls that Ethernet has had for years. That is a category of link getting more serious, not a niche getting a knob.

As for timing, the patches sit in the thunderbolt tree aimed at Linux 7.3. Nothing has shipped yet, and after 7.3 releases you still wait for a distribution kernel that carries it.

Sources and further reading

Frequently asked questions

What is USB4STREAM and how is it different from networking over Thunderbolt?

USB4STREAM is an Intel defined protocol for shipping raw data packets between two hosts connected by a USB4 or Thunderbolt cable. The important word is raw. It is a transport for packets, not a network interface with an IP address and a routing table, so what runs on top of it is whatever the application decides. That distinguishes it from the older approach of exposing a Thunderbolt link as an Ethernet like network device, which gives you a familiar interface at the cost of carrying a full networking stack you may not need. Both live in the same part of the kernel and both rely on the same XDomain machinery that lets two machines discover each other over the cable. If you want IP between two boxes, the network device is still the answer. If you want the shortest path from your application to the wire, USB4STREAM is the one that does not put a stack in the middle.

What does busy polling actually change?

It changes who notices that data arrived. In the default arrangement, the hardware raises an interrupt, the kernel handles it, and a worker gets scheduled to do the actual processing. Each of those steps is cheap individually and none of them is free, and together they put a floor under how quickly your process can react. Busy polling removes the whole chain: a CPU sits in a loop asking the transfer ring whether anything is there, so the answer arrives as fast as the hardware can produce it. Network engineers will recognise the shape of this immediately, because it is the same trade made by NAPI busy polling and the SO_BUSY_POLL socket option, and the same trade that pushed high frequency trading and telecom workloads toward kernel bypass frameworks years ago. The pattern is old. What is new is that it is now a per stream toggle on a USB4 link.

What is the cost, in plain terms?

A CPU that is doing nothing but asking. Busy polling means a core spins whether or not traffic is flowing, so you pay the same cycles at idle as under load. On a laptop that shows up as heat and battery drain. On a server it is a core you cannot allocate to anything else. The patch also notes a second cost that is easy to miss: enabling busy poll prevents the use of poll(2) on the interface. That is not a footnote, it is a change in how you write the program. Anything built around an event loop that waits on file descriptors has to be restructured around the polling loop instead. If your application already runs a dedicated thread doing tight reads, the option costs you nothing you were not already spending. If it sits inside epoll with fifty other descriptors, this is not a switch you flip.

How do I turn it on, and should I?

It is a ConfigFS attribute, so it is a file. The path takes the shape /sys/kernel/config/thunderbolt/stream/[xdomain].[service]/$name/busy_poll, where the xdomain and service components identify the remote host and the service you negotiated with it. Writing to that file switches the rings for that stream, which is the right granularity: you are not making a system wide decision, you are making it for one link with one peer. Whether you should is a question about your workload, not about the feature. The honest test is whether you have measured a latency problem and traced it to interrupt and scheduling overhead rather than assumed it. Busy polling makes a real difference to workloads that are genuinely latency bound and makes everything else worse by consuming a core for nothing.

When will this actually be available?

The patches are in the thunderbolt.git next branch, which is where Thunderbolt and USB4 changes queue up before being sent to Linus during a merge window. The target is Linux 7.3. In practice that means the code is settled enough that the maintainer intends to ship it, but it has not reached a released kernel yet, and the usual caveats about anything in a subsystem next branch apply. After 7.3 releases there is then the second wait, which is your distribution shipping a kernel new enough to include it. If you run a stable distribution, that is measured in months rather than weeks. If you build your own kernels or run a rolling distribution, you will have it as soon as the release lands.