> ## Documentation Index
> Fetch the complete documentation index at: https://dragonwingdocs.qualcomm.com/llms.txt
> Use this file to discover all available pages before exploring further.

# RT validation and known limitations

Achieving deterministic latency on Qualcomm<sup>®</sup> Linux requires both the RT kernel
and correct system configuration. This page covers the tuning steps required
before running latency tests, `cyclictest` usage, and the known limitations of
the Qualcomm Linux RT kernel.

## Pre-test system tuning

Apply the following configuration steps on the target device before running
any RT validation test. Tuning must be reapplied after every reboot unless
automated via a systemd service (see
[OTA and upgrade considerations](./rt-ota-upgrade#persist-rt-tuning-across-reboots)).

### QCS6490 · IQ-9075 · IQ-615

These platforms isolate CPU 7 as the RT core. CPUs 0–6 are housekeeping CPUs.

**1. Disable timer migration**

```bash theme={null}
echo 0 > /proc/sys/kernel/timer_migration
```

**2. Affine workqueues to housekeeping CPUs (mask 0x7F = CPUs 0–6)**

```bash theme={null}
for wq in /sys/devices/virtual/workqueue/*; do
    [ -w "$wq/cpumask" ] && echo 7F > "$wq/cpumask"
done
```

**3. Set all CPU frequency governors to performance**

```bash theme={null}
for policy in /sys/devices/system/cpu/cpufreq/policy*; do
    [ -w "$policy/scaling_governor" ] && echo performance > "$policy/scaling_governor"
done
```

**4. Disable RT accounting / throttling**

```bash theme={null}
echo -1 > /proc/sys/kernel/sched_rt_runtime_us
```

**5. Set IRQ affinity to housekeeping CPUs (0–6)**

```bash theme={null}
ALLOW_CPUS="0,1,2,3,4,5,6"
cpu_list_to_mask() {
    MASK=0
    for cpu in $(echo $1 | tr ',' ' '); do
        MASK=$((MASK | (1 << cpu)))
    done
    printf "%x\n" "$MASK"
}
MASK=$(cpu_list_to_mask "$ALLOW_CPUS")
echo "Setting IRQ affinity to CPUs: $ALLOW_CPUS (mask=0x$MASK)"
for irq in /proc/irq/[0-9]*; do
    smp_file="$irq/smp_affinity"
    [ -w "$smp_file" ] && echo "$MASK" > "$smp_file" 2>/dev/null
done
```

### IQ-8275

This platform isolates CPU 3 as the RT core. CPUs 0–2 and 4–7 are
housekeeping CPUs (mask `0xF7`).

**1. Disable timer migration**

```bash theme={null}
echo 0 > /proc/sys/kernel/timer_migration
```

**2. Affine workqueues to housekeeping CPUs (mask 0xF7 = CPUs 0–2, 4–7)**

```bash theme={null}
for wq in /sys/devices/virtual/workqueue/*; do
    [ -w "$wq/cpumask" ] && echo F7 > "$wq/cpumask"
done
```

**3. Set all CPU frequency governors to performance**

```bash theme={null}
for policy in /sys/devices/system/cpu/cpufreq/policy*; do
    [ -w "$policy/scaling_governor" ] && echo performance > "$policy/scaling_governor"
done
```

**4. Disable RT accounting / throttling**

```bash theme={null}
echo -1 > /proc/sys/kernel/sched_rt_runtime_us
```

**5. Set IRQ affinity to housekeeping CPUs (0–2, 4–7)**

```bash theme={null}
ALLOW_CPUS="0,1,2,4,5,6,7"
cpu_list_to_mask() {
    MASK=0
    for cpu in $(echo $1 | tr ',' ' '); do
        MASK=$((MASK | (1 << cpu)))
    done
    printf "%x\n" "$MASK"
}
MASK=$(cpu_list_to_mask "$ALLOW_CPUS")
echo "Setting IRQ affinity to CPUs: $ALLOW_CPUS (mask=0x$MASK)"
for irq in /proc/irq/[0-9]*; do
    smp_file="$irq/smp_affinity"
    [ -w "$smp_file" ] && echo "$MASK" > "$smp_file" 2>/dev/null
done
```

## Install rt-tests via Yocto

The `cyclictest` utility is part of the upstream
[rt-tests](https://git.kernel.org/pub/scm/utils/rt-tests/rt-tests.git/) suite.
Include it in the Yocto image by appending to `IMAGE_INSTALL` in your layer
configuration:

```text theme={null}
IMAGE_INSTALL:append = " rt-tests numactl"
```

Rebuild and reflash the image. After boot, `cyclictest` is available at
`/usr/bin/cyclictest`.

## Run cyclictest

`cyclictest` measures timer latency by scheduling a periodic thread and
recording how late each wakeup occurs relative to the requested interval.

### QCS6490 · IQ-9075 · IQ-615 (RT core: CPU 7)

```bash theme={null}
cyclictest -a 7 -t 1 -m -l 100000000 -i 1000 -p 99 -h 100
```

### IQ-8275 (RT core: CPU 3)

```bash theme={null}
cyclictest -a 3 -t 1 -m -l 100000000 -i 1000 -p 99 -h 100
```

**Table: cyclictest parameter reference**

| **Flag** |  **Value**  | **Meaning**                                       |
| :------: | :---------: | :------------------------------------------------ |
|   `-a`   |  `7` or `3` | Pin test threads to the isolated RT CPU           |
|   `-t`   |     `1`     | Run 1 measurement thread                          |
|   `-m`   |      —      | Lock all memory pages (prevent page-fault jitter) |
|   `-l`   | `100000000` | Number of measurement loops (long-duration test)  |
|   `-i`   |    `1000`   | Timer interval in microseconds (1 ms)             |
|   `-p`   |     `99`    | Thread RT priority (`SCHED_FIFO`, priority 99)    |
|   `-h`   |    `100`    | Build a latency histogram up to 100 µs            |

Sample output:

```text theme={null}
# /dev/cpu_dma_latency set to 0us
policy: fifo: loadavg: 0.00 0.00 0.00

T: 0 ( 1234) P:99 I:1000 C:100000000 Min:      3 Act:    4 Avg:    5 Max:     42
```

The `Max` field is the worst-case latency in microseconds. On a properly
tuned system this should remain below 100 µs on QCS6490, IQ-9075, and
IQ-615, and below the same threshold on IQ-8275 with tuning applied.

For complete documentation and additional test tools (`hackbench`,
`oslat`, `pi_stress`), see
[RT-Tests documentation](https://wiki.linuxfoundation.org/realtime/documentation/howto/tools/rt-tests).

## Known limitations

**Kernel space only**

`PREEMPT_RT` provides deterministic scheduling for kernel threads and
interrupt handlers. User-space applications must explicitly opt in to RT
scheduling using `SCHED_FIFO` or `SCHED_RR` policies (via `sched_setscheduler`)
and must be pinned to isolated CPU cores using `taskset` or `cpuset`. A
user-space process running with `SCHED_OTHER` (default) on a shared CPU will
not benefit from the RT kernel.

**Thermal throttling**

Qualcomm SoCs apply thermal mitigation that reduces CPU frequency when the
SoC temperature rises. Even with the `performance` governor set, thermal
events can temporarily lower the CPU frequency of the RT core, introducing
latency spikes. On long-duration production tests, monitor thermal state:

```bash theme={null}
cat /sys/devices/virtual/thermal/thermal_zone*/temp
```

Consider reducing system load or improving thermal dissipation if the
junction temperature regularly exceeds the throttling threshold.

**Remoteproc firmware authentication**

On first boot, the aDSP, cDSP, and WPSS subsystems load and authenticate
firmware via TrustZone. This process runs during `device_initcall` and can
take several seconds, briefly stressing the memory bus and introducing
latency spikes in early-boot RT measurements. Run RT validation only after
all remoteproc subsystems have fully started:

```bash theme={null}
# Confirm all subsystems are running before testing
cat /sys/class/remoteproc/remoteproc*/state
# Expected: running (for each enabled subsystem)
```

**SMT / Hyper-Threading**

Qualcomm ARM64 SoCs do not implement simultaneous multithreading (SMT). The
CPU isolation model (`isolcpus`, `nohz_full`, `rcu_nocbs`) is therefore
simpler than on x86 where there are no sibling threads sharing execution resources
with the RT core.

**`sched_rt_runtime_us` and watchdog**

Setting `sched_rt_runtime_us` to `-1` (unlimited) disables the RT throttle
that prevents RT tasks from starving CFS tasks. This is required for
deterministic latency but means a runaway RT task can lock the system. Enable
the RT kernel watchdog (`CONFIG_DETECT_HUNG_TASK=y`, `hung_task_timeout_secs`)
in production configurations to mitigate this risk.

**EFI runtime services**

When `PREEMPT_RT` is enabled, the kernel's `EFI_DISABLE_RUNTIME` Kconfig option
defaults to `y` (see `drivers/firmware/efi/Kconfig`). This intentionally disables
EFI runtime services to eliminate the large, unpredictable latency that UEFI
firmware calls can introduce into the RT scheduling path.

On Qualcomm platforms this has practical consequences: EFI runtime services are
required for enabling user to configure boottime dtb overlay (writing the
`VendorDtbOverlays` EFI variable).  EFI runtime services currently is enabled in
yocto configs by passing `efi=runtime` on the kernel command line by appending
the following parameter to `RT_KERNEL_CMDLINE` in
`conf/machine/include/qcom-common.inc`:

```text theme={null}
RT_KERNEL_CMDLINE:append = " efi=runtime"
```

<Caution>
  Evaluate whether your production configuration genuinely requires EFI runtime
  services and disable them (the default) if deterministic worst-case latency is
  the primary requirement.
</Caution>
