Skip to main content

TECH VEDA

Embedded Linux on Edge-AI 23rd Sept 2026 enrollingLinux kernel & Device drivers starts on 24th Oct 2026 enrollingCorporate on-site training - Submit proposal Pick your modulesSharpen your kernel skills: deep dives, drivers, Yocto, CVEs, careers — updated daily. Read the blog →Embedded Linux fast track starts 23rd sept 2026 enrollingEmbedded Linux Mastery track starts 23rd sept 2026 enrollingLinux systems engineering starts 23rd sept 2026 enrolling
News

Linux Makes the x86 TSC a Baseline: What Changes for Embedded Systems?

Linux now treats the x86 TSC as a baseline and requires the Time Stamp Counter. How Arm, RISC-V and others guarantee a counter, and how to check yours.

Linux Makes the x86 TSC a Baseline: What Changes for Embedded Systems?

The x86 Time Stamp Counter is now part of the Linux kernel’s hardware baseline: since 7.2, CONFIG_X86_TSC is unconditional and every supported x86 processor is expected to provide the counter. For embedded systems the change matters in two ways. It draws a hard boundary for long-lived products on 486-class silicon, which now live on frozen pre-7.2 kernels. And it makes visible a question every architecture answers differently: what clock can the kernel take for granted? Arm settled it with the mandatory Generic Timer in ARMv8, RISC-V architected a counter in from the start, and 32-bit Arm never had one — and paid for it in driver fragmentation.

A hardware baseline is the set of features the kernel assumes every supported processor provides. On x86 that set just grew. Since Linux 7.2, released on 16 August, the Time Stamp Counter is part of it: the commit “x86/cpu: Make CONFIG_X86_TSC unconditional” removes the build-time option, and the code paths that existed for TSC-less processors are being stripped out separately. The change drew little attention when it was queued in June, which is exactly why it is worth a careful look now.

The answer to the question in the title comes in three parts. For most products, nothing changes and nothing needs doing. For a small class of legacy x86 systems, the support boundary is now fixed. And for anyone choosing or maintaining a platform, the comparison with Arm and RISC-V shows what a guaranteed counter is worth: it is the difference between one timer driver for an entire architecture and the long list of vendor timer drivers that 32-bit Arm still carries.

What the TSC is, and why the kernel wanted it mandatory

The Time Stamp Counter is a per-CPU register that counts up continuously from reset, read with the RDTSC instruction. It has been present in every Intel and AMD processor since the original Pentium in 1993. It is the cheapest high-resolution time source x86 has: a userspace read costs a few tens of cycles, with no I/O port access and no interrupt.

Modern kernels lean on it heavily. On most x86 systems the TSC is the clocksource behind gettimeofday() and clock_gettime(), the basis of sched_clock() for scheduler timestamps, and the reference the timekeeping code calibrates against — the logic lives in arch/x86/kernel/tsc.c. The flags in /proc/cpuinfo describe different properties: tsc means the counter exists; constant_tsc that its rate stays stable across frequency changes; nonstop_tsc that it keeps counting through deep idle states. The flags alone decide nothing — the kernel still evaluates the counter at boot and can demote the TSC to another clocksource if calibration or platform behaviour makes it unreliable.

Until 7.2, all of this was conditional. Because the kernel still nominally supported i486-class processors — which have no TSC — every timing path needed a fallback, typically through the PIT or other legacy timers, and CONFIG_X86_TSC existed to build kernels for hardware without the register. The recent removals of i486, AMD K5, and AMD Elan support took away the last in-tree users of those fallbacks. Making TSC unconditional is the follow-through: the option disappears, and with it the maintenance cost of timing code that almost no running system has exercised in years.

The precise sequence matters, because the cleanup spans releases:

  • Over the preceding cycles, i486-class, AMD K5, and AMD Elan support were removed — the last in-tree users of TSC-less timing paths.
  • Linux 7.2 (released 16 August 2026) makes CONFIG_X86_TSC unconditional; the 7.2 changelog records the step as “Remove support for TSC-less and CX8-less CPUs” — the CMPXCHG8B instruction (the cx8 flag) became part of the same baseline.
  • The remaining code paths that existed only for TSC-less processors are being removed separately as the cleanup proceeds; the Kconfig option went first.

