Modem: rflm_qlnk assertion on ~half of boots, and SSR recovery then wedges the AP #16
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The single biggest source of instability. The modem asserts in its RF Link Manager on roughly every other boot, and the remoteproc recovery that follows takes the application processor down with it.
Signature
Every dead boot ends the same way, at ~27 s:
and then, a few seconds to ~20 s later, the AP dies. Two captured examples of what comes immediately before death:
The failure mode from outside is a wedge, not a panic: the USB controller keeps the gadget enumerated in hardware, but nothing in software responds — no ping, no ACM, no console output. Writes to the ACM endpoint return
EAGAINbecause the device side never drains it.Rate
From the persistent
/root/kmsg.log(thegts6l-kmsgcapservice), across 37 boots:rflm_qlnk_ls_retry_cnt— 51%.slpi/modem/cdsp/adsp), WiFi listing 16 networks, and audio playing.RFLM/qlnkis the RF Link Manager talking to the RF front-end over QLink;ls_retry_cnt < 2is a link-status retry exhaustion. It fires before anything in userspace touches the modem.Two separable bugs
recovering modem, and the RCU stall shows a CPU taking 0 ticks in a grace period, i.e. wedged with no timer progress. Prime suspect is the sysmon/SSCTL notification path plus glink teardown blocking with interrupts off or holding a lock — sysmon blocks ~5 s per notification against an unresponsive peer, and there are four remoteprocs to notify.Fixing (2) makes the device usable even while (1) remains.
Correcting an earlier conclusion
An earlier "definitive single-variable test" recorded the audio PD binding (
qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd") as the cause of this assertion. That was wrong. It compared one boot per arm against an event that fires ~51% of the time — a single sample of a coin flip on each side. Verified since:qcom,protection-domainin the DTS, working tree clean against HEAD).modem=running rflm=0 afe_err=0, audio played audibly, modem healthy.So the PD binding is neither implicated nor exonerated. Any future comparison here needs many boots per arm, never one.
Next steps
disabledto/sys/kernel/debug/remoteproc/remoteprocN/recoverybefore the assertion window. If the system survives with a dead modem, the recovery path is confirmed as the killer. (gts6l-norecover.serviceinstalled on the rootfs to do this early.)qcom_sysmon,qcom_glink_*,rproc_crash_handler_work— to find what blocks.Notes for whoever picks this up
ramoopsdoes not survive a reset on this device (DRAM decays;uncorrectable error in header×10 every boot). The log channel that works is/root/kmsg.logon the SD rootfs.Uncompressing Kernel Image to 80008000, FDT relocated to0xbcbe4000(~700 MB clear of the kernel),Starting kernel ....Recovery-path hypothesis: evidence against it
Ran the experiment. Disabling SSR recovery did not prevent the wedge.
Cycle 2 confirms the knob was genuinely
disabledat t=26 s, one second before the assertion window, and the device died anyway. Withrproc->recovery_disabledset,rproc_crash_handler_work()skipsrproc_trigger_recovery()entirely — so if the wedge still happens, the sysmon/glink teardown path is not what kills the AP.Caveat, stated precisely: I could not retrieve
/root/ssr-experiment.logor the kmsg tail afterwards to confirm the assertion actually fired on that boot — the device wedged before I could read it, and stayed wedged.rflm=0at t=26 s is consistent with the assertion landing at ~27 s (just after the probe) but does not prove it did. So this is strong evidence against hypothesis (2), not a clean disproof. Re-confirm by reading the persistent log from a boot that is known to have asserted.Cycle 1 is consistent with the established pattern: no assertion, stable for 517 s.
Wedge is a hang, not a panic
Worth recording: in the wedged state the device still answers ICMP but sshd is dead, and the USB device number does not change — i.e. it never reboots.
panic=10 sysctl.kernel.panic_on_rcu_stall=1therefore does not rescue it, because nothing panics. The RCU stall is reported and the machine simply stops making progress. This also explains why several "it auto-recovered" observations were really the device having been power-cycled.Practical consequence: the auto-reboot safety net does not exist for this failure mode, so unattended soak testing stalls on the first wedge and needs a human.
Tooling installed on the rootfs
/usr/local/bin/gts6l-norecover— polls for the modem rproc, writesdisabledto its debugfsrecovery, appends to/root/ssr-experiment.log./etc/systemd/system/gts6l-modem.service.d/norecover.conf—ExecStartPre=hook. This is the mechanism that works.Three earlier attempts failed and are recorded so they are not retried:
WantedBy=sysinit.target—systemctl enabledid not stick (preset: disabled), unit never ran.ConditionPathExists=/sys/kernel/debug/remoteproc— condition failed; the modem rproc registers at ~t=17 s, well after sysinit.SUBSYSTEM=="remoteproc", ATTR{name}=="modem"— never fired.Hooking
ExecStartPreonto the already-enabledgts6l-modem.serviceavoids the enable and ordering races entirely.Where that leaves the diagnosis
Both halves of the original split are now in question. The assertion correlates strongly with death (19/37 boots assert; asserting boots die, non-asserting boots run for minutes), but the mechanism is not the recovery path. Next candidates: the crash-notification path that still runs with recovery disabled (
rproc_crash_handler_work→rproc_report_crashand its blocking notifier chain), or something the modem does to shared state/interconnect at assertion time that the AP cannot survive regardless of what remoteproc does next.It is a start-time race, and the NV/rmtfs lead is dead
Two solid results.
1. rmtfs is not involved
Ran
rmtfs -P -r -vwith logging, then started the modem. The verbose log recorded zero requests — the modem never asked rmtfs for anything, before or during RF init. So the EFS/NV path (and thefsgwrite-protected-LUN shadow patch) is not where the RF failure comes from. That hypothesis is closed.2. The assertion tracks when the modem is started
Started late, the modem comes up healthy and stays healthy. With it running from a late start, all three subsystems work at once:
That is the first time modem, WiFi and audio have been up together on this device.
Uncomfortable interaction with the fts fix
The touchscreen fix (
241a0784e5eb) took boot from 722 s to 25.6 s. That is a big win on its own, but it means the modem now always starts at ~18 s — i.e. always inside the failure window. Boots that used to succeed by accident (because the machine was crawling and the modem started at 400 s) no longer do. The fts fix did not cause the modem bug, but it does make it hit every boot instead of about half.Workaround attempt: inconclusive
Added
ExecStartPre=/bin/sleep 90as a drop-in ongts6l-modem.serviceand rebooted. The device brought up USB networking but never started sshd (port 22 refused for 200 s), then dropped off entirely — so the test never produced a verdict. Unclear yet whether 90 s is simply too short, or whether blocking aType=oneshotunit thatmulti-user.targetwants for 90 s interferes with the boot. Retry with the delay moved off the critical path (a separate timer unit, or a background( sleep N; echo start > .../state ) &) rather than anExecStartPre.What to look for next
Something that is not ready ~18 s in but is by ~400 s. rmtfs is ruled out. Candidates worth checking against a boot log:
runningsync_state()completion — gcc/gpucc/rpmhpd all reportsync_state() pendingwell past the failure windowtcs_tx_doneWARN note in MAINLINE-NOTES)A bisect of the delay (30 / 45 / 60 / 90 s) would bracket the threshold and point at whichever of these completes there.
Root cause of the wedge found, and the assertion isolated from it
Two separate bugs were tangled together here. One is solved; the other is now bounded and no longer fatal.
The wedge:
qcom_scm_pas_shutdown()never returnsWhen the modem crashes,
rproc_boot_recovery()→rproc_stop()→qcom_pas_stop()callsqcom_scm_pas_shutdown(), an SMC into TrustZone to tear down a wedged modem. That SMC does not return. The CPU is left in EL3, which is why it:0 ticks this GP)idle=948c/1/0x4000000000000000is byte-identical at t=47 s, 120 s and 193 sSending NMI from CPU 4 to CPUs 1:produces no backtrace, ever, while NMIs to CPUs 2 and 4 report normallyNo software state does that. Everything else was downstream: RCU can't complete a grace period, RTNL's holder can never run, and sshd/NetworkManager/cfg80211 pile up in
D. Seven CPUs stay fine, which is why the kernel keeps printing, the panel keeps updating and ICMP keeps working — and why this kept getting misdiagnosed as a hang.Fix: write
disabledto the remoteproc'srecoveryattribute before starting it. Verified 2026-08-24: modem asserts at ~26 s exactly as before, and the system survives — 0 RCU stalls, 0 D-state processes,ip linkreturns instantly, adsp/cdsp/slpi all running. An identical boot was previously unusable.Stock reaches the same end by another route:
restart_level=SYSTEMon all nine subsystems, i.e. Samsung reboots rather than ever recovering in place.Committed:
b0c82aaf1dbe(addsqcom_q6v5_pas.auto_boot=0so userspace can set the knob before start).Why this took so long: two confounders, both now fixed
a3f17b0850f5— missing PRNG.sm8150.dtsidescribes no RNG, so the CRNG seeded from interrupt timing alone andcrng init donelanded ~133 s in.getrandom()blocks until then; udevd blew its 90 s timeout and was SIGKILLed and restarted up to 7 times, and nothing went ready behind it.dev-mmcblk0p2.deviceranged from 9 s to 32 minutes between identical boots. Modem start time tracked boot speed, so the assertion looked random when it was tracking a missing DT node. Every single-boot comparison made before this — the audio PD binding,cpuidle.off, the 90 s delay — was sampling that noise.241a0784e5eb— fts driver.regulator_get()/enable()/put()on every power call, releasing rails with a non-zero enable count and callingregulator_disable()on handles that never enabled anything. Every I2C transfer to the touch IC returned-110, GPI DMA piled upCH STOPtimeouts, and boot crawled. 13 kernel warnings → 1; I2C timeouts, GPI DMA errors and SMMU faults all → 0; boot 722 s → 25.6 s.The assertion itself: still unexplained, but heavily constrained
The modem asserts
rflm_qlnk_ls_retry_cnt < 2about 9 s after coming up, when started at ~16 s. It does not assert when started after ~90 s, and stock never asserts at all — despite starting it at 6.8 s, earlier than our failing case. So "early" is not the discriminator.Eliminated, each with a clean single-variable test on fast deterministic boots:
modprobe.blacklist=ath10k_snoc, still assertedrmtfs -vlogged zero requestscoredumpis alreadydisabledcpuidle.off=1confirmed active, still stalledThe AP is idle for those 9 s (log is silent between 19 s and the assertion), so the modem is failing on hardware state it finds, not on anything we do concurrently.
Also found while diffing rails (
9d3b38d1c50c)pm8150_l17— touch AVDD, capped at 3008 mV here vs 3300 mV downstream. The FTS controller was under-volted by ~444 mV and could never reach its specified voltage.pm8150_l18— missing entirely; downstream enables it at 912 mV for the SS PHY and DisplayPort. No consumer here yet (USB is high-speed-only for bring-up), so this changes nothing today.Suggested next steps
recovery=disabledthe shipped default and package the bring-up unit.qcom_scm_pas_shutdown()hanging the calling CPU forever is arguably a mainline bug worth reporting upstream — at minimum it should be survivable.subsys-pil-tzload paths is the obvious next angle.2026-08-24/25: the assertion is start-time dependent; SSR diagnosis corrected
The wedge (part 2 of this issue) — corrected diagnosis
recovery=disabledwritten before starting the modem makes the crash survivable: modem still asserts, 0 RCU stalls, 0 D-state,ip linkreturns instantly, all other subsystems stay up. Needsqcom_q6v5_pas.auto_boot=0(commitb0c82aaf1dbe) so nothing starts before the knob is set. Stock reaches the same end by another route —restart_level=SYSTEMon all nine subsystems, i.e. it reboots rather than ever recovering in place.Correction to the earlier claim that
qcom_scm_pas_shutdown()hangs. It does not, unconditionally. Stopping a healthy subsystem works fine —echo stop/echo starton slpi goes offline then running again. The 21 s that write takes isglink_ssrtiming out on the dead modem edge, not TrustZone. Only stopping an already-asserted modem hangs, and the RCU stall window opens the instantrecovering modemis printed (CPU 4 silent,rcu_preemptstarved on CPU 1).Operationally:
start/stopare no-ops on a crashed rproc (stop→-EINVALsince state != RUNNING,start→ 0 withrproc->powerstill held). The only restart knob isecho recover > recovery, which is the hanging path. So one modem start per boot, and never writerecover.The assertion is deterministic in start time
Unattended sweep, one trial per boot, ~20 trials. Full data in
baselines/modem-start-time-sweep.md.Hard boundary between 60 s and 75 s. The earlier "~51% of boots" figure was start-time variance, not a coin flip — the two confounders behind it are fixed (missing PRNG in DT
a3f17b0850f5, crng init 133 s → 5.3 s; and the fts regulator/IRQ misuse241a0784e5eb, boot 722 s → 25.6 s).What QLINK actually is
From strings in the modem firmware itself (
modem.b18): QLINK is the high-speed SerDes between the modem and the WTR/SDR RF transceiver —rflm_qlnk_wtr_serdes_fix_8KV1_ag.c,RFLM_QLNK_GEAR_SEL_8p5Gbps/3Gbps/1p5Gbps,QLNK fails to instantiate SDR object,rflm_qlnk_start_link_lsvs..._hs,QLNK is up running in LS mode.LS = Low Speed, not "link setup" — bring-up runs the link at low speed first, then trains to HS. So
rflm_qlnk_ls_retry_cnt < 2means the modem could not establish the low-speed serial link to the transceiver, twice.Eliminated, each on evidence
nodsparm (modem at 20 s, adsp/cdsp/slpi never started) still asserts, twice.rmtfs -vlogs nothing at all, including on boots where the modem survives. It is never asked.mmc0irq drops 295/s → 3.1/s exactly at the boundary, which looked decisive. Tested properly: heavy SD I/O neither breaks a late modem (2/2 survive) nor rescues an early one (2/2 assert). Coincidence. This also exposed that the earlier "load doesn't matter" test used CPU spinners and dd to /dev/null and tmpfs — no storage I/O at all.apps_rscirq 80.6/s vs 81.2/s across the boundary) and display traffic (43.0 vs 44.5/s) — flat.mpss_resource_initalready votes both atINT_MAX, released on handover. Downstream votes corner 385 and unvotes at 0.56 s.samsung-src/kernelagainstLA.UM.8.1.r1-16600-sm8150.0. Samsung's entire delta insubsys-pil-tz.c/peripheral-loader.c/subsystem_restart.cis boot markers,panic("Modem booting fail !"), silent-SSR and sec_debug plumbing. Nothing touching clocks, regulators, votes or RF. Stock's modem bring-up is stock Qualcomm PIL.Nothing happens at the boundary
State snapshots at 20 / 62 / 78 s (interconnect votes, genpd states, enabled clocks, regulators, interrupt counts, power supplies) show no structural difference across 62→78 — only counters advancing and momentary CPU idle states. And the full kernel + journal log for 30–119 s contains exactly one line:
regulator: Not disabling unused regulatorsat 30.7 s. There is no event to find.Fixed along the way: mcfg was never served
Separate real bug. The modem asks for its carrier config over tqftpserv and was refused all four files, because the stock
modemvfat partition was never mounted. tqftpserv'stranslate_readonly()walks/sys/class/remoteproc/*/firmwareand takes each dirname, somodem_prhas to sit beside the modem firmware, not at the top of/lib/firmware. Fixed in gts6l-alarm (firmware-modem.mount+ link); rejects per boot 6 → 2, and the remaining two are theota_firewall/rulesetpair that stock also refuses.Does not affect the assertion — the modem requests mcfg at t+11.9 s, three seconds after it dies in the failing arm. Verified: early start with mcfg served still asserts, 2/2.
A surviving modem brings up WiFi
With the modem running,
ath10k_snocgets WLFW from it, loads firmware and createswlan0, with all four remoteprocs up. Not functional yet —board_id 0xff, random MAC,chan info: invalid frequency 0, 0 BSS on scan. Separate issue.Caveat on all of the above
Every one of these trials ran on a platform that hung on ~50% of boots (#17, only diagnosed afterwards). The 13-vs-7 split is far too clean to be an artifact, but the sweep is worth re-running now that the device boots reliably.
Next
DIAG,DIAG_CTRL,DIAG_DATAorDIAG_CMD(the names downstream'sdiagfwd_rpmsg.cuses for edge "mpss") — all time out inqcom_glink_create_local(). Its advertised set is only DATA1-11, DS, IPCRTR, LOOPBACK_CTL_MPSS, SSM_RTR_MODEM_APPS, apr_apps2, apr_voice_svc, glink_ssr.rproc_crash_handler_workto take the minidump when recovery is disabled (mpsshasminidump_id = 3). Carries XPU-fault risk on the MSA-protected carveout.pas_shutdownhang upstream.