Skip to content

irqchip/apple-aic: Report the effective affinity of AICv2+ IRQs - #228

Merged
maralcbr merged 1 commit into
integration/aurorafrom
neo/aic2-effective-affinity-20261025
Oct 26, 2026
Merged

maralcbr merged 1 commit into
integration/aurorafrom
neo/aic2-effective-affinity-20261025

Conversation

@DjDeveloperr

@DjDeveloperr DjDeveloperr commented Oct 25, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

AICv2+ has no per-IRQ CPU target. Each CPU says in its SIQ_CFG system register whether it accepts IRQs; routing field (bits 1:0) = 3 means it never receives one. On T8140 (Neo) CPU 0 reads 0 and every secondary reads 3, so every hardware IRQ lands on CPU 0. Because the AICv2 irqchip has no irq_set_affinity, the effective affinity stayed empty, and threaded handlers floated to any CPU. Where the G17 GPU's mailbox receive IRQ is threaded, the GPU completion thread (irq/65) often ran on the app's CPU, which saturated it and caused a bimodal "slow mode" in latency-sensitive GPU workloads. That is the case on the aurora-silicon tree, where the measurements below were taken.

On integration/aurora, the GPU mailbox receive IRQ is a plain hard IRQ (also with #229), so GPU completions already run on CPU 0 and this change does not move them. There it binds the threaded handlers that do exist, such as Wi-Fi MSI (mt7932), dockchannel, Bluetooth, AVD, audio and ISP, to CPU 0, where their hard IRQs arrive, and reports the effective affinity correctly. The GPU latency gains below apply once the GPU mailbox handler is threaded.

On SoCs whose routing has been verified on hardware (currently T8140), and only at EL2, AICv2+ IRQs map to a second irqchip, aic2_routed_chip. It records at CPU bring-up which CPUs accept IRQs and reports them as each IRQ's effective affinity, so genirq binds threaded handlers to the CPU(s) the hard IRQ actually arrives on.

Safety and scope:

  • The register is read only on T8140 and only at EL2, gated by per-SoC match data (apple,t8140-aic3).
  • Every other AIC2 SoC (M1 Pro/Max, M2, M3, M5 T8142, …) keeps the existing aic2_chip byte for byte. smp_affinity writes still fail there, and MSI affinity calls don't reach AIC.
  • AICv1 is unchanged.
  • A SoC joins the list only after a hardware boot test.
  • The accepting set grows as CPUs start, and existing IRQs keep theirs. That is enough while only one CPU accepts IRQs; a SoC with more than one would also need an online refresh, as the code comment says.

Behaviour change on T8140 (at EL2): every ordinary AIC IRQ thread, PCIe MSI ones included, now runs on CPU 0, and smp_affinity writes don't move it. They are accepted and kept only for reporting. The CPU 0 load numbers below cover this for gpubench.

Hardware evidence (Neo, T8140, aurora-silicon 7.3 tree with the threaded GPU mailbox)

  • Routing probe on a spare AIC line:

    • all 32×6 triggers landed on CPU 0, from any firing CPU, even with CPU 0 masked for 35 ms;
    • setting a secondary's field to 2 made it a fallback, and 1 made it preferred.
  • New core: irq/65 on CPU 0 in 100% of 50 ms samples, and /proc/irq/65/effective_affinity_list = 0. On the old core it was on CPU 5 64–99% of the time, with an empty effective affinity.

  • Benchmarks (gpubench, µs/submit, 2 new-core boots vs 3 old-core boots; slow rounds in brackets):

    row old new
    compute d2, unpinned 47.9 / 46.9 / 49.2 (10, 10, 7 of 10 slow) 37.5 / 36.9 (0, 0)
    compute d2, app on CPU 5 57.4 (7) 37.9 (0)
    render d32, app on CPU 5 38.4 (7) 30.5 (0)
    render d1, app on CPU 0 127.9 107.6

    Slow rows overall: 20/30 + 20/30 + 54/80 → 8/30 + 12/80. Other rows are unchanged.

  • CPU 0 load: not overloaded (69–70% busy under render d32 vs 54–57% before), and its 1 ms timer lateness improved (p99 81–83 µs vs 105–115).

Base

The same change on 7.2.11; it applies unchanged. The measurements above were taken on Neo with the 7.3 kernel. This branch builds cleanly on 7.2.11 with the Neo config; a Neo boot test of the 7.2.11 build follows.

@greptile-apps

greptile-apps Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge, with the previous hotplug finding addressed and no new blocking issues found.

Summary

The PR reports the CPUs that receive hardware IRQs on T8140 at EL2, allowing IRQ threads to run on those CPUs.

  • T8140 IRQs report the CPUs that accept them as their effective affinity.

Reviews (2) · Last reviewed commit: "irqchip/apple-aic: Report the effective ..." · Reviewed by Greptile

Comment thread drivers/irqchip/irq-apple-aic.c Resolved
@DjDeveloperr
DjDeveloperr force-pushed the neo/aic2-effective-affinity-20261025 branch 2 times, most recently from 4542a65 to 4e2f3fa Compare October 25, 2026 22:36

@maralcbr maralcbr left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @DjDeveloperr, this is a nice find. The before/after irq/65 placement and the gpubench numbers make a convincing case for T8140. No blockers in the code.

Checked and fine:

  • The gate is in the right place. Only apple,t8140-aic3 sets siq_cfg_routing (irq-apple-aic.c:322-328). t8140.dtsi:677 lists that compatible first, so it wins the match. The register is read only at EL2 (:1010).
  • The reported set no longer depends on which CPUs are online (:502-504), so a CPU onlined late can't narrow it. On the other AICv2+ SoCs, threads get cpu_possible_mask, which is where they sit on the base anyway (kernel/irq/manage.c:1432).
  • The commit carries a Signed-off-by now. check-commits.py passes locally, and checkpatch is clean on the diff.

Smaller things, none blocking:

  • The other AICv2+ SoCs aren't quite unchanged. aic2_chip now has irq_set_affinity everywhere (:550). On M1 Pro/Max, M2 and M3, a write to /proc/irq/N/smp_affinity now succeeds and is ignored, where it used to fail with -EPERM, and smp_affinity then shows whatever was written. PCIe MSI affinity calls now reach AIC as well and rewrite the same MSI message. I don't see harm in any of that, and AICv1 already takes the MSI path. If you'd rather keep those SoCs exactly as they are, a second chip that aic_irq_domain_map (:728-729) picks only when siq_cfg_routing && is_kernel_in_hyp_mode() would do it. Otherwise, please list these changes in the PR body.
  • Please note the T8140 behaviour change in the PR body. At EL2, every ordinary AIC IRQ thread now runs on CPU 0, PCIe MSI ones included, and smp_affinity writes don't move it. Your CPU 0 load numbers cover that for gpubench.
  • nit: the comment at :497-500 says the set doesn't depend on which CPUs are online. On the SIQ_CFG path, though, bits are added as each CPU starts (:1012-1018), and existing IRQs aren't refreshed. That's fine while only CPU 0 accepts IRQs. A line by siq_cfg_routing (:275) would help whoever adds the next SoC: one with more than one accepting CPU would need a refresh when a CPU comes online.
  • nit: the PR body still says checkpatch is clean "apart from Signed-off-by, which this repo doesn't use". The repo does require it (tools/aurora-ci/README.rst:52-54), and the commit now has one, so that line can go.

CI was still running when I looked. Only plan and the CI self-test had passed, so commits, compile, device trees, host tests, package and KUnit hadn't finished on this head. I'll approve once they're green.

For release (not the source merge): the tested boots used the ungated 7.3 build. Please post the Neo boot of this 7.2.11 build, showing /proc/irq/65/effective_affinity_list and where irq/65 runs. CI's boot test is QEMU-only, and the chip change reaches every AICv2+ SoC. So unless it moves to a separate chip, I'll also boot it on our M2 Max with Wi-Fi up before release.

Comment thread drivers/irqchip/irq-apple-aic.c Outdated
.irq_mask = aic_irq_mask,
.irq_unmask = aic_irq_unmask,
.irq_eoi = aic_irq_eoi,
.irq_set_affinity = aic_irq_set_affinity,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This reaches every AICv2+ SoC. On those, smp_affinity writes now succeed and are ignored, and MSI affinity calls reach AIC. I'm fine with that if it's listed in the PR body. A separate chip, picked only when siq_cfg_routing && is_kernel_in_hyp_mode(), would keep the other SoCs unchanged.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to a separate chip in 1a10581: aic_irq_domain_map() picks aic2_routed_chip only when siq_cfg_routing && is_kernel_in_hyp_mode(). Every other SoC maps to the unchanged aic2_chip, so smp_affinity writes still fail there and MSI affinity calls don't reach AIC. aic_irq_set_affinity() is back to its original AICv1-only form.

Comment thread drivers/irqchip/irq-apple-aic.c Outdated
* Report those CPUs, so that threaded handlers run where the
* hard IRQ is taken; where SIQ_CFG was not read, any CPU may
* take it. The set does not depend on which CPUs are online,
* so CPU hotplug never narrows it.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: on the SIQ_CFG path the set grows as CPUs start (:1012-1018), and existing IRQs aren't refreshed. So "does not depend on which CPUs are online" only holds while just CPU 0 accepts IRQs.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. The comment no longer makes that claim. The routed chip's comment says what the callback does, and the siq_cfg_routing field comment says the set grows as CPUs start while existing IRQs keep theirs, which is enough only while one CPU accepts IRQs.

Comment thread drivers/irqchip/irq-apple-aic.c Resolved
AICv2 and later have no per-IRQ CPU target. The controller hands each
hardware IRQ to one of the CPUs that accept IRQs, and each CPU says
whether it does in its SIQ_CFG system register: a CPU whose routing
field (bits 1:0) reads 3 never receives one. On T8140 the boot CPU reads
0 and every secondary reads 3, so every hardware IRQ is taken on CPU 0,
even while CPU 0 holds IRQs masked for tens of milliseconds. Setting a
secondary to 1 or 2 makes the controller deliver to it as well.

The AICv2 irqchip has no irq_set_affinity, so the effective affinity of
its IRQs stays empty and their threaded handlers may run on any CPU. The
scheduler often places them away from the CPU taking the hard IRQ, which
adds a cross-CPU wakeup to every interrupt.

On SoCs where this routing has been verified on hardware, currently
T8140, and only at EL2, since a hypervisor or secure monitor may trap
SIQ_CFG, map AICv2+ IRQs to a second irqchip. It records at CPU bring-up
which CPUs accept IRQs and reports them as each IRQ's effective
affinity, so that genirq binds threaded handlers to the CPUs the hard
IRQ arrives on. The requested mask cannot change delivery; it is
accepted and kept only for reporting. On T8140 every AIC IRQ thread,
PCIe MSI ones included, therefore runs on CPU 0, and smp_affinity writes
do not move it. Every other SoC keeps the existing irqchip unchanged.

The accepting set grows as CPUs start and existing IRQs keep theirs,
which is enough while only one CPU accepts IRQs. A SoC with more than
one accepting CPU would also need the masks refreshed when such a CPU
comes online.

On T8140 the G17 GPU completion thread used to run on CPU 5 most of the
time and now stays on CPU 0. Over two boots of each kernel, compute
submission at depth 2 goes from 47-49 us to 37 us per submit, and render
submission at depth 1 from a CPU 0 submitter from 128 us to 108 us.
Other submission rows are unchanged.

(cherry picked from commit 28ceabd)
Signed-off-by: DjDeveloperr <hey@djdev.me>
@DjDeveloperr
DjDeveloperr force-pushed the neo/aic2-effective-affinity-20261025 branch from 4e2f3fa to 1a10581 Compare October 25, 2026 22:59
@DjDeveloperr

Copy link
Copy Markdown
Collaborator Author

Thanks for the careful review. Changes are in 1a10581:

  • Other AICv2+ SoCs are now unchanged. I moved the change to a separate chip: aic_irq_domain_map() uses aic2_routed_chip only when siq_cfg_routing && is_kernel_in_hyp_mode(), and every other SoC keeps the existing aic2_chip. aic_irq_set_affinity() is back to its original form.
  • T8140 behaviour change. It is now in the PR body and the commit message: at EL2, every ordinary AIC IRQ thread, PCIe MSI ones included, runs on CPU 0, and smp_affinity writes don't move it.
  • Comments. They no longer claim the set is independent of online CPUs on the SIQ_CFG path. The siq_cfg_routing field notes that a SoC with more than one accepting CPU would also need an online refresh.
  • PR body. The stale Signed-off-by line is gone.

It builds cleanly on 7.2.11 with the Neo config. I'll post the Neo boot of the 7.2.11 build showing /proc/irq/65/effective_affinity_list and where irq/65 runs. Since the change no longer reaches other SoCs, the M2 Max boot shouldn't be needed.

@maralcbr maralcbr left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed at 4e2f3fa (source only; no build or boot on my side).

The approach matches what the hardware does: on AICv2+ the hard IRQ lands wherever SIQ_CFG allows, so reporting that set as the effective affinity is the right way to get threaded handlers onto the same CPU. Gating the SIQ_CFG read to T8140 at EL2, and making the reported set independent of which CPUs are online, both look correct. CPU0 offline isn't reachable on Neo with spin-table.

Before merge:

  • Test the exact build. The PR body says the Neo boots used a build without the per-SoC gate, and the gated build was compile-checked only. Please boot this head on Neo (on 7.2.11, which the body also says is still to come) and re-check irq/65 placement and effective_affinity_list.
  • Every AICv2+ SoC changes, not just Neo. aic2_chip now has irq_set_affinity, so on M1 Pro/Max, M2, M3 and later, request_irq(), irqbalance and /proc/irq/*/smp_affinity writes now succeed (without steering anything), and the effective mask becomes cpu_possible_mask. That should behave like today, but it is untested. I'll boot it on our M2 lab machine; a run on an M1 Pro/Max or M3 would also help.
  • Design call for the maintainers. On Neo every threaded AIC handler (GPU, NVMe, Wi-Fi, …) is now pinned to CPU0, a Tahiti E-core (capacity 712). The numbers show a clear win for GPU latency and CPU0 at ~70% under render d32, but combined I/O + GPU load hasn't been measured. Worth a run with NVMe and Wi-Fi traffic alongside the GPU benchmark.

As with #226 and #227, one combined run on the exact base with all three applied would be the most useful evidence, since they all act on the same utilisation and frequency loop.

@chriskearney chriskearney left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Source review at 1a10581c385e8a78f966824be91d8f03072ce2ba: the separate routed irqchip addresses the shared-path concern in the earlier review. M3 Pro's T6030 compatible still selects aic3_info with siq_cfg_routing=false, retaining the original aic2_chip without an affinity callback. Both the SIQ register read and new routed-chip selection require the T8140 flag plus EL2.

I found no new source blocker in that gate or the unchanged M3 IRQ/MSI path. The comment correctly limits the current mask scheme to the single-accepting-CPU case; adding another accepting CPU/SoC later would require refreshing existing effective masks.

Remaining target qualification is the final 7.2.11 Neo build: actual effective affinity/thread placement, ordinary and PCIe MSI device operation, and suspend/resume. A clean M3 regression run cannot validate the Neo register access or latency gain.

Validation here is source review of the changed controller paths and M3 Pro DT compatibility. No independent physical boot of this head yet.

@DjDeveloperr

Copy link
Copy Markdown
Collaborator Author

Thanks. This review was at 4e2f3fa; the current head is 1a10581.

  • Every AICv2+ SoC changing. No longer the case. The change moved to a separate aic2_routed_chip, which aic_irq_domain_map() uses only when siq_cfg_routing && is_kernel_in_hyp_mode(). M1 Pro/Max, M2, M3 and later keep the existing aic2_chip unchanged: no irq_set_affinity, so smp_affinity writes fail as before and the effective mask isn't touched. An M2 boot shouldn't be needed for this anymore, though it's welcome.
  • CPU 0 on Neo. It is a P-core, not an E-core. On Neo, cpu0 and cpu5 form policy0 (capacity 1024, 4.044 GHz), and cpu1–cpu4 are the E-cores (capacity 426, 2.424 GHz). So the threaded AIC handlers run on a P-core.
  • Exact build and combined load. Under way as one 7.2.11 boot with soc: apple: clpc: raise the T8140 fabric floor for GPU work #226, cpufreq: apple: verify T8140 transitions on the next request #227 and irqchip/apple-aic: Report the effective affinity of AICv2+ IRQs #228 applied, against the same base without them. It records irq/65 placement and effective_affinity_list, and runs combined NVMe + Wi-Fi + GPU load: GPU latency rows, I/O throughput, CPU 0 utilisation, and timeout and lost-device counts. I'll post the results here.

@maralcbr maralcbr left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow-up at 1a10581 (source only).

Two corrections to my previous review. I posted it against 4e2f3fa after you had already pushed this head, so the "every AICv2+ SoC changes" point was already addressed. And you're right about CPU 0: Linux makes the boot CPU logical CPU 0, and Neo boots on the P-core at cpu@10100. I had read the DT order as the logical order. Sorry about both.

The separate aic2_routed_chip, selected only when siq_cfg_routing is set at EL2, keeps every other SoC on the unchanged aic2_chip, and the single-accepting-CPU limitation is documented where a future SoC would need it. No further code comments; I agree with Chris's source review.

Ready to merge from my side once the combined 7.2.11 Neo run reports thread placement and effective_affinity_list, ordinary and PCIe MSI device operation under combined NVMe + Wi-Fi + GPU load, and suspend/resume.

@DjDeveloperr

Copy link
Copy Markdown
Collaborator Author

Results from the combined 7.2.11 Neo run with this head (1a10581), together with #226 and #227:

  • Placement: irq 65 (482600000.mailbox-recv, AIC2 hwirq 66532) has effective_affinity_list 0 and smp_affinity_list 0-5. Both held at boot and after both suspend cycles, and every interrupt was counted on CPU0. The interrupt is not threaded. CPU0 is the P-core at cpu@10100 (cpu_capacity 1024).
  • MSI and ordinary device interrupts under load: Wi-Fi (MT7932, PCIe MSI, irq 95) and NVMe (nvme-apple, AIC2 hwirq 66575) both report effective affinity 0. The load was 14 s of GPU rows with an NVMe write/read loop (1146 MB/s write, 3076 MB/s read) and a Wi-Fi download loop (4.5 MB/s). During it:
    • 170,914 mailbox, 51,689 NVMe and 18,234 MSI interrupts, all on CPU0;
    • CPU0 at 29.8% utilisation;
    • no timeout, lost-interrupt, reset or fault lines from nvme, mt79, asahi or pcie.
  • Suspend/resume: two pm_test (freeze) cycles, at devices and at platform (late and noirq phases). Real s2idle does not resume on Neo yet. Both cycles were clean, irq 65 and the MSI and NVMe interrupts kept effective affinity 0, and Wi-Fi re-associated within 10 s and downloaded 50 MB after each.

All of these interrupts share CPU0, because SIQ_CFG accepts only that CPU here. Under the combined I/O load, render.light d2 on omacom's asahi driver was 22% slower (66.1 → 80.8 µs per submit).

@maralcbr maralcbr left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the combined run at 1a10581. Placement and device health look good: effective affinity 0 for the mailbox, NVMe and Wi-Fi MSI, no timeouts or resets under load, and it holds across both suspend cycles.

Two things before merge:

  1. Which handler does this actually move? The run says irq 65 "is not threaded", but the PR's premise is that the threaded GPU completion handler (irq/65) floated to the app's CPU, and the gains were explained that way. This change only affects threaded handlers: the hard IRQ already arrives only on CPU 0 because of SIQ_CFG, and this PR just reports that. Could you list the actual handler and thread identities involved (e.g. ps -eLo pid,psr,comm | grep irq/, /proc/irq/*/actions, and which kthread or workqueue runs GPU completion), with where each ran before and after? If irq 65 has no thread, what explains the latency gains?

  2. A matched comparison under combined load. "render.light d2 22% slower (66.1 → 80.8 µs) under combined I/O" compares load against no load; it doesn't show whether this change makes contention better or worse. Please run the same combined NVMe + Wi-Fi + GPU load with and without #228 on the same base, keeping #226 and #227 fixed, and report the GPU latency rows, I/O throughput and CPU 0 utilisation. Average utilisation (29.8%) can't rule out burst contention, so per-interval peaks or irq/ thread run-delay would help.

