PAF becomes saf/device (history kept), STATE.md dissolves into saf/state.md with the dated era archived, the substrate SAF moves up from souveraine, and every agreement points at saf/INDEX.md and nowhere else. one map, nothing to remember
837 lines
64 KiB
Markdown
837 lines
64 KiB
Markdown
# PAF · Modem bring-up
|
||
|
||
## ARCH STATUS (2026-07-10): WORKING — verified live on the Arch install.
|
||
|
||
`mmcli`: state connected, LTE, operator Fido, packet service attached,
|
||
signal 73%. The whole solved stack made the jump to Arch: `modemsmem`
|
||
is in our kernel tree (0c2eb6bf3 "soc: qcom: add modemsmem, wire up on
|
||
blueline"), rmtfs/tqftpserv/pd-mapper/ModemManager run as services, and
|
||
`blueline-clat.service` handles 464XLAT. Everything below is the research
|
||
record of HOW the 52 wall fell (pmOS era, 2026-06/07) — the mechanism is
|
||
identical on Arch; read it before touching anything modem-adjacent.
|
||
Deep evidence docs referenced below live in `evidence/`.
|
||
|
||
## RESOLVED 2026-07-03 — modem ONLINE, registered, passing LTE traffic. Root cause of the 52 wall: missing modemsmem driver (SMEM item 134).
|
||
|
||
Google Pixel modem firmware reads SoC info from SMEM_ID_VENDOR0 (item 134) during boot;
|
||
downstream writes it via `drivers/soc/qcom/modemsmem/`. Mainline never had the driver, so
|
||
the MPSS RF task found nothing there and parked op-mode OFFLINE → every RF transition
|
||
illegal → QMI 52. Fix: Richard Acayan's sdm670 mainline port of the driver (commit
|
||
d9afe44b) + `google,modemsmem`/`qcom,smem = <134>` DT node — canonical tree `4ef9b6943`,
|
||
pmaports `9d52b47813` (CONFIG_QCOM_MODEMSMEM=y). Verified live: op-mode online, Fido LTE
|
||
registration home, IPv6 bearer passing packets. Full details in HANDOFF.md (2026-07-03).
|
||
Everything below this line is the (closed) investigation record; the leads/ledger remain
|
||
correct as history. Remaining open threads are identity (SFS/test-IMEI) and polish
|
||
(IPv4 bearer, calls/SMS), not RF.
|
||
|
||
## TOP LEAD 2026-07-02 #15 — DIAG_DATA glink channel: AP CAN request it, modem acks but never completes its own open. Real firmware-behavior finding, not a kernel gap.
|
||
|
||
**Correction to this doc's own earlier framing tonight**: an initial pass concluded mainline's glink
|
||
core lacked any AP-initiated ("locally initiated") channel-open primitive at all, and that reaching
|
||
DIAG_DATA would need core `qcom_glink` infrastructure work. **That was wrong** — re-read
|
||
`drivers/rpmsg/qcom_glink_native.c` properly: `qcom_glink_create_local()` (a complete, working
|
||
implementation of exactly this, sends `GLINK_CMD_OPEN`, waits for both acks) already exists and is
|
||
already wired into the standard `.create_ept` op every transport uses. The real, and much smaller,
|
||
entry-point gap was just: no *driver* was calling `rpmsg_create_ept()` against a fresh channel name
|
||
from an already-bound `rpdev`. Fixed with **zero new kernel code** — userspace's existing
|
||
`RPMSG_CREATE_EPT_IOCTL` on `/dev/rpmsg_ctrl2` (the modem-edge control device; `rpmsg_ctrl0`/`1` are
|
||
CDSP/ADSP respectively, confirmed via `/sys/devices/.../4080000.remoteproc/.../rpmsg_ctrl2`) reaches
|
||
this exact path already. Built a 60-line test binary (`diag_open_test.c`, cross-compiled via
|
||
pmbootstrap chroot) to drive it.
|
||
|
||
**Live result, confirmed clean and repeatable across multiple fresh single-attempt modem boots**:
|
||
- `GLINK_CMD_OPEN` sent for `DIAG_DATA` → modem.
|
||
- Modem sends `GLINK_CMD_OPEN_ACK` back, consistently in <10ms when it responds at all.
|
||
- **The modem never sends its own reciprocal `GLINK_CMD_OPEN` back** — the other half of glink's
|
||
bidirectional handshake `qcom_glink_create_local()` requires (`wait_for_completion_timeout(&channel
|
||
->open_req, ...)`) before a channel counts as usable.
|
||
- Tested whether this was just slow: bumped the wait from 5s→60s (kernel commit `7441ca3dc`), rebuilt,
|
||
reflashed, ran ONE clean attempt on a fresh modem boot, waited the full 63.84s. **Still nothing.**
|
||
Falsified the "just needs more time" theory outright. Reverted the bump (`b4185e71b`) — no reason
|
||
to ship a 60s stall for a case that structurally doesn't complete.
|
||
- Cross-checked against downstream (`references/los-kernel-blueline-4.9/drivers/soc/qcom/glink.c`):
|
||
its `GLINK_CONNECTED` notification requires the exact same bidirectional
|
||
`ch_is_fully_opened(ctx)` condition (checked from both the incoming-open and the open-ack RX
|
||
handlers) — downstream isn't looser about what counts as "open," it's just event-driven with no
|
||
hard timeout instead of blocking-with-timeout. So this isn't mainline enforcing an extra
|
||
requirement Android doesn't have; it's the same requirement, and the modem doesn't satisfy it
|
||
either way under mainline's bring-up.
|
||
|
||
**What this means**: the modem's DIAG service is reachable and responsive at the glink-negotiation
|
||
level (it correctly acks a request for a channel it recognizes by name) but will not commit to
|
||
opening it — a "deliberate partial refusal" shape that rhymes with the *entire* rest of this frontier
|
||
(SIM/QMI all healthy, DMS answers reads, refuses RF-arming writes; modem parks `offline` not `LPM`).
|
||
Whatever state gate blocks RF-arm plausibly also gates DIAG. **F3 access via this channel is not
|
||
reachable by any change on the AP side alone** — this is now a real, evidenced, narrow finding, not
|
||
an assumption. Retest if/when the LPM-vs-offline or any other frontier item moves; a modem that
|
||
reaches a healthier init state might complete this handshake as a side effect.
|
||
|
||
Test binary + method preserved: `diag_open_test.c` (cross-built via `pmbootstrap chroot -b aarch64`),
|
||
`RPMSG_CREATE_EPT_IOCTL` against `/dev/rpmsg_ctrl2`, then `open()` the resulting `/dev/rpmsgN` — same
|
||
approach works for probing ANY named glink channel on ANY edge (swap `/dev/rpmsg_ctrl0/1/2` for
|
||
cdsp/adsp/modem) if a similar question comes up for a different service.
|
||
|
||
---
|
||
|
||
## TOP LEAD 2026-07-02 #14 — frontier #8's 3-precondition test finally run: provisioning-churn fixed & shipped, LPM-vs-offline confirmed unreachable from AP side
|
||
|
||
**Fixed and shipped precondition (b) from frontier #8 below**: `blueline-uim-select.sh` was
|
||
unconditionally deactivating+reactivating the primary-gw provisioning session even when it already
|
||
matched the slot/AID it was about to select — churn on an already-correct session, and exactly the
|
||
class of write the raw-QMI RESULTS.md proved times out during the modem's not-ready window. Patched
|
||
to skip the deactivate/reactivate when the existing binding already matches
|
||
(`device-google-blueline-modem-tools` 7-r18→7-r21, committed `1ed2df1788`). **Verified live**: the
|
||
log now reads "primary-gw session already bound to slot 1 app 1 ... skipping stock
|
||
deactivate/reactivate" — the session is genuinely left alone across a modem restart for the first
|
||
time this whole investigation.
|
||
|
||
**Result: does NOT flip DMS online.** Immediately after the clean-session restart,
|
||
`--dms-set-operating-mode=online` still returns `DeviceNotReady (52)`. Polled operating-mode every
|
||
3s for 18s post-restart: **steady `offline` the entire window, never once observed `LPM`.** So
|
||
precondition (c) — "modem in LPM (not offline) for the online flip" — is now confirmed, not just
|
||
suspected, to never occur spontaneously on pmOS: the firmware decides `offline` vs `LPM` before any
|
||
AP-side QMI write is even possible, so no host script/wrapper/choreography (this fix included) can
|
||
create the window frontier #8 needed.
|
||
|
||
**Where this leaves it:** frontier #8's 3-precondition experiment (configs active + clean
|
||
provisioning + LPM-not-offline) is no longer "untested" — it's tested, with (a) and (b) now cheaply
|
||
satisfiable and (b) fixed for real, and (c) confirmed firmware-internal and unreachable from any
|
||
AP-side lever. This converges with TOP LEAD #13's conclusion (SLPI/ADSP/fastrpc/choreography all
|
||
closed, F3 narration is the remaining instrument) via a different path — both land on "the
|
||
offline-vs-LPM decision happens inside the firmware before Linux gets a vote." **Next: same F3
|
||
instrument #13 named, now aimed at a sharper question** — not generic RF-init narration, but
|
||
specifically why the firmware selects `offline` over `LPM` at its own boot, since that's now the
|
||
single remaining precondition standing between here and an online modem.
|
||
|
||
Also confirmed same session: mainline blueline has **no DIAG transport at all** (`/dev/diag` absent,
|
||
no `diagchar`-equivalent config, no `DIAG` glink channel among the live rpmsg devices) — so
|
||
`diag_capture.md`'s Side B is a real, confirmed dead end on the AP side as of kernel
|
||
`7.1.1_p20260702080259-r2`; F3 access (if pursued) needs either a from-scratch DIAG-over-glink
|
||
kernel path or stays Android-side-only (Side A) for comparison purposes.
|
||
|
||
---
|
||
|
||
## TOP LEAD 2026-07-01 #13 — fastrpc `pageslen` kernel bug FIXED & shipped; 52 wall now proven independent of adsprpcd/ADSP health too
|
||
|
||
**Real, named, diff-attached kernel defect — the first of the whole investigation — found, fixed, shipped, verified.** `fastrpc_init_create_static_process()` in `drivers/misc/fastrpc.c` advertised `inbuf.pageslen = 0` while actually passing one remote_heap page in `args[2]`; the sibling dynamic `fastrpc_init_create_process()` correctly sets `pageslen = 1` for the identical one-page layout. The DSP trusts the metadata field, believes zero pages were passed, and aborts `INIT_CREATE_STATIC` — surfacing in userspace as `Broken pipe` and the adsprpcd coredump cascade (`dsp information is incorrect err: -1` for ADSP+CDSP). One-line fix (`0`→`1`); matches `FisiFla/nabu-cachyos` `0005-fastrpc-fix-init-create-static-pageslen.patch` (SM8250, independently shipped for the identical signature, commit claims it also killed an SLPI crash loop there). Committed `e3c47d44e` in `references/linux-7.1.1-sdm845-CANONICAL`. **Also committed the previously-floating-uncommitted RTC read-only fix** (`68ffb014b` — the load-bearing half of the 0-SPMI-writes result; it had never been committed, only sitting in the worktree). Both shipped in kernel `7.1.1_p20260701093924-r1`, flashed to `boot_a`.
|
||
|
||
**Process correction (saved to memory `pmos-src-skips-apkbuild-patches`):** `pmbootstrap --src` builds the **working tree as-is**, not committed-only. A first build silently included the two then-uncommitted RTC/DTS files; caught by inspecting `chroot_native/mnt/pmbootstrap/source-override/`. "Bake as commits" is necessary but not sufficient — the worktree itself must be in the intended state at build time.
|
||
|
||
**Verified live post-flash:**
|
||
- **adsprpcd: no longer a fatal crash-loop.** Previously coredumped every boot with `dsp information is incorrect` / `Broken pipe`. Now: coredumps ONCE on first probe, systemd restarts it (NRestarts=1), then runs stably — **successfully opens `adsp_default_listener` handles on ADSP (domain 0)**. Old fatal signatures absent from the journal. Residual non-fatal noise remains: `remote_handle64_invoke ... method 2 ... Operation not permitted` + `open_mod_table_handle_invoke ... Error 0xe` on domain 0 — a *separate* ADSP-invoke-permissions issue, not the pageslen bug; next fastrpc thread if pursued.
|
||
- **SPMI write flood: still 0** — RTC read-only fix preserved across the rebuild.
|
||
- **`/dev/fastrpc-sdsp` still ABSENT** → `hexagonrpcd-sdsp` still "Could not attach to FastRPC node: Operation canceled". The pageslen fix targets ADSP/CDSP static-process creation; the SDSP node is a different path (depends on SLPI remoteproc fastrpc edges), so the SLPI/sensor-island story is **not** changed by this fix.
|
||
- **dms-ui-ready (r17 C binary): ran clean**, same `DMS 0x0064 RESULT: FAILURE (result=1 error=58)` as before (unchanged, expected — orthogonal to fastrpc).
|
||
|
||
**Modem 52 wall: STILL THERE — now proven independent of adsprpcd/ADSP health too.** First `mmcli --enable` of the entire session with a non-crashing adsprpcd (all chain units active: modem-qrtr-ready, qcril-autoselect, qcril-prov, dms-ui-ready, ModemManager): identical `QMI protocol error (52): 'DeviceNotReady'` on `Set Operating Mode=online`, op-mode stays `offline`, state `disabled`, lock `sim-pin2`, SIM on slot 2 (correct). Combined with TOP LEAD #12's SLPI proof, **the modem's RF-ready gate is now robust to the entire host-side DSP coordination layer** (SLPI state × 3 boots, adsprpcd/ADSP health × 1 boot). The ADSP-PD/servreg candidate is substantially weakened. The wall is the modem firmware's own internal decision; nothing host-side we can move has touched it.
|
||
|
||
**Where that leaves the candidate space:** of `los-mss-translated.c`'s four deltas — (1) EFS NV item, (2) bootloader/ABL verified-boot state, (3) subsystem coordination [SLPI/PD], (4) host-QMI-replay timing — #3 is now closed and #4 is substantially exhausted (DMS 0x0064 sends+responds but error 58; NAS mode-pref fails DeviceUnsupported pre-RF). #1/#2 were researched to ground with no static delta. The one instrument that could show the modem's *own* RF-init reasoning — F3 narration — remains uncaptured (QCSuper's blanket arm skips the NAS/RRC SSID ranges; per-range SET_RT_MASK arms cleanly but yields no traffic, and we lack a Qualcomm SSID name table to confirm those ranges *are* NAS/RRC). That F3 capture + SSID identification is the most likely remaining source of new signal.
|
||
|
||
---
|
||
|
||
## TOP LEAD 2026-07-01 #12 — SLPI independence now PROVEN (not just argued); DMS 0x0064 "UI ready" built, untested
|
||
|
||
**SLPI-state dependency is now definitively closed, with hard repeated evidence** (2026-06-30
|
||
night → 2026-07-01, three separate boots, live hardware). Fixed a real regression along the way:
|
||
`blueline-slpi-ready.sh` disabled SLPI crash-recovery for a "single-shot" start; when the SAR/CHRE
|
||
firmware fault crashed it, the disabled-recovery path left the glink-edge channel permanently torn
|
||
— `intent request timed out` storming every ~10s indefinitely, which took the modem's own QMI/QRTR
|
||
transport down with it (`endpoint hangup`, `Connection reset by peer`). Fix: recovery must stay
|
||
**enabled** (matches Android's `ssr_setup`/`ssr_diag`, which never disables it) so the kernel's own
|
||
crash handler tears down/rebuilds glink cleanly; the script then does ONE clean attempt and parks
|
||
SLPI (`echo stop`) once caught in a healthy `running` window, instead of crash-looping forever.
|
||
Verified over three clean boots: SLPI crashed (0 times / 50 times / 0 times depending on timing),
|
||
**every single time `DeviceNotReady` on RF-enable was byte-for-byte identical** regardless of SLPI's
|
||
state (crashed continuously, running, offline, or cleanly parked). Also wired `modem-qrtr-ready.service`
|
||
`After=`/`Wants=blueline-slpi-ready.service` to match Android's real architecture — `vendor.qcom.devup`
|
||
(what `modem-qrtr-ready` mirrors) is **literally set by** `init.qcom.devstart.sh` right after it kicks
|
||
SLPI (`echo 1 > /sys/kernel/boot_slpi/boot; setprop vendor.qcom.devup 1`), confirmed by reading the
|
||
real Android script off the mounted LOS vendor image. Architecturally correct, safe, zero cost — but
|
||
does not move the 52 wall. **Candidate #4 ("Subsystem coordination — SLPI PD state?") in
|
||
`los-mss-translated.c`'s delta list is now closed.**
|
||
|
||
**Checked and closed a real diagnostic gap**: `qmicli --dms-get-operating-mode`'s output includes an
|
||
optional "Offline reason:" line (libqmi `qmi_message_dms_get_operating_mode_output_get_offline_reason`,
|
||
bitmask of `HOST_IMAGE_MISCONFIGURATION`/`PRI_IMAGE_MISCONFIGURATION`/`PRI_VERSION_INCOMPATIBLE`/
|
||
`DEVICE_MEMORY_FULL`) that no prior capture had actually looked for. Checked the existing captured
|
||
output (`tools/modem-online-provisioner/modem-online-provision-20260622-063154.log`): the field never
|
||
appears — the modem doesn't populate any of the four documented reasons. Dead end, but a clean one.
|
||
|
||
**Built AND tested: `dms-ui-ready.py`/`.service` + a raw-C fallback. Sends clean, modem responds,
|
||
52 unchanged.** `PAF/qcril_online_sequence.md` (prior session, full disassembly of
|
||
`libril-qc-hal-qmi.so`) identified DMS message **0x0064** ("telephony UI ready") as the one
|
||
load-bearing pre-online step QCRIL performs that pmOS had never replayed. The Python/GI
|
||
implementation (`Qmi.Message` + raw TLV writers) **failed at runtime**: this libqmi build does
|
||
not expose a generic raw-message type via GObject-Introspection at all — only per-message typed
|
||
classes exist in the typelib, confirmed by enumerating `dir(Qmi)` live on the phone. Built a
|
||
small C program instead, cross-compiled against the same libqmi (openimsd fork, 1.39.0) via
|
||
`pmbootstrap chroot -b aarch64`, linked directly against the `.so` already on the phone. Ran it
|
||
live: the modem answered 0x0064 with a real, understood protocol response (not "unsupported
|
||
message"), `RESULT: FAILURE (result=1 error=58)`. Error 58's standard libqmi meaning
|
||
(`WMS_ENCODING`, an SMS-service code) can't be its true meaning for an OEM DMS message — almost
|
||
certainly a vendor-private error space reusing that numeric slot. Immediately retried
|
||
`mmcli --enable`: **`DeviceNotReady` (52), byte-identical to every attempt all night.** Full
|
||
detail + the C source path in `qcril_online_sequence.md`. Kept `dms-ui-ready.service` wired in
|
||
the boot chain (best-effort, harmless, now proven to do something real) — the Python version in
|
||
the package needs porting to the same raw-C approach before it'll actually work at boot; that's
|
||
the concrete next step, not another blind guess.
|
||
|
||
---
|
||
|
||
## TOP LEAD 2026-06-26 #11 — THE 52 IS A MODEM XPU (SECURE-MEMORY) CRASH-LOOP
|
||
|
||
> **🔴 SUPERSEDED 2026-06-29.** Captured on the **pre-DELTA-1 r2 LLVM kernel**, where the modem
|
||
> genuinely crash-looped on an XPU violation. **DELTA-1 (`c2923cb49` MPSS assign-ordering) fixed the
|
||
> load** — on the current kernel the modem MSS runs *steady* (MBA boots, MPSS loads, `remoteproc
|
||
> running`, **no XPU crash-loop, zero −22 on `4080000`**; the only crash-lines are the SLPI's
|
||
> `SNS_REG_INIT`). Yet it **still parks OFFLINE / model 0 / 52**. So **52 is NOT an XPU crash-loop**
|
||
> — it's a firmware-internal RF-init decision, kernel-independent (6.16.7 and 7.1-rc1 both give 52,
|
||
> see #10). The −22 referenced below is the SLPI's fastrpc heap. Kept as the XPU/load investigation
|
||
> record.
|
||
|
||
**Captured live on the rebuilt r2 LLVM kernel (slot A, full system, ssh).** The
|
||
`DeviceNotReady (52)` wall is now explained at the mechanism level: the modem
|
||
**boots then crash-loops on a hardware secure-memory protection violation**, so it
|
||
can never complete RF-init and parks `offline`. dmesg (`qcom-q6v5-mss
|
||
4080000.remoteproc`, remoteproc3):
|
||
|
||
```
|
||
Booting fw image qcom/sdm845/Google/blueline/mba.mbn ... MBA booted ... loading mpss
|
||
remote processor 4080000.remoteproc is now up
|
||
crash #1: fatal error received: SFR Init: wdog or kernel error suspected.
|
||
crash #2: fatal error received: modem_xpu_int.c:456:[modem_sec_xpu_I]XPU violation
|
||
... port failed halt ... modem offline ... starting ... up ... crash ... (loop)
|
||
```
|
||
|
||
**XPU = Qualcomm eXtreme Protection Unit** — hardware memory guard programmed by
|
||
TrustZone. `modem_sec_xpu XPU violation` = the modem firmware accessed a memory
|
||
region the XPU does not permit it → the modem's **secure memory regions are not
|
||
assigned/programmed correctly** for mainline. The modem comes up, touches a
|
||
protected region, XPU faults it, q6v5 recovers it, repeat. The "running" state in
|
||
a one-shot `remoteproc/state` read is just a momentary up-window between crashes —
|
||
do not trust a single-sample `running`; watch `journalctl -b -p err` over ~30s.
|
||
|
||
**This is the same TZ layer as the SLPI/fastrpc failure.** Every modem AND slpi
|
||
restart also logs `qcom_scm firmware:scm: Assign memory protection call failed -22`
|
||
(hyp-assign / `qcom_scm_assign_mem` → -EINVAL). The fastrpc patch *tolerates* it;
|
||
the modem cannot — it needs its secure regions actually assigned. **Shared root:
|
||
this blueline's TZ rejects mainline's secure-memory-assign, → modem XPU violation
|
||
→ 52.** See `secure_load_tz_frontier.md`.
|
||
|
||
**Ruled OUT as the cause of 52 (this session, hard evidence):**
|
||
- *Provisioning / MCFG* — software MCFG `Rogers_Canada` (Casey's real carrier) is
|
||
`Active` (PDC `--pdc-list-configs=software`). Selecting the carrier config — the
|
||
thing qcril/Set-Feature does on Android — is already done, and 52 reproduces
|
||
anyway. Platform configs = 0 (blueline EFS gap) and PDC Set Feature 0x2E times
|
||
out, but neither is the 52: the modem crashes below the QMI layer.
|
||
- *Kernel config regression* — 52 reproduces on the corrected 1135-module r2 LLVM
|
||
kernel with SLPI/SSC in. Not the GCC-stripped-config disaster.
|
||
- *libqmi* — confirmed the openimsd fork is installed (apk desc: "openimsd fork,
|
||
adds PDC Set Feature msg 0x2E"; ships `Qmi-1.0.typelib`). Not the blocker.
|
||
|
||
**[RETIRED 2026-07-01 — see HANDOFF CORRECTIONS]** ~~The one-per-boot online attempt was
|
||
spent this boot ... Modem now poisoned until power-cycle.~~ Online attempts are retry-safe
|
||
within a boot; QMI `Set Operating Mode = RESET (4)` cleanly reinitializes, no reboot needed
|
||
(`tools/modem-online-provisioner/RESULTS.md`). Kept for history: that boot's attempt gave 52,
|
||
mode stayed `offline`, serving-system not-registered/detached, signal InformationUnavailable.
|
||
|
||
**Next frontier:** make TZ accept the modem's secure-memory assignment — i.e. the
|
||
XPU/hyp-assign region setup. Compare LOS pil-tz secure-load (mba region
|
||
`qcom,mba-mem`, mpss region assign, `qcom_scm_assign_mem` VMID lists) vs mainline
|
||
`q6v5_mpss` region handling on this device. The `assign -22` is the thread to pull.
|
||
(qmicli also **segfaults** on `--pdc-list-configs` — separate libqmi/fork bug to log.)
|
||
|
||
## TOP LEAD 2026-06-21 #10 — KERNEL-REGRESSION HYPOTHESIS: DISPROVEN. Kernel layer ruled out airtight.
|
||
|
||
**Result (clean-boot test, 2026-06-21 eve):** built blueline on `sdm845-6.16.7-r0` (last pre-regression
|
||
stable, 2025-09-19), flashed boot_b, booted clean. The modem boots **fully** on 6.16.7 — firmware
|
||
loads (`Booting fw image …/mba.mbn` → `remote processor is now up`), ALL QMI services register
|
||
(qrtr-lookup shows DMS/NAS/UIM/Voice/WDS/PDC…), UIM is healthy (card present, USIM `ready`, Primary-GW
|
||
slot1/app1), `remoteproc2` = `running`. Yet `--dms-set-operating-mode=online` → **DeviceNotReady (QMI
|
||
52)**, mode stuck `offline`, Networks `''`, Max TX/RX 0 — **byte-for-byte identical to 7.1rc1.** A
|
||
second run on a *clean* boot (modem auto-started at boot-time, UIM freshly provisioned) reproduced the
|
||
same 52, removing the manual-start confound. Per this lead's own triage rule (still-52 on the
|
||
pre-regression kernel) = **the kernel is ruled out airtight.** The online wall is NOT a kernel
|
||
regression; it is device-internal (Route B) — the modem's own firmware RF-init never self-completes, so
|
||
it parks `offline` and refuses `online` (Android never has to ask; see frontier #8 REFRAME).
|
||
6.16.7 is now a known-good working kernel for blueline (modem boots clean); either 6.16.7 or 7.1rc1 is
|
||
fine going forward (both give 52). **The live frontier is Route B — see `frontier #8 REFRAME` below.**
|
||
|
||
### Firmware-path gotcha found + fixed (RECORD — bites any upstream-tree blueline DTB)
|
||
The 6.16.7 *upstream* `sdm845-google-blueline.dts` requests firmware at
|
||
`qcom/sdm845/pixel3/{mba,modem,adsp,cdsp,ipa_fws,a630_zap}.mbn`, but pmaports packages blueline
|
||
firmware at `qcom/sdm845/Google/blueline/`. So the upstream-tree DTB silently fails `request_firmware`
|
||
(ENOENT -2) → modem/ADSP/CDSP never boot (`remoteproc: Boot failed: -2`). The 7.1rc1 *pmaports* DTB
|
||
uses `Google/blueline/` (correct) — which is why 7.1rc1 loaded firmware and 6.16.7 did not until fixed.
|
||
**Fix applied on the rootfs (persists across reboots):**
|
||
`ln -snf /lib/firmware/qcom/sdm845/Google/blueline /lib/firmware/qcom/sdm845/pixel3`
|
||
Any future build using the upstream blueline DTB needs this symlink (or a DT patch correcting
|
||
firmware-name paths) or the modem will not load firmware. (Stray: the 6.16.7 DTB also references
|
||
`qcom/sdm845/oneplus6/venus.mbn` for venus — harmless, video-decoder only.)
|
||
|
||
### Kernel-swap procedure (RECORD — the modular-modem-stack gotcha)
|
||
The blueline modem stack is **fully modular** on this config: `qcom_q6v5_mss`, `qrtr`/`qrtr-smd`,
|
||
`qcom_glink_smem`, `qcom_sysmon`, `mhi*` all `=m`. So swapping kernels needs the matching modules on the
|
||
rootfs or the modem never loads (a false 52). UFS + USB-gadget-NCM are built-in (`=y`), so a
|
||
module-mismatched boot still reaches rootfs + USB. Working procedure (validated this session):
|
||
build kernel .apk → `tar xzf` it → extract `lib/modules/<kver>/` → scp to phone → `sudo cp -a` into
|
||
`/lib/modules/` + `depmod <kver>` → reboot. Boot.img = `cat vmlinuz <blueline>.dtb` + the standing
|
||
initramfs, `mkbootimg` (header v0, base 0x0, kernel_off 0x8000, ramdisk_off 0x1000000, tags 0x100, the
|
||
real cmdline `quiet splash … pmos_boot_uuid=2CE8-836F pmos_root_uuid=26733d78…`). USB iface
|
||
`enp0s20f0u6` (cdc_ncm) needs manual bring-up each boot: `nmcli dev set … managed no; ip addr add
|
||
172.16.42.2/24 dev …; ip link set … up`.
|
||
|
||
### Original #10 thesis + bisect-window analysis (HISTORICAL — hypothesis disproven above)
|
||
Thesis (Casey): the 7.1rc1 bump (pmaports MR !8446, merged 2026-04-28, "basic smoke testing… Pixel 3")
|
||
never validated blueline's modem; the modem may have regressed there. Corroboration: beryllium wiki
|
||
flags 7.1.0-rc1-sdm845 for modem breakage on the same SoC; Joel Selvaraj had SDM845 modem working on
|
||
mainline back at 5.11, so the capability predates the regression. **Running test:** rebuild blueline
|
||
kernel against `sdm845-6.16.7-r0` (last pre-regression stable, 2025-09-19), flash boot_b, retry
|
||
`--dms-set-operating-mode=online`. Outcomes: online → regression confirmed, bisect the bump; flaky
|
||
like beryllium → kernel layer validated, inherit beryllium recipe; still DeviceNotReady(52) → kernel
|
||
ruled out airtight, it's device-internal firmware/EFS state (Route B).
|
||
|
||
### Kernel-tree pull (2026-06-21) — what the AP-driver diff says about the bisect window
|
||
Pulled `references/sdm845-linux-20260610-ONHOLD-DAVID-TREE` (codeberg `sdm845-next-20260610`, base **7.1.0**) and the
|
||
`sdm845-next-20260306` tarball (base **7.0.0**) and diffed the modem-relevant subsystems:
|
||
- **`drivers/remoteproc/qcom_q6v5_mss.c`: functionally identical** 7.0→7.1 (brace-whitespace only).
|
||
- **`drivers/soc/qcom/pdr_interface.c` + `pdr_internal.h`: rename-only** — `SERVREG_LOCATOR_SERVICE`→
|
||
`QMI_SERVICE_ID_SERVREG_LOC` (both 0x40), `SERVREG_NOTIFIER_SERVICE`→`QMI_SERVICE_ID_SERVREG_NOTIF`
|
||
(both 0x42), `reason[257]`→`reason[SERVREG_PFR_LENGTH+1]`(=257). No behaviour change.
|
||
- **`qcom_pd_mapper.c` present in BOTH trees** → the in-kernel pd-mapper is NOT new to 7.1 (already
|
||
in-kernel by 20260306 / 7.0.0; it landed ~mainline 6.13, so 6.16.7 has it too). The "in-kernel
|
||
pd-mapper is the regression" sub-hypothesis is weak; the **sdm845-mainline rebase** is the live one.
|
||
- `qmi_interface.c`, `qmi_encdec.c`, `rmtfs_mem.c`: identical 7.0→7.1.
|
||
**Implication for the bisect:** in the codeberg 7.0→7.1 window there is NO functional change in
|
||
mss/pdr/qmi/rmtfs — so if the regression is real and in that window, it is NOT in those drivers
|
||
(look at clk/regulator/interconnect/scm/smem/glink/IPA instead). **Caveat:** pmaports tracks
|
||
`gitlab.com/sdm845-mainline/linux`, NOT codeberg `sdm845/linux` (the two repos the Matrix thread
|
||
argues over), and my window (7.0→7.1) does not cover the 6.16.7→7.0 jump. So this scopes, it does
|
||
not pin — Casey's 6.16.7 build is still the right swing.
|
||
|
||
### Upstream blueline DTS confirms our DT is already correct (kills #9 a second way)
|
||
The 20260610 tree ships an **in-tree `sdm845-google-blueline.dts` + `sdm845-google-common.dtsi`**
|
||
(model "Google Pixel 3"). Its modem nodes: `&mss_pil` = `blueline/mba.mbn`+`blueline/modem.mbn`,
|
||
`&ipa` = `blueline/ipa_fws.mbn`, `mpss memory@8e000000` size `0x9800000`, `rmtfs-region@f2700000`
|
||
vmid MSS_MSA. **`dt-work/blueline-pmos.dts` already matches all of these byte-for-byte.** Zero
|
||
WTR/QFE/RFFE/FEM/GRFC regulator nodes in the upstream blueline DTS — same as fajita, same as pmOS.
|
||
So the pmOS modem DT is upstream-aligned, not a fajita guess. RF power is modem-firmware/RFFE driven
|
||
(see `dt-work/rf-rail-diff-FINAL.txt`). **Lead #9 (add 11 pm8998 LDOs) is refuted** by (a) the
|
||
upstream blueline DTS not declaring them either, and (b) all 11 candidate LDOs showing use=0 from the
|
||
AP on live working Android. Do NOT flash `dt-work/blueline-live.dtb` for this reason.
|
||
|
||
### qrild finding folded in — there is no hidden online handshake
|
||
`references/qrild` (abandoned AOSPM RIL): its modem bring-up (`qrild_android_modem.cc` ctor) is
|
||
DMS Set Operating Mode RESET → powerup → NAS register-indications, with `setRadioPower` a no-op stub.
|
||
Same levers ModemManager already pulls — **no secret QMI sequence** that arms RF. This corroborates
|
||
the #8 REFRAME (`qcril_bringup_capture.md`): on Android the modem firmware SELF-onlines at its own
|
||
RF-init; replaying a "QCRIL/RIL online handshake" on pmOS is a dead end because there isn't one.
|
||
|
||
---
|
||
|
||
## (REFUTED 2026-06-21) #9 — pmOS DT under-defines the pm8998 regulator set
|
||
|
||
Refuted by #10 above (upstream blueline DTS does not declare these LDOs either; all 11 are use=0 on
|
||
live Android) and by `dt-work/rf-rail-diff-FINAL.txt` (RF power is firmware/RFFE-driven, not AP-DT).
|
||
Kept for the record; do NOT flash the LDO DTB. Original reasoning below.
|
||
|
||
Direction (Casey + GLM): the fix is in OUR pmOS implementation/DT, make it mimic Android. Concrete,
|
||
evidenced bug found this session:
|
||
|
||
**Our mainline blueline DT instantiates only ~14 of the 24 pm8998 LDOs. Android defines all of them.**
|
||
Missing from `dt-work/blueline-pmos.dts` rpmh-regulators (present in downstream Android DTB):
|
||
`ldo4, ldo6, ldo8, ldo9, ldo10, ldo11, ldo15, ldo16, ldo18, ldo23, ldo27`.
|
||
Voltages (from `dt-work/android-dtb/android-base.dts`, full diff in `dt-work/regulator-diff-android-vs-pmos.txt`):
|
||
ldo6=1.856V ldo8=1.2V ldo9=1.704V ldo10=1.704V ldo11=1.0V ldo15=1.8V ldo16=2.704V ldo18=2.704V ldo23=3.0V.
|
||
|
||
Why this matters even though all 11 are `deviceless`/use=0 in BOTH regulator_summaries: **the modem
|
||
votes its RF-frontend rails (WTR5975/PA/tuners) directly via RPMh, not the AP regulator framework.**
|
||
If the AP DT doesn't define a rail in the rpmh-regulators node, it isn't in the Linux RPMh regulator
|
||
set — so when the modem's RF-init requests it, the vote can't be satisfied/arbitrated. Modem RF-init
|
||
fails → modem parks in `offline` and refuses LPM/online (DeviceNotReady / silent no-op). This fits
|
||
every symptom: modem boots (DSP up) but RF never inits; `offline` won't flip; configs don't help.
|
||
|
||
Supporting evidence this session:
|
||
- Modem FATAL crash in pmOS dmesg: `qcom-q6v5-mss: fatal error received: ...Asserted in
|
||
wlan_vdev.c:_wlan_vdev_create` + `port failed halt` on stop (subsystem not halting cleanly →
|
||
modem can't flush NV → MCFG selection lost across restart → 0 configs every boot).
|
||
- Modem comes up `offline` (not LPM like Android); `set low_power`/`online` return rc=0 but mode
|
||
never changes; PDC autoselect (Set Feature) does NOT persist across modem restart (RIL-layer, not
|
||
firmware NV).
|
||
|
||
### Executable plan (start here next session — do NOT re-derive):
|
||
1. **Diff our blueline DTS rpmh-regulators block vs UPSTREAM linux-next `sdm845-google-blueline.dts`**
|
||
(Heidelberg's). Our pmaports kernel build may predate the full regulator set. If upstream already
|
||
defines all LDOs, bump/patch the kernel DTS; if not, add them.
|
||
2. **Add the 11 missing LDOs** to the `pm8998-rpmh-regulators` node in the blueline DTS at the Android
|
||
voltages above; mark the RF-candidate analog rails `regulator-always-on` so they're up at RF-init.
|
||
3. Build via pmbootstrap (`linux-postmarketos-qcom-sdm845`), flash `boot_b` (see platform.md), boot.
|
||
4. `dmesg | grep -iE 'regulator|vreg|q6v5|fatal'` — confirm no rail/halt errors; then
|
||
`--dms-set-operating-mode=online` → `--dms-get-capabilities` Networks non-empty = RF armed.
|
||
5. **Leverage other devs (Casey): do NOT silo.** Cross-check the SDM845 mainlining wiki, sargo/bonito
|
||
(Google sister devices) DTS, and the `#sdm845:postmarketos.org` channel for how RF rails are
|
||
declared. Heidelberg's blueline series on lore.kernel.org is the authoritative reference.
|
||
|
||
Artifacts: `dt-work/regulator-diff-android-vs-pmos.txt`, `dt-work/android-dtb/android-base.dts`
|
||
(decompiled downstream DTB), `dt-work/blueline-pmos.dts`.
|
||
|
||
---
|
||
|
||
|
||
The modem is a self-contained DSP (MPSS) running Qualcomm firmware. Linux only loads it, powers
|
||
it, and talks QMI to it. RF is the modem's own internal state machine — Linux cannot drive RF
|
||
directly. Read this stack bottom-up; the blocker is at L6.
|
||
|
||
## The bring-up stack
|
||
|
||
| L | Layer | What it is | Status (2026-06-19) |
|
||
|---|---|---|---|
|
||
| L0 | Silicon / RF | SDM845 SoC; **SDR845 + WTR5975** transceivers; pm8005/pm8998 PMICs | fixed HW |
|
||
| L1 | Firmware load | `mba.mbn` (238 KB) → `modem.mbn` (67 MB MPSS), via remoteproc `q6v5-mss` | healthy — "remote processor is now up" ~12.8 s |
|
||
| L2 | Power | rpmhpd domains `cx`/`mx`/`mss`; `mss`→`mss.lvl` ARC→`pm8005_s2_level` | healthy — `q6v5` votes `mss` INT_MAX; verified vs Android |
|
||
| L3 | Transport | QMI over QRTR; `glink-edge` to the modem PID | healthy — all QMI services register |
|
||
| L4 | Host services | `rmtfs` (EFS), `pd-mapper`, `tqftpserv`, `qrtr-ns` | **CRITICAL 06-19**: rmtfs binary was replaced (69KB→141KB) and config changed from `-r -P -s` to `-P -s`, causing EFS corruption + modem crash + system freeze at "[stack] dump". Original binary at `/usr/bin/rmtfs.orig-20260618` must be restored. **CORRECTION (06-19 #2): `-r` = read-only is WRONG for arming the modem — Android serves EFS read-write and the modem writes modemst2 on boot. Use `-P -s` (read-write). The 02:38 corruption was the wrong binary, not the rw flag.** |
|
||
| L5 | SIM / UIM | card detect, app select, primary-GW provisioning | healthy — `usim (2) ready`, slot1/app1 |
|
||
| **L6** | **RF arm** | `DMS Set Operating Mode → online` arms the RF stack | **BLOCKED — DeviceNotReady (QMI 52).** The 06-19 #2 "rmtfs read-only" root-cause is **DISPROVEN (2026-07-02)**: rmtfs runs `-P -s` read-write live (drop-in enforced, all EFS partitions present) and 52 persists. rmtfs ruled out. Real cause is the modem's own boot-time RF-init decision (Route B), not an AP EFS-write path. |
|
||
| L7 | Data / voice | IPA/rmnet, ModemManager, calls/SMS/data | gated behind L6 |
|
||
|
||
**The blocker, precisely:** `DMS Set Operating Mode=online` → **DeviceNotReady (QMI 52)**;
|
||
`DMS Get Capabilities` → zero channel rates / empty networks = the RF stack never initialized
|
||
inside the DSP. Everything upstream (L1–L5) is proven healthy. ModemManager reaches `enabling`,
|
||
hits this, falls back to `disabled`, cycles.
|
||
|
||
## Eliminated leads — DO NOT RE-CHASE
|
||
|
||
Each killed with proof. The "proof" column is why it's dead, not a hypothesis.
|
||
|
||
| Lead | Verdict | Proof |
|
||
|---|---|---|
|
||
| rmtfs NV-files / `msm-cros-efs-loader` (serve EFS from file copies) | DEAD ( UPDATED 06-19 ) | **REAL CAUSE FOUND**: rmtfs binary was replaced (69KB→141KB) on 06-19 02:38 and service config changed from `-r -P -s` to `-P -s`. This broke EFS partition access, causing modem crash → "[stack] dump" → system freeze. Fixed by restoring `/usr/bin/rmtfs.orig-20260618` (69192 bytes) and resetting `/etc/systemd/system/rmtfs.service.d/writable.conf` to `-r -P -s`. The NV-files approach is dead; the original partition-mode rmtfs MUST be used. |
|
||
| `removed-region@88f00000` carveout (was "lead #1") | DEAD | Android iomem: `88f00000-8aafffff : System RAM`. The device whose modem **works** leaves it allocatable. OnePlus-specific quirk. (06-19) |
|
||
| cmd-db maps `mss.lvl` to wrong PMIC (was "lead #3") | DEAD | Android regulator tree: `4080000.qcom,mss → pm8005_s2_level` (correct rail). cmd-db is the same firmware blob on both OSes. pm8005 absent from pmOS `regulator_summary` is **expected** — mainline drives it via rpmhpd/genpd, not the regulator framework. (06-19) |
|
||
| `vdd_mss-supply` / SPMI `pm8005@4` in DT | DEAD | Mainline `q6v5-mss` is power-domains-only for SDM845 (no `devm_regulator_get`). `qcom,pm8005` has **no SPMI driver** in mainline → adding `pmic@4/5` panics the kernel. Only `smps1/2` under the rpmh-regulators-2 block is safe. (06-18/19) |
|
||
| "blueline lacks `soc-qcom-sdm845-modem` dep" | DEAD (stale doc) | Current pmaports pkg is `soc-qcom-modem`; blueline depends on it just like enchilada. Device-pkg deps + firmware manifests are equivalent. (06-19) |
|
||
| fcc-unlock missing | DEAD | `fcc-unlock` exists nowhere in pmaports; no SDM845 device uses one. Modem is not FCC-locked-waiting. (06-19) |
|
||
| Modem DT node differs from working device | DEAD | blueline modem node is byte-identical to fajita (same power-domains/clocks/resets); only firmware path + phandles differ. (06-18) |
|
||
| Storage / EFS calibration is missing | DEAD | rmtfs writable + Android-primed EFS (modem online in Android first) → still DeviceNotReady in pmOS. EFS content is not what's missing. (06-18) |
|
||
|
||
**Net:** every kernel / DT / power / packaging layer is proven equal to blueline-**Android**
|
||
(which runs the modem online, Fido LTE) on the **same silicon**. The blocker is not there.
|
||
|
||
## The frontier (REVISED 2026-06-20 #8 — QCRIL does more at bring-up; mainline stack under-initializes the modem)
|
||
|
||
Casey's standing thesis (correct, and the through-line of this whole effort): **QCRIL powers and
|
||
initializes more of the modem than ModemManager does** — and mainline pmOS, as a minimal port,
|
||
under-powers/under-initializes the board. We are hunting the specific delta. Evidence gathered:
|
||
|
||
1. **QCRIL sends a `'UI ready'` / power-on-optimization handshake to the modem that MM never sends.**
|
||
Android cold-boot capture (`android-live-20260619/deep/radio-boot.txt`): `qcril_qmi_nas_telephony_ready:
|
||
poweron_opt: send 'UI ready' to modem` (qcril_qmi_nas.cpp:17527), plus an active radio-power
|
||
state machine (`qcril_qmi_nas_update_radio_power_request_info` → `BOOTUP_RADIO_POWER_OFF`,
|
||
`qcril_qmi_nas_radio_power_transaction_handler`, state line `telephony LPM | ril NONE | card UP |
|
||
modem ONLINE`). ModemManager has no equivalent of this poweron_opt / UI-ready signalling.
|
||
2. **No DT RF node on either OS** (see retracted #6) — so the delta is QMI-level (modem-side
|
||
init/power), not a Linux regulator we can add. The mainline DT brings up cx/mx/mss + the basic
|
||
stack; it does NOT replicate QCRIL's QMI bring-up choreography.
|
||
3. **Provisioning race (real bug, partially validated).** `msm-modem-uim-selection` fails every boot:
|
||
it fires during the early QRTR window ("node with id 0 not found"), then its primary-GW provisioning
|
||
ACTIVATE times out → service exits FAILURE → the live `primary-gw-provisioning` session loops
|
||
`end-with-failure`/`app-reset`. Run manually AFTER boot it SUCCEEDS (`Successfully changed
|
||
provisioning session`). KEY: with provisioning freshly+cleanly active, `--dms-set-operating-mode=
|
||
online` **no longer returns DeviceNotReady(52)** (returns rc=0) — though the modem still stays
|
||
`offline` because PDC configs were 0 that boot. We have never had configs-active AND
|
||
clean-provisioning AND the QCRIL init handshake all at once.
|
||
|
||
4. **QCRIL online path captured (airplane off→on, `android-capture-20260620/qcril-online-capture.txt`):**
|
||
`qcril_qmi_nas_dms_handle_modem_operating_mode` (qcril_qmi_nas.cpp:18289) → "modem's operating mode
|
||
needs to be changed" → ril SETTING_OP_MODE → **modem LPM → ONLINE** in ~30ms (a plain DMS
|
||
set-operating-mode=online). post-transition: `set_bootup_power_optimization_state=2`, ATEL UI-READY,
|
||
enable networking/sys-info indications. **No hidden RF-power QMI command** — the modem is already
|
||
powered (LPM) and the flip arms RF. **KEY STATE DIFFERENCE:** Android modem starts in **LPM**
|
||
(low_power) and does LPM→online; the pmOS modem sits in **`offline`** (deeper state) and
|
||
offline→online is what fails. So the gate is the combination: (a) MCFG configs loaded, (b)
|
||
primary-GW provisioning active, (c) the modem in LPM (not offline) for the online flip. We have
|
||
NEVER had all three at once on pmOS — that is the decisive untested experiment.
|
||
|
||
**The decisive instrument (next):** a QMI-message-level capture of QCRIL's bring-up on the rooted
|
||
Android (enable QMI verbose radio logging, cold boot or airplane-toggle), then diff the QMI request
|
||
sequence against ModemManager's (we already have MM's via `--debug`). The delta = exactly what to
|
||
replay on pmOS (UI-ready/poweron_opt, any NAS/DMS/RF config QCRIL issues). Then replay on pmOS with
|
||
configs active + provisioning clean. Rooted Android (slot B) is the instrument; keep this doc current
|
||
as the capture lands.
|
||
|
||
---
|
||
|
||
## The frontier (REVISED 2026-06-20 #7 — live RF-init trace: blocker reframed to primary-GW provisioning, NOT RF cal)
|
||
|
||
Ran the decisive pmOS-side RF-init trace (slot B, kernel 7.1.0-rc1, modem over qrtr://0). Two
|
||
big results — one closes a thread, one opens a sharper one.
|
||
|
||
**The modem is not faulting and nothing it requests is missing.** dmesg: clean boot, mba→mpss→
|
||
running→handover, NO crash/coredump/fatal in the RF-arm window; an `online` attempt produces ZERO
|
||
dmesg delta. tqftpserv serves only the readonly MBN tree (read OK) + an empty `mcfg.tmp` scratch
|
||
file the modem RRQ/WRQ-loops on — and `mcfg.tmp` being 0 bytes is NORMAL (tqftpserv is bind-mounted
|
||
to the **persistent** persist partition `/dev/sdf2[/rfs]` — NOT volatile tmpfs as first feared —
|
||
and persist is SHARED with Android, so if the working modem needed content there it would persist;
|
||
it's empty on both). So serving is correct and complete. **The modem boots healthy and simply
|
||
REFUSES `online` at the QMI layer (DeviceNotReady = clean refusal, not a load failure).**
|
||
|
||
**NEW lead — primary-GW SIM provisioning session fails.** ModemManager's log during the refusal:
|
||
`refresh indication received: session type 'primary-gw-provisioning', stage 'end-with-failure',
|
||
mode 'app-reset'` — looping every MM retry (~72s), alongside a NAS system-info indication that
|
||
returns `FAILURE: InformationUnavailable`. Operating mode `offline`, **HW restricted `no`** (not
|
||
FCC/HW-locked), serving system fully detached, radio interface `none`. AND `msm-modem-uim-selection`
|
||
**failed this boot**: "Application was already selected" → `operation failed: Transaction timed out`
|
||
→ service exit FAILURE. Yet the static card read is healthy: Primary GW bound (slot1/app1), USIM
|
||
app `ready`, personalization `ready`, PIN1 `disabled`. So the binding exists but the live
|
||
provisioning SESSION keeps failing + app-resetting. This is distinct from (and more proximate than)
|
||
the RF-cal lead — the modem may refuse `online` because primary-GW subscription provisioning never
|
||
completes, not because RF is uncalibrated. (mBands=[] is non-diagnostic per #6; generic IMEI works
|
||
on Android per Casey — so cal/QCN lead is weak.)
|
||
|
||
**OPEN — causality not yet proven.** Why does the provisioning session end-with-failure while the
|
||
GW binding shows bound+ready? Candidates: (a) `msm-modem-uim-selection` timing out leaves the
|
||
subscription half-selected; (b) the modem triggers an app-reset refresh (post-MCFG) that nothing
|
||
on the AP side completes the way Android's RIL does; (c) downstream symptom of offline state.
|
||
**Decisive next test (fresh boot, one clean shot):** on a fresh slot-B boot, before MM enables,
|
||
(1) confirm whether the primary-gw-provisioning refresh fails on its own; (2) re-run UIM selection
|
||
cleanly (the service timed out) and retry `online`; (3) capture the UIM/provisioning QMI sequence.
|
||
Compare to what Android's RIL does on the same refresh. Known: a remoteproc reset (online is retry-safe, see CORRECTIONS)
|
||
both clear UIM provisioning, so this needs a clean boot.
|
||
|
||
---
|
||
|
||
## The frontier (REVISED 2026-06-20 #5 — MCFG SOLVED; online blocker isolated to device-specific RF bring-up)
|
||
|
||
Live pmOS run this session SOLVED the MCFG provisioning blocker AND, by doing so, proved MCFG was
|
||
never the RF-arm blocker. The online wall (`DeviceNotReady` QMI 52) survives every config/stack/SIM
|
||
fix. Full elimination, all on hardware (slot B, kernel 7.1.0-rc1-sdm845):
|
||
|
||
**SOLVED — persistent MCFG self-provisioning.** `qcril-autoselect.py` (PDC Set Feature 0x2E,
|
||
Selection Mode=3) made the modem self-load 2 platform (SS-LA-SDM845) + 25 software (Rogers_Canada)
|
||
configs from the tqftpserv tree; survives reboot (self-loads at RF-init). Both ACTIVE; software
|
||
version `0x801481A` == Android's exact value. The "0/0 every cold boot" blocker (frontier #3/#4)
|
||
is dead. Tooling: `tools/qcril-autoselect.py` + `tools/build-openimsd-libqmi.sh` (openimsd libqmi
|
||
fork, has Set Feature). Believed a Pixel 3 mainline first.
|
||
|
||
**RULED OUT as the online (RF-arm) blocker — every one tested on hardware:**
|
||
- MCFG/PDC — both configs ACTIVE, matching Android. online still 52.
|
||
- UIM/SIM — card present, USIM app `ready`, Primary GW slot1 app1 provisioned.
|
||
- timing/lock — MM stopped, 10 patient online retries over 30s, all 52.
|
||
- ModemManager — its full 9-step enable (power-state → op-mode indication register → Set Operating
|
||
Mode 0x2E=online) returns the same 52. Not a manual-qmicli artifact.
|
||
- missing stack — pd-mapper, hexagonrpcd, q6voiced, rmtfs (`-P -s` rw), tqftpserv ALL running;
|
||
`soc-qcom-modem` installed; PD JSONs (modemr.jsn/modemuw.jsn) + firmware present; no errors.
|
||
Matches working SDM845 devices (enchilada/fajita) component-for-component.
|
||
- EFS not served — modemst1/2, fsg, fsc all populated (~260K nonzero) + served. (modemcal sdd4 is
|
||
all-zero; persist sdf2 has data.)
|
||
- firmware mismatch — modem sw version `g845-00194-210812-B-7635520` IDENTICAL to Android;
|
||
revision `MPSS.AT.4.0.c2.17-00194-SDM845_GEN_PACK`.
|
||
|
||
**THE REMAINING BLOCKER = device-specific RF bring-up.** Same firmware + same shared EFS + complete
|
||
stack + DT byte-identical to fajita, yet: NAS `get-system-info` empty, `nas-get-rf-band-info` →
|
||
no bands, mode stuck offline, `DeviceNotReady` on online. The modem boots but its RF never inits.
|
||
Two leads:
|
||
1. **RF cal / QCN** — generic test IMEI `990012001581294`, model `0`, no bands. Classic
|
||
no-calibration signature. UNCONFIRMED: does the WORKING Android show the REAL IMEI (→ pmOS isn't
|
||
loading cal/QCN) or the same generic one (→ red herring)? Decisive next test: reboot slot A,
|
||
read IMEI + DMS caps + bands; compare. (Not done autonomously — avoids leaving the phone
|
||
off-pmOS while unattended.)
|
||
2. **Board RF-frontend** — fajita (OnePlus 6T) works on mainline; blueline (Pixel 3) shares the
|
||
q6v5-mss DT node but has a different PMIC/RF frontend (WTR/QFE/antenna tuners). If blueline's RF
|
||
frontend needs power/GPIO/cal mainline doesn't provide for THIS board, the modem can't arm RF
|
||
even with identical firmware. (Distinct from the DEAD pm8005/mss-rail lead — this is the RF
|
||
frontend, not the modem-subsystem rail.)
|
||
|
||
### 2026-06-20 #6 — RETRACTED: do NOT treat the board-power lead as closed
|
||
I previously wrote this section as "lead #2 CLOSED with positive proof." That was an overclaim and
|
||
Casey was right to reject it. What the regulator/DT evidence below actually shows is narrower: there
|
||
is no *labeled RF-frontend regulator node* in the device tree — confirmed on BOTH mainline AND the
|
||
**downstream Android DTB** (`dt-work/android-dtb/android-base.dts`, decompiled from slot-A boot_a;
|
||
its `qcom,mss@4080000` declares only vdd_cx/vdd_mx/vdd_mss, no RF/WTR/antenna node anywhere). That
|
||
means we can't fix this by copying an "RF rail" node — NOT that board power is irrelevant. Mainline
|
||
blueline is a **minimal fresh port**: it instantiates only rails with explicit consumers and leaves
|
||
every other board rail off, whereas the downstream stack + QCRIL bring up far more (subsystems,
|
||
power-on handshakes, NV/RF init via QMI). The live lead remains: **what does the modem need powered/
|
||
initialized — via Linux rails the mainline port omits, or via QMI commands QCRIL sends — that pmOS
|
||
does not provide.** See the #8 frontier (top of file) for the QCRIL-does-more evidence.
|
||
|
||
(original text retained below for the evidence it contains)
|
||
|
||
Brought the "power Android provides" thread full circle on live hardware (Android slot A, rooted):
|
||
|
||
- **No Linux-side RF rail exists on EITHER OS.** In both the Android (`rf-compare/regulators-android.txt`)
|
||
and pmOS (`regulators-pmos.txt`) regulator dumps, the modem `4080000.qcom,mss` consumes ONLY the
|
||
Q6 DSP level rails (s6_level=CX, s9_level=MX, s2_level=MSS). There is no WTR/PA/tuner regulator
|
||
in Linux on Android either — RF-frontend power is driven by the modem firmware over RFFE + GRFC,
|
||
not the Linux regulator framework. So a "missing regulator in the pmOS DT" was never possible.
|
||
- **DT modem node is correct + complete** (`dt-work/blueline-pmos.dts`): power-domains cx/mx/mss,
|
||
xo/bus/mem clocks, glink "modem" transport, `gpio-reserved-ranges = <0 4, 81 4>` (Linux leaves
|
||
the modem-owned GPIOs alone). No regulator-supply phandles — correct for mainline q6v5-mss.
|
||
- **Pinctrl: no AP/modem GPIO conflict.** Android TLMM (`3400000.pinctrl`) owns only camera-CCI,
|
||
gpio-keys, and USB-extcon pins; the modem's GRFC/RF-control pins are MSS-internal and not
|
||
AP-routed. The AP cannot be stepping on an RF pin.
|
||
- **"No bands" is NOT a distinguishing signal.** The fresh working-Android radio capture
|
||
(`android-capture-20260620/android-radio-log.txt`) shows `mBands=[]` in CellIdentityLte while
|
||
fully attached to Fido LTE (REG_HOME, EARFCN 2000 = B4). So the empty mBands we saw on pmOS does
|
||
not by itself mean RF is dead — weakens (does not kill) lead #1's reasoning.
|
||
|
||
**Verdict:** every AP-side power/GPIO/pinctrl/DT input the modem receives is provably equal to
|
||
blueline-Android (which arms RF on the same silicon). Lead #2 is closed the same way IMEI closed
|
||
lead #1. The blocker lives strictly inside the modem firmware's RF-init, which the AP only feeds
|
||
via: firmware blobs, EFS (rmtfs), persist/rfs (tqftpserv), power-domains, clocks, QMI. All proven
|
||
present/equal — EXCEPT we have never traced what the modem *requests* from rmtfs/tqftpserv during
|
||
its RF-init, nor captured the modem's own failure reason.
|
||
|
||
**Decisive next experiment (pmOS-side, not yet run):** boot slot A, attempt `online`, and capture
|
||
(a) `tqftpserv`/`rmtfs` request trace during RF-init — which file/NV path the modem asks for and
|
||
whether it's served (frontier #4 showed Android rmt_storage *reads* on boot; we never logged the
|
||
pmOS read side), and (b) the modem remoteproc coredump / SSR reason on the failed online. This is
|
||
the one byte-for-byte trace we still lack; it points at the specific RF-init resource that differs.
|
||
|
||
Route B (autoselect EFS NV item) is DEPRIORITIZED: it would only persist the config state we
|
||
already achieved, and config-active does not fix online.
|
||
|
||
---
|
||
|
||
## The frontier (REVISED 2026-06-20 #4 — Android boot is VERIFY-ONLY; the modem persists MCFG itself)
|
||
|
||
Source: analysis of the captured Android radio logs in `android-live-20260619/deep/`
|
||
(`radio-boot.txt`, `radio-full.txt`, `ssr-capture.txt`), 2026-06-20. This **overturns** both
|
||
frontier #3's "just make the platform config active" and the `qcril_full_provisioning.md §D.4`
|
||
"load+activate every boot" model. Read this before either.
|
||
|
||
### What the captures actually show
|
||
|
||
Across all three logs (~12K PDC log lines, including a full modem SSR) QCRIL made **only query
|
||
calls** — never load/select/activate, never `pdc_enable_auto_selection`:
|
||
|
||
- `ssr-capture.txt:24293` — the decision point:
|
||
`qcril_qmi_pdc_is_modem_mbn_updated: prev_ver_info: MCFG-g845-00194-220517-B-8604334,
|
||
cur_ver_info: MCFG-g845-00194-220517-B-8604334` → **prev == cur → reload SKIPPED.**
|
||
- `ssr-capture.txt:23949` — `get_active_config_info_ind: config_version = 0x801481a`,
|
||
`Update CNV from 0x48 to 0x48` (0x48 = **72** = `cnv=[72]` = `persist.vendor.radio.mbn0=72`).
|
||
- Only PDC functions logged anywhere: `get_active_config_info`, `get_selected_mbn_config`,
|
||
`get_selection_carrier`, `is_modem_mbn_updated`. **Zero** `*_load_config`, `*_select_config`,
|
||
`*_activate_config`, `enable_auto_selection`, `enable_modem_update`.
|
||
|
||
### What that means
|
||
|
||
**Android's steady-state boot does almost nothing to PDC.** The modem holds its MCFG persisted in
|
||
its own EFS (`modemst1/2` — the 2 MB write to `modem_fs2` the `rmt_storage` capture caught),
|
||
**self-applies it at firmware RF-init every boot**, and QCRIL just confirms the active version
|
||
matches `persist.vendor.radio.cnv.ver_info` and stops. The full load→select→activate path runs
|
||
**only on first provision or an MCFG version change** (the `prev_ver != cur_ver` branch) — which
|
||
we have **never captured**, because every capture was an already-provisioned device. That is
|
||
exactly why `pdc_enable_auto_selection` never appears: it lives on the unobserved path.
|
||
|
||
### Consequences for the two prior theories
|
||
|
||
- **Frontier #3 ("just need an active platform config")** — necessary but NOT sufficient. PROGRESS
|
||
L165–172 had BOTH configs active (SS-LA-SDM845 + Rogers) and DMS Networks stayed empty. Active
|
||
≠ armed. Don't chase "make it active" as the finish line.
|
||
- **`§D.4` ("load+activate every boot, accept two restarts")** — that is a *reconstruction of the
|
||
unobserved first-provision path*, not what Android does in steady state. It remains a valid
|
||
pmOS *workaround* (see `tools/qcril-prov.py`), but it is unproven on hardware and is not the
|
||
mechanism that actually arms RF on Android.
|
||
|
||
### The pmOS problem, restated from the evidence
|
||
|
||
The "0/0 configs every cold boot" volatility (PROGRESS L140–144) is **not** something QCRIL fixes
|
||
per-boot. It's that **the modem cannot persist/restore its PDC selection in EFS the way Android
|
||
does.** The earlier "rmtfs read-write didn't fix it" result (ledger L38) is a chicken-and-egg:
|
||
writable EFS is useless if the modem never had a valid MCFG to commit, and a one-shot userspace
|
||
activate is useless if it cannot persist to survive the next firmware RF-init. **Both are
|
||
required: a valid config loaded AND modem-side persistence that survives reboot.**
|
||
|
||
### Two candidate paths forward
|
||
|
||
- **(A) Per-boot provisioner workaround** — `tools/qcril-prov.py` loads HW+SW, selects, activates
|
||
each boot. Mirrors the reconstructed first-provision path. Unproven; "active ≠ armed" is the
|
||
open risk.
|
||
- **(B) Provision-once + persistence (the Android mechanism)** — get a valid MCFG into the modem
|
||
once, then ensure `modemst` persistence so the modem self-restores + self-applies at RF-init,
|
||
and userspace reverts to verify-only. This is what the captures show actually works on hardware.
|
||
|
||
### The capture we still need (next experiment)
|
||
|
||
A normal-boot capture only re-shows the skip path. To record the **real first-provision load
|
||
sequence** (and settle whether `pdc_enable_auto_selection` / `enable_modem_update` is a required
|
||
precondition), **force a first-provision on Android**: clear `/data/vendor/modem_config/` and
|
||
`persist.vendor.radio.cnv.ver_info`, reboot, then capture. Runbook:
|
||
`PAF/first_provision_capture.md`.
|
||
|
||
---
|
||
|
||
## The frontier (SUPERSEDED 2026-06-19 #3 — see #4 above — PDC platform config is the blocker)
|
||
|
||
After a full day of Android-vs-pmOS forensics, the blocker is identified:
|
||
|
||
### What's actually wrong
|
||
|
||
The modem's **PDC (Policy Decision Control)** stores MBN configs in modem NV:
|
||
|
||
- **25 software (carrier) configs** loaded — **Rogers_Canada is ACTIVE** (133KB, v0x801481A)
|
||
- **2 platform (hardware) configs** loaded — **SS-LA-SDM845 is INACTIVE** (56KB)
|
||
|
||
Without an **active platform config**, the modem doesn't know its RF hardware capabilities.
|
||
DMS reports `Networks: ''`, NAS home network returns `NotProvisioned (QMI 16)`, and
|
||
`Set Operating Mode=online` returns `DeviceNotReady (QMI 52)`.
|
||
|
||
On Android, QCRIL (`libril-qc-hal-qmi.so`) loads MBN files from `/vendor/rfs/msm/mpss/readonly/vendor/mbn/`
|
||
via QMI PDC, activates both platform and software configs, and the modem restarts with full RF.
|
||
|
||
ModemManager does none of this — it assumes the modem is pre-provisioned.
|
||
|
||
### Attempted: direct PDC activation
|
||
|
||
`qmicli --pdc-activate-config=platform,6FE571A9...` returned **"Successfully requested config
|
||
activation"** but triggered a modem restart that **cleared the platform config** (0 configs after
|
||
restart). The activation request succeeded at the QMI level but the modem's internal handling
|
||
removed the config during restart. Needs Android QCRIL to re-load it.
|
||
|
||
`qmicli --pdc-load-config=...` **segfaults** on MBN binary files (qmicli 1.39.0 / libqmi 1.38.0).
|
||
Cannot load MBN files from pmOS side — libqmi bug or MBN format incompatibility.
|
||
|
||
### Key facts confirmed (06-19)
|
||
|
||
- **IMEI: identical** on Android and pmOS (`990012001581294`). NOT the blocker. Android works on
|
||
Fido LTE with this same test IMEI.
|
||
- **Modem firmware: identical** SHA256 (`97c1d19c...`) between slots A and B.
|
||
- **Modem crashes** (SFR Init / XPU violation): **intermittent** — some boots 0 crashes, some 2.
|
||
Even clean boots get DeviceNotReady. Not the blocker.
|
||
- **rmtfs DOES serve correct partitions**: partlabels are GPT-stable; UFS LUN renumbering changes
|
||
`/dev/sdX` names between boots but `by-partlabel` symlinks always resolve correctly.
|
||
- **DMS Get Capabilities** consistently shows `Networks: ''` and `Max TX/RX: 0` on pmOS.
|
||
Android shows populated networks (Fido LTE, Rogers 302720, full band support).
|
||
- **NAS Get System Selection Preference** shows FULL band tables on both OSes (43 LTE bands +
|
||
extended). NAS has the data; DMS doesn't. The bridge is the platform MBN activation.
|
||
- **Android rmt_storage**: reads EFS on boot (no writes), writes 2MB to modem_fs2 AFTER going
|
||
online. Normal operation — not initial provisioning.
|
||
- **pmOS rmtfs journal**: empty (rmtfs doesn't log successful reads/writes). No errors either.
|
||
|
||
### Fix path
|
||
|
||
1. Boot Android to let QCRIL re-load the platform MBN into PDC (it was there before activation)
|
||
2. Boot pmOS — do NOT touch PDC, do NOT run `qmicli` activation
|
||
3. Verify: `qmicli --pdc-list-configs=platform` shows SS-LA-SDM845 as Active
|
||
4. Verify: `qmicli --dms-get-capabilities` shows `Networks: 'gsm, wcdma, lte'`
|
||
5. Let ModemManager drive enable→online (NEVER manual qmicli online)
|
||
6. If platform config is still Inactive after Android: need to fix `qmicli --pdc-load-config`
|
||
segfault, or write a minimal MBN loader using libqmi directly
|
||
|
||
### What we have on device
|
||
|
||
- rmtfs: read-write (`-P -s`), serving correct EFS partitions via partlabels
|
||
- tqftpserv: bind-mounted to `/mnt/vendor/persist/rfs` (persist partition)
|
||
- pd-mapper: installed and running from boot
|
||
- MBN files: 179 files (11MB) at `/mnt/vendor/persist/rfs/readonly/vendor/mbn/`
|
||
(extracted from Android `/vendor/rfs/msm/mpss/readonly/vendor/mbn/`)
|
||
- MCFG version: `g845-00194-220517-B-8604334`
|
||
- Rogers Canada MBN: `mcfg_sw/generic/NA/Rogers/Commercial/CA/mcfg_sw.mbn`
|
||
- SDM845 LA/SS platform MBN: `mcfg_hw/generic/common/SDM845/LA/SS/mcfg_hw.mbn` (56KB)
|
||
- Kernel: building from `sdm845/7.1-dev` HEAD (`85f1df2a`), config fixed to `sdm845`
|
||
|
||
### Android vs pmOS service comparison
|
||
|
||
| Component | Android | pmOS | Notes |
|
||
|-----------|---------|------|-------|
|
||
| EFS storage | rmt_storage r/w | rmtfs `-P -s` r/w | Parity |
|
||
| TFTP | tftp_server → vendor/rfs | tqftpserv → persist bind | Parity |
|
||
| pd-mapper | running (maps PDs) | running | Parity |
|
||
| RIL | QCRIL (`libril-qc-hal-qmi.so`) | ModemManager | **Missing PDC provisioning** |
|
||
| ipacm | running (`/dev/ipa` FDs) | not installed | Data path only |
|
||
| Keymaster | decrypts persist blobs | none | IMEI encrypted at rest |
|
||
| QMI services | comparable (50+) | comparable (50+) | Parity |
|
||
|
||
### (superseded) earlier frontiers
|
||
|
||
**Read-only rmtfs theory (06-19 #2):** rmtfs read-only prevented modem from persisting EFS
|
||
writes. Fixing to read-write didn't resolve DeviceNotReady. EFS r/w is necessary but not
|
||
sufficient — the modem needs valid MCFG in EFS first, which comes from PDC provisioning.
|
||
|
||
**QMI-handshake theory (original):** "MM doesn't send QCRIL's init sequence." Dead —
|
||
same MM binary works on OnePlus 6. The missing sequence is PDC MBN loading, not a
|
||
handshake gap. Other SDM845 devices likely have platform config pre-loaded from factory.
|
||
|
||
**fsg_oem theory:** Modem requesting `modem_fsg_oem_1/2`. Patched rmtfs to serve them.
|
||
Modem never actually requests these when EFS is properly provisioned. Symptom, not cause.
|
||
|
||
**XPU violation theory:** Modem crashes twice on some boots. Even on clean (0-crash) boots,
|
||
DeviceNotReady persists. Not the blocker.
|
||
|
||
## Useful commands (pmOS)
|
||
|
||
```sh
|
||
qrtr-lookup | awk '$1==11' # UIM service → note Port
|
||
qmicli -p -d qrtr://0/<port> --uim-get-card-status
|
||
qmicli -d qrtr://0 --dms-get-operating-mode
|
||
qmicli -d qrtr://0 --dms-set-operating-mode=online
|
||
qmicli -d qrtr://0 --dms-get-capabilities # zero rates = RF uninit
|
||
# clean modem re-init (rmtfs runs -P -s read-write; see 2026-07-02 correction):
|
||
echo stop | sudo tee /sys/class/remoteproc/remoteproc2/state ; sleep 3
|
||
echo start | sudo tee /sys/class/remoteproc/remoteproc2/state
|
||
# preferred: QMI Set Operating Mode = RESET (4) reinitializes without touching UIM/provisioning.
|
||
```
|
||
|
||
Forcing a remoteproc reset clears UIM provisioning; `msm-modem-uim-selection` only re-runs at
|
||
boot. (The old note here claimed `-r -P -s` read-only was required for re-provisioning — stale
|
||
and wrong; rmtfs runs `-P -s` read-write live and the modem re-provisions fine across a
|
||
stop→start. For a clean reinit that does NOT drop provisioning, use QMI RESET, not remoteproc.)
|
||
|
||
## Cross-references worth mining
|
||
|
||
- **Working SDM845 (same SoC):** OnePlus 6/6T (enchilada/fajita), Poco F1 (beryllium),
|
||
SHIFT6mq (axolotl) — data + SMS work via the same mainline kernel + pmaports packages.
|
||
Their *AP-side* config is already in `~/pmos/pmaports`; nothing to pull. Their working
|
||
firmware/EFS is device-specific and not transplantable.
|
||
- **Pixel 3a (sargo) / 3a XL (bonito):** the closest *Google* analogs with modem support in
|
||
pmaports (SDM670). Best target if a Google-specific RIL quirk is suspected.
|
||
- **Android on this exact device** is the cleanest reference: same silicon, modem works.
|
||
Diff blueline-Android vs blueline-pmOS, not against OnePlus.
|
||
|
||
## TOP LEAD 2026-07-02 #16 — locally-initiated DIAG_CTRL/DIAG_DATA open CRASHES the modem (glink_channel_migration assertion), repeatably
|
||
|
||
**Real, causal, previously-unknown finding — not a theory.** Following up #15's ack-but-no-reciprocal-
|
||
open result: tried the same locally-initiated open against `DIAG_CTRL` (not just `DIAG_DATA`).
|
||
Confirmed via `dmesg -T` (not my own client's stderr, which kept getting lost across SSH session
|
||
churn — the KERNEL'S OWN log line is the ground truth here): `rpmsg rpmsg0: failed to open DIAG_CTRL`
|
||
fires cleanly at the expected 5s mainline timeout, exactly as designed. But roughly 18-40 seconds
|
||
LATER, every single time this was attempted (three separate occasions, two of them minutes apart on
|
||
different modem boots), the modem hard-crashes:
|
||
```
|
||
qcom-q6v5-mss 4080000.remoteproc: fatal error received: [disable_ssr]glink_channel_migration.c:602:
|
||
[IST336]Assertion status == GLINK_STATUS_SUCCESS failed
|
||
remoteproc remoteproc3: crash detected in 4080000.remoteproc: type fatal error
|
||
remoteproc remoteproc3: handling crash #N in 4080000.remoteproc
|
||
```
|
||
This is a **repeatable causal chain**, confirmed across crashes #5 and #6 in the same dmesg buffer,
|
||
both immediately following a `failed to open DIAG_CTRL` line, both with the identical
|
||
`glink_channel_migration.c:602` assertion. `glink_channel_migration.c` is the FIRMWARE's own glink
|
||
channel-transport-migration logic (this is a modem-firmware-side log line, reported via SFR/fatal
|
||
error, not an AP-side kernel message) — meaning the incomplete/abandoned local-open handshake left
|
||
channel/migration bookkeeping in a state the modem's own firmware asserts on and can't tolerate.
|
||
|
||
**Practical, urgent implication**: DO NOT locally-initiate an open for `DIAG_DATA` or `DIAG_CTRL`
|
||
casually or repeatedly during further investigation — it reliably crashes the whole modem MSS a
|
||
short time later, disrupting whatever else was being tested (this crashed WLAN's firmware too, via
|
||
the shared XPU/hyp-assign path, matching TOP LEAD #11's earlier finding about shared secure-memory
|
||
fragility). If this path is pursued further, it needs to be done RARELY, with full crash-recovery
|
||
tolerance, ideally on a boot with nothing else running that a modem SSR would disrupt.
|
||
|
||
**What this actually tells us, functionally**: the modem's glink/migration layer is NOT robust to an
|
||
AP-initiated open attempt that times out — downstream never hits this because (a) it doesn't time out
|
||
in 5s (event-driven, no hard deadline, per #15's downstream comparison) and/or (b) Android's DIAG
|
||
daemon presumably completes successfully before any abandonment would occur. This is now a second,
|
||
independent data point (alongside offline-vs-LPM, #14) that mainline's bring-up leaves this modem's
|
||
firmware in a MORE FRAGILE state than Android's does — not just "missing a feature" but "structurally
|
||
less tolerant of imperfect AP-side timing/sequencing." Worth weighing against #14's LPM finding: both
|
||
point at the same underlying idea -- whatever Android's fuller bring-up sequence does before touching
|
||
these channels, mainline's minimal sequence skips, and the modem firmware was never hardened against
|
||
being touched without it.
|
||
|
||
**Honest gap, not yet resolved**: unclear if the crash is specific to DIAG_CTRL/DATA's particular
|
||
migration-eligible status, or would happen for ANY locally-initiated open of ANY channel abandoned via
|
||
timeout. Worth testing later (carefully, expecting a crash) against a channel we know is NOT normally
|
||
migration-sensitive, to isolate whether this is DIAG-specific or a general "don't abandon a local
|
||
open" hazard on this modem.
|