One distinction is worth stating precisely: unconditional CONFIG_X86_TSC is a build-time statement about which CPUs the kernel supports, not a promise about the running clocksource. The kernel still validates the TSC at boot and falls back to HPET or the ACPI PM timer on machines where it proves unreliable.

Who is actually affected

On mainstream hardware: nobody. Every x86 processor that remains supported provides a TSC — mainstream Intel and AMD parts have carried one since the original Pentium in 1993, and the removed compatibility range is 486-class parts plus early or clone x86 designs without the counter. A distribution kernel has assumed a working TSC in practice for a long time. There is no new firmware requirement, no security co-processor, nothing to buy. The comparison some coverage drew with Windows 11’s TPM requirement does not hold; this is the removal of dead code for processors that predate the 1993 Pentium, not a gate on current ones.

The population that does need to pay attention is small and specific: long-lived industrial and retro systems on 486-class silicon, including embedded boards built on 486-class IP cores, and hobbyist machines from the early 1990s. From 7.2 onward the mainline kernel simply does not support a TSC-less x86 processor; the last kernels that do are the pre-7.2 series, and that is now a fixed boundary you plan around rather than a configuration you select.

Why this change is x86-only

The commit touches only x86 because only x86 had this particular debt. Two conditions had to hold for such a change to exist at all: the architecture defines a standard counter, and the kernel still carried support for processors without it. On x86 both were true — the TSC has been architecturally standard since 1993, yet the tree still supported pre-TSC processors, so a Kconfig option and fallback code had to exist. Once the i486-class removals took the last TSC-less hardware out of the tree, the option became meaningless and could be deleted. CONFIG_X86_TSC never had an equivalent on other architectures because no other port was in that position.

Everywhere else, one of the two conditions fails. On arm64, RISC-V, PowerPC, and s390 the counter has been mandatory in the architecture from the start, so there was never a “without it” configuration to remove. On 32-bit Arm the opposite is true: most older cores have no architected counter at all, so there is nothing to make mandatory — the kernel instead retires the platforms themselves, which is exactly what the 7.3 deprecations do. The x86 change is one architecture catching up, in its own way, to a guarantee the others either always had or will reach by removal.

How Arm handles the same problem

The x86 situation — one architected counter, guaranteed everywhere — is what 32-bit Arm never had, and embedded Linux carries the consequences to this day. Through the ARMv5 and ARMv6 generations and most of ARMv7, the timekeeping counter was not part of the architecture at all. It was a vendor peripheral: TI SoCs brought their dual-mode timers, i.MX parts their GPT, PXA its OS timer, and each one needed its own kernel driver and device tree binding. That is a large part of why drivers/clocksource/ contains such a long list of single-SoC timer drivers, and why bringing up an old Arm board always includes the question of which timer the kernel should trust.

The architecture fixed this in two steps. ARMv7-A introduced the Generic Timer as an optional extension — Cortex-A15 and Cortex-A7 have it, while the older Cortex-A8 and A9 do not; an A9 system instead uses its per-core TWD private timers plus a SoC-level timer. ARMv8 then made the Generic Timer mandatory. Every arm64 CPU carries an architected system counter with a discoverable frequency (CNTFRQ_EL0) and a virtual count register (CNTVCT_EL0) that userspace can read directly. One driver, drivers/clocksource/arm_arch_timer.c, covers every arm64 machine ever made.

This is why arm64 will never need a cleanup like the one x86 just performed: the guarantee x86 reached in 2026 by deprecating three decades of hardware, arm64 shipped with in 2011 as an architectural requirement. The fragmented 32-bit era is instead being retired the direct way — the 7.3 SoC pull we covered this week marks the pre-device-tree board files and the Cortex-M/ARM1136 platforms deprecated, and the vendor timer drivers that exist only for removed platforms become removable with them.

RISC-V and the older architectures

RISC-V, arriving latest, had the benefit of both examples. The unprivileged specification architects a time CSR from the start — a monotonically incrementing real-time counter readable with the rdtime instruction, with its frequency published to the kernel through the device tree timebase-frequency property. drivers/clocksource/timer-riscv.c is the single driver. The counter and the timer-interrupt mechanism are distinct things — rdtime reads the former. The more recent Sstc extension adds a supervisor-level timer compare register (stimecmp), letting the kernel program its next timer event directly instead of trapping into SBI firmware for every tick — a latency refinement, not a rescue of a missing feature.