Real suspend/resume also stays unqualified until s2idle resumes on Neo. That's fine to defer, as on #227.

@DjDeveloperr

Copy link
Copy Markdown
Collaborator Author

Good catch. The combined run couldn't show the effect in the description, and I should have spelled out why.

1. Which handler.

  • Where the description's numbers come from. They were measured on the aurora-silicon 7.3 tree. There, the G17 GPU's mailbox receive IRQ is requested threaded: in drivers/soc/apple/mailbox.c, the GPU mailbox uses devm_request_threaded_irq() with no hard handler and IRQF_ONESHOT. GPU completions therefore run in the irq/65 kthread. That is the thread that ran on CPU 5 64–99% of the time before and on CPU 0 after.
  • integration/aurora. That IRQ is a plain hard IRQ there, and the combined run used omacom's asahi driver, so irq 65 had no thread. GPU completions already run in hard-IRQ context on CPU 0, and this PR does not move them. drm/asahi: G17 (Neo, T8140) driver update for 7.2.11 #229 doesn't carry the threaded mailbox change either.
  • What this PR changes on integration/aurora today. It binds the threaded handlers that do exist to CPU 0, where their hard IRQs arrive, and reports effective affinity correctly. Those handlers include irq/95 mt7932 (Wi-Fi MSI), irq/94 dockchannel, irq/113 mt7932-bt, avd, cs42l42 and isp.

I'll update the description so the GPU latency gains are scoped to trees where the GPU mailbox handler is threaded. I'll also post the thread identities and placement with and without this PR on both trees: ps -eLo pid,psr,comm, /proc/irq/*/actions, and where GPU completion runs.

2. Matched comparison. Agreed. I'll run the same combined NVMe + Wi-Fi + GPU load with and without this PR, on the same base with #226 and #227 fixed. I'll report the GPU rows, I/O throughput, CPU 0 utilisation per interval with peaks, and run delay for the irq/ threads.

@DjDeveloperr

Copy link
Copy Markdown
Collaborator Author

Both asks, measured on Neo. Each variant was built in the same tree, with one one-shot boot each:

vmlinux BTF differs between the two, so each variant got its own modules. The aurora-silicon 7.3 kernel was captured for identities only.

1. Thread identities and placement

  • Delivery: every AIC2 IRQ is delivered on CPU0 in all three kernels; the per-CPU counts are non-zero only on CPU0. The GPU mailbox, irq 65 (482600000.mailbox-recv, hwirq 66532), took 5763 interrupts in A, 5776 in B and 14920 on 7.3, all on CPU0.
  • What this PR changes: reporting and thread placement, not delivery.
    • With it, effective_affinity_list is 0 for 34 of the 57 AIC2 IRQs, irq 65 and the Wi-Fi MSI (irq 95) among them. Without it, and on 7.3, all 57 are empty.
    • Threaded handlers follow the effective affinity. With this PR, irq/95-mt7932, irq/94 (dockchannel), irq/103, irq/107 (apple-isp), irq/109 (avd) and irq/113 (mt7932-bt) all run on CPU0. Without it, irq/95 ran on CPU5 and the others spread over CPUs 0–5.
    • Interrupts whose parent is not AIC (SPMI, GPIO) are unaffected.
  • GPU completion path, traced during compute.light d1:
    • integration/aurora (A and B identical): irq 65 is a hard IRQ on CPU0, with no irq/65 thread. asahi's event work item then runs on a CPU0 kworker, the drm_sched run_job and free_job work on other CPUs' kworkers, and the client is woken on a non-zero CPU. This PR does not move any of it.
    • aurora-silicon 7.3: the hard IRQ is also on CPU0, but the handler is the irq/65-482600000.mailbox-recv thread (SCHED_FIFO 50, seen on CPU5 in this capture). The G17 event work then runs on a CPU5 kworker, and drm_sched on CPU1. That thread is the one the description's numbers come from.

2. Matched combined load: an NVMe direct write/read loop plus a Wi-Fi download loop, with GPU rows run under it.

with this PR without
no load: compute.light d1 / d2, render.light d2 (µs) 317.1 / 165.9 / 66.1 318.1 / 166.3 / 66.3
under load: compute.light d1 / d2, render.light d2 (µs) 280.6 / 139.0 / 70.1 275.6 / 139.5 / 68.2
NVMe direct write, median (mean) MB/s 1000 (1135) 1100 (1219)
NVMe direct read, median (mean) MB/s 2750 (2862) 2700 (2792)
Wi-Fi download MB/s (2 samples, internet-bound) 7.6 6.7
CPU0 utilisation in 100 ms samples under load (n=143): mean / p95 / max 33 / 56 / 78% 31 / 60 / 70%
CPU0 samples at or above 90% 0 0
irq/95-mt7932 run delay (schedstat) 2.65 ms over 23,692 runs, 0.11 µs/run, on CPU0 0.40 ms over 19,580 runs, 0.02 µs/run, on CPU5

The other irq threads did not run in the window.

Reading the table:

@maralcbr maralcbr left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving at 1a10581.

Thanks for the thread identities and the matched runs. They answer both questions. On integration/aurora the GPU mailbox is a hard IRQ, so GPU completion doesn't move. The change reports effective affinity correctly (34 of 57 AIC2 IRQs) and co-locates the existing threaded handlers with their hard IRQ on CPU 0. Under combined load, CPU 0 peaked at 78%, with no samples at or above 90%, and the irq/95 run-delay increase (0.02 → 0.11 µs per run) is negligible. The description now scopes the GPU latency gains to the aurora-silicon tree with the threaded mailbox, which matches the evidence.

One note, not blocking: NVMe direct writes came out about 9% lower with the change (median 1000 vs 1100 MB/s). With one boot per side that can't be called noise, and it can't be pinned on this PR either. If you get the chance, three alternating A/B boots on just the write leg would settle it.

@maralcbr
maralcbr merged commit b496091 into integration/aurora Oct 26, 2026
14 checks passed
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.

3 participants