The older server architectures made the same choice decades earlier: PowerPC has carried an architected Time Base register since the first PowerPC processors, and s390’s TOD clock has been part of the architecture from the beginning. MIPS sits closer to the x86 story — the CP0 Count register arrived with the R4000, so the earliest MIPS parts lack it and the port kept fallbacks around. The pattern across all of them is consistent: architectures that guaranteed a counter early have one timer driver and no legacy tail; architectures that left it optional spent decades maintaining fallbacks and are only now allowed to delete them.

The practical payoff of a guaranteed, userspace-readable counter is the vDSO fast path. clock_gettime() without a system call requires a counter userspace can read directly — the TSC on x86, CNTVCT_EL0 on arm64, rdtime on RISC-V. Where no such counter exists, every timestamp is a full syscall, and time-heavy workloads (tracing, logging, latency measurement, financial and telecom loads) pay for it on every call.

How to check your systems

Three quick checks answer the question on any Linux box. The first shows whether the x86 TSC and its quality flags are present; the second shows what clocksources the kernel found on this machine; the third shows which one it is actually using:

raghu@techveda.org:~$ grep -owE 'nonstop_tsc|constant_tsc|tsc' /proc/cpuinfo | sort -u
raghu@techveda.org:~$ cat /sys/devices/system/clocksource/clocksource0/available_clocksource
raghu@techveda.org:~$ cat /sys/devices/system/clocksource/clocksource0/current_clocksource

On modern x86, expect all three flags and a current clocksource of tsc. On arm64 the same sysfs files report arch_sys_counter; on RISC-V, riscv_clocksource. If an x86 machine reads hpet or acpi_pm instead, the kernel distrusted the TSC on that hardware (unstable calibration, broken firmware tables) — worth investigating separately, but unrelated to this change. On an older 32-bit Arm board, the available list names the vendor timer the platform depends on — the fragmentation story above, visible in one file.

What it means for teams on legacy hardware

If you maintain a product on TSC-less x86 silicon, the decision is the familiar one from every removal cycle: the platform now lives on a frozen kernel. Pin the newest pre-7.2 series that supports your hardware, write down why, and check its end-of-life date against your product’s remaining life — our kernel lifecycle tracker keeps the current LTS dates. While reviewing such a platform, also check its 32-bit time_t status — an unrelated problem technically, but the same long-lived products that need a frozen kernel pin are usually the ones still counting time in 32 bits, so the one review should cover both. Teams on pre-ARMv7 or early-ARMv7 Arm boards should read the 7.3 deprecation list the same way: the timer driver your board depends on lives or dies with the platform’s board file.

FAQ

How do I check if my CPU has a TSC?

Look for the tsc flag in /proc/cpuinfo. The additional flags constant_tsc and nonstop_tsc indicate a TSC that ticks at a fixed rate and keeps running in idle states, which is what modern timekeeping expects.

Which CPUs are affected by the Linux TSC requirement?

Only x86 processors without a TSC — 486-class parts and some early or clone 586-class designs. Mainstream Intel and AMD processors have included one since the original Pentium (1993) and are unaffected.

Does Arm have an equivalent of the x86 TSC?

Yes — the Generic Timer, an architected system counter with the CNTVCT_EL0 count register and CNTFRQ_EL0 frequency register. It is mandatory on every ARMv8/arm64 processor and optional on late ARMv7 cores; older 32-bit Arm SoCs used vendor-specific timer peripherals instead, each with its own kernel driver.

What if my product runs on TSC-less x86 hardware?

Stay on a pre-7.2 kernel series, pin it deliberately with a written record, and check that series’ end-of-life date against your product’s remaining lifetime. Plan the hardware migration around that date rather than around the next kernel upgrade.

References

— Raghu Bharadwaj

Was this worth your time?
RB
Raghu Bharadwaj

Founder, TECH VEDA — 20+ years teaching the Linux kernel, device drivers and embedded systems.

Follow on LinkedIn

Get new posts by email

Kernel, embedded Linux and AI-era engineering — a few sharp reads a month. No spam.

We email occasionally and never share your address.