Device Tree 的 iommussvcmethod = "smc"Device-tree iommus, svc and method = "smc"デバイスツリーの iommussvcmethod = "smc"

圍繞 iommus = <0x09 0x0a> 展開的八個問題 — phandle 機制、位址空間、SMC conduit、 altr,smmu_enable_quirk,以及為什麼「只移除 svc 的 iommus」在 Agilex 5 上行不通Eight questions arising from iommus = <0x09 0x0a> — the phandle mechanism, address spaces, the SMC conduit, altr,smmu_enable_quirk, and why “just remove svc's iommus” does not work on Agilex 5iommus = <0x09 0x0a> から派生する 8 つの問い — phandle の仕組み、アドレス空間、SMC conduit、altr,smmu_enable_quirk、そして「svc の iommus を外すだけ」が Agilex 5 で通用しない理由

DE25-Standard Agilex 5 (A5ED013BB32AE4SCS) Linux 6.12.11 arm-smmu-v3 stratix10-svc SMCCC / SiP

0. 這份文件的範圍0. Scope of this document0. 本書の範囲

這是 smmu_rbf_load_failure_zh.html姊妹篇。 前一份說明「為什麼 RBF 載入會失敗」; 這一份逐項拆解在讀那份分析時自然會冒出來的基礎機制問題 — device tree 的數字到底代表什麼、誰替誰做位址轉換、 以及最後那個實際動手的問題:能不能只針對 svc 一個節點下手This is the companion to smmu_rbf_load_failure_zh.html. That note explains why RBF loading fails; this one works through the underlying mechanism questions that naturally arise while reading it — what the numbers in a device tree actually mean, who translates addresses for whom, and finally the practical question: can you act on the svc node alone?本稿は smmu_rbf_load_failure_zh.html姉妹編です。あちらはなぜ RBF のロードが失敗するのかを説明し、本稿はそれを読むときに自然に浮かぶ基礎的な仕組みの疑問を一つずつ解きほぐします — デバイスツリーの数値が実際に何を表すのか、誰が誰のためにアドレス変換を行うのか、そして最後に実務的な問い:svc ノードだけを手当てできるのか

八個問題的一句話答案:One-sentence answers to the eight questions:8 つの問いに対する一言での答え:
  1. 0x09phandle(指向節點的指標),不是位址0x09 is a phandle (a pointer to a node), not an address0x09phandle(ノードを指すポインタ)であって、アドレスではない
  2. 16000000實體位址(PA / bus address),DT 裡永遠不會有 VA16000000 is a physical address (PA / bus address); a device tree never contains a VA16000000物理アドレス(PA / バスアドレス)であり、デバイスツリーに VA が入ることはない
  3. IOMMU 不是幫 CPU 轉址 — 它替裝置把 IOVA 轉成 PAThe IOMMU does not translate for the CPU — it translates IOVA to PA for devicesIOMMU は CPU のために変換するのではないデバイスのために IOVA を PA へアドレス変換する
  4. svc 兩者都是:DT 節點名 + 綁上去的 stratix10-svc 驅動svc is both: a DT node name and the stratix10-svc driver bound to itsvcその両方である:DT のノード名であり、そこにバインドされる stratix10-svc ドライバでもある
  5. method = "smc" 選擇呼叫韌體的指令(SMC→EL3,HVC→EL2)method = "smc" selects the instruction used to call firmware (SMC→EL3, HVC→EL2)method = "smc"ファームウェアを呼び出す命令を選択する(SMC→EL3、HVC→EL2)
  6. altr,smmu_enable_quirk 是 Agilex 5 上的必要屬性 — SMMU 支援是刻意設計的,不是意外altr,smmu_enable_quirk is a required property on Agilex 5 — SMMU support is deliberate design, not an accidentaltr,smmu_enable_quirk は Agilex 5 では必須のプロパティ — SMMU 対応は偶然ではなく意図的な設計である
  7. 不可以只移除 svciommus — Agilex 5 上會讓 svc probe 直接 -ENODEV 失敗You cannot simply remove svc's iommus — on Agilex 5 the svc probe fails outright with -ENODEVできませんsvciommus を単に外すと、Agilex 5 では svc の probe が -ENODEV でそのまま失敗する
  8. 真正該做的是對齊 kernel + DTB + ATF 的版本, 並確認 quirk 在兩個節點上都存在What you should actually do is align the kernel, DTB and ATF versions and confirm the quirk is present on both nodes実際にやるべきことはカーネル・DTB・ATF のバージョンを揃えることと、quirk が両方のノードに存在するのを確認することである
訂正說明(第 6–8 節)。 本文最初的第 6、7 節建議「移除 svc 節點的 iommus」。 在查閱 /home/vivado/kernel/linux-socfpga-6.12 (tag QPDS25.3.1_REL_FCS_FIX,6.12.43)的實際原始碼後, 確認該做法在 Agilex 5 上行不通,且 StreamID 10 確實承載真實流量。 第 6–8 節已依原始碼重寫;第 1–5 節的機制說明不受影響。 Correction notice (sections 6–8). Sections 6 and 7 originally recommended “remove iommus from the svc node”. After consulting the actual sources in /home/vivado/kernel/linux-socfpga-6.12 (tag QPDS25.3.1_REL_FCS_FIX, 6.12.43), it is confirmed that this does not work on Agilex 5 and that StreamID 10 does carry real traffic. Sections 6–8 have been rewritten against the sources; the mechanism explanations in sections 1–5 are unaffected.訂正のお知らせ(第 6〜8 節)。第 6 節と第 7 節では当初「svc ノードから iommus を削除する」ことを勧めていました。/home/vivado/kernel/linux-socfpga-6.12(タグ QPDS25.3.1_REL_FCS_FIX、6.12.43)の実際のソースを確認した結果、この方法は Agilex 5 では通用しないこと、および StreamID 10 が実際のトラフィックを運んでいることが確認されました。第 6〜8 節はソースに基づいて書き直しています。第 1〜5 節の仕組みの説明には影響ありません。

1. iommus = <0x09 0x0a> 裡的 0x09 是什麼?1. What is the 0x09 in iommus = <0x09 0x0a>?1. iommus = <0x09 0x0a>0x09 とは何か?

phandle 0x09 是 iommu@16000000(arm,smmu-v3, #iommu-cells = <1>), 所以 iommus = <0x09 0x0a> 是 SMMU 上的 stream ID 10 — 那 0x09 為何存在? phandle 0x09 is iommu@16000000 (arm,smmu-v3, #iommu-cells = <1>), so iommus = <0x09 0x0a> means stream ID 10 on that SMMU — but why does 0x09 exist at all?phandle 0x09 は iommu@16000000(arm,smmu-v3, #iommu-cells = <1>)なので、iommus = <0x09 0x0a> はその SMMU 上の stream ID 10 を意味する — では 0x09 はそもそもなぜ存在するのか?

0x09 不是位址,而是一個 phandle — 指向另一個 DT 節點的 32-bit 指標。 0x09 is not an address; it is a phandle — a 32-bit pointer to another DT node.0x09アドレスではない。これは phandle — 別の DT ノードを指す 32 ビットのポインタである。

iommus 遵循 DT 標準的「phandle + specifier」格式:iommus follows the standard DT “phandle + specifier” form:iommus は DT 標準の「phandle + specifier」形式に従う:

iommus = <phandle specifier...> 0x09 0x0a ↑ 指向哪個 IOMMU↑ which IOMMU it points at↑ どの IOMMU を指すか ↑ 對那個 IOMMU 而言的參數↑ the parameter, as that IOMMU understands it↑ その IOMMU にとってのパラメータ
Cell 角色Role役割 含意Meaning意味
0x09 phandle iommu@16000000 節點上 phandle 屬性的值。 由 dtc 在編譯時自動配發(0x01、0x02… 依序給每個被引用到的節點)。 數值本身沒有任何意義,只在這一份 .dtb 內部有效。The value of the phandle property on the iommu@16000000 node. Assigned automatically by dtc at compile time (0x01, 0x02, … in order, to every node that is referenced). The number itself carries no meaning and is valid only within this one .dtb.iommu@16000000 ノードの phandle プロパティの値。dtc がコンパイル時に自動で割り当てる(参照されるノードへ 0x01、0x02… と順に振られる)。数値自体に意味はなく、この .dtb の内部でのみ有効である。
0x0a specifier 寬度由目標節點的 #iommu-cells = <1> 決定 → 只吃一個 cell。 對 arm,smmu-v3 而言這一個 cell 就是 StreamID → 10。Its width is set by the target node's #iommu-cells = <1> → it consumes exactly one cell. For arm,smmu-v3 that single cell is the StreamID → 10.幅は対象ノードの #iommu-cells = <1> が決める → cell をちょうど 1 個だけ消費する。arm,smmu-v3 にとってその 1 cell が StreamID → 10 である。

原始 .dts 裡其實不長這樣The original .dts does not look like this元の .dts はこの形をしていない

你看到的是反編譯後的結果。人寫的原始碼是 label reference:What you are looking at is the decompiled output. The human-written source uses a label reference:いま見ているのは逆コンパイルした出力である。人が書いたソースはラベル参照を使う:

/* 原始 .dts — 人寫的 *//* original .dts — as written by a human *//* 元の .dts — 人が書いたもの */
iommus = <&smmu 10>;

/* dtc 編譯後,&smmu 被換成 smmu 節點的 phandle 數值 *//* after dtc, &smmu is replaced by the smmu node's phandle value *//* dtc の処理後、&smmu は smmu ノードの phandle 値に置き換わる */
iommus = <0x09 0x0a>;

要驗證這條連結的另一端,直接找誰宣告了 phandle = <0x09>To verify the other end of the link, just find who declares phandle = <0x09>:このリンクのもう一方の端を確かめるには、phandle = <0x09> を宣言しているのが誰かを探せばよい:

dtc -I dtb -O dts system.dtb | grep -n 'phandle = <0x09>'
同一套機制在 DT 裡到處都是。 clocks = <&clk 3>interrupts-extendeddmasgpiosmemory-region 全是「phandle + specifier」, specifier 寬度一律由目標節點的 #*-cells 宣告。 看懂一個就看懂全部。 The same mechanism appears all over a device tree. clocks = <&clk 3>, interrupts-extended, dmas, gpios and memory-region are all “phandle + specifier”, and the specifier width is always declared by the target node's #*-cells. Understand one and you understand them all.同じ仕組みはデバイスツリーの至るところに現れる。clocks = <&clk 3>interrupts-extendeddmasgpiosmemory-region はすべて「phandle + specifier」であり、specifier の幅は常に対象ノードの #*-cells が宣言する。一つ分かればすべて分かる。

2. iommu@1600000016000000 是 VA 還是 PA?2. Is the 16000000 in iommu@16000000 a VA or a PA?2. iommu@1600000016000000 は VA か PA か?

16000000 is va or pa?

PA(更精確地說:父匯流排位址空間中的位址)。 Device tree 裡永遠不會出現虛擬位址。 It is a PA (more precisely: an address in the parent bus's address space). A virtual address never appears in a device tree.PA である(より正確に言えば 親バスのアドレス空間におけるアドレス)。仮想アドレスがデバイスツリーに現れることはない。

@ 之後的部分叫做 unit address, 依 DT 規範必須等於該節點 reg 的第一個位址。 而 reg 是用父節點的位址空間表示的: The part after @ is the unit address, and per the DT specification it must equal the first address in that node's reg. And reg is expressed in the parent node's address space:@ の後ろは unit address であり、DT 仕様ではそのノードの reg の先頭アドレスと一致していなければならない。そして reg親ノードのアドレス空間で表される:

父匯流排的 rangesThe parent bus's ranges親バスの ranges unit address 的意義What the unit address meansunit address の意味
空的 ranges; 或 identity mapping
(HPS 週邊匯流排的常態)
An empty ranges; or an identity mapping
(the normal case for the HPS peripheral bus)
空の ranges;、または恒等マッピング
(HPS 周辺バスでは通常こちら)
= CPU 實體位址。 所以 0x1600_0000 就是 SMMUv3 register window 在 HPS memory map 裡的 PA。= the CPU physical address. So 0x1600_0000 is the PA of the SMMUv3 register window in the HPS memory map.= CPU の物理アドレス。したがって 0x1600_0000 は HPS メモリマップ上の SMMUv3 レジスタ窓の PA である。
非 identity 的 ranges
(如 PCIe、部分橋接器)
A non-identity ranges
(e.g. PCIe, some bridges)
恒等でない ranges
(例:PCIe、一部のブリッジ)
child bus address,必須沿著父節點鏈一路往 root 翻譯才會得到 CPU PA。It is a child bus address and must be translated up the parent chain to the root before you get a CPU PA.これは子バスのアドレスであり、CPU の PA を得るには親を辿ってルートまでアドレス変換する必要がある。

那 VA 什麼時候才出現?So when does a VA appear?では VA はいつ現れるのか?

只在 driver probe 的那一刻,由 kernel 動態產生,而且與 0x16000000 完全無關:Only at driver probe time, generated dynamically by the kernel, and entirely unrelated to 0x16000000:ドライバの probe 時にカーネルが動的に生成するときだけであり、0x16000000 とはまったく無関係である:

DT: reg = <0x0 0x16000000 ...> devm_platform_ioremap_resource() 回傳一個 kernel VAreturns a kernel VAカーネル VA を返す (固定寫在檔案裡的 PA) (每次開機可能不同)(the PA, fixed in the file) (may differ on every boot) (ファイルに固定で書かれた PA) (ブートのたびに変わりうる)
為什麼 DT 不可能放 VA: DT 是在 kernel 啟動前就存在的靜態描述檔(U-Boot 交給 kernel 的一塊資料)。 那個時間點根本還沒有 page table、沒有 ioremap、也沒有任何 VA 的概念。 DT 描述的是硬體接線,硬體只認得實體位址。 Why a DT cannot contain a VA: the device tree is a static description that exists before the kernel starts (a blob handed to the kernel by U-Boot). At that point there are no page tables, no ioremap and no notion of a VA at all. A DT describes how the hardware is wired, and hardware only understands physical addresses.DT に VA を置けない理由:デバイスツリーはカーネルが起動する前から存在する静的な記述である(U-Boot がカーネルへ渡す一塊のデータ)。その時点ではページテーブルも ioremap も存在せず、VA という概念自体がない。DT が記述するのはハードウェアの配線であり、ハードウェアは物理アドレスしか理解しない。

3. IOMMU 是幫 CPU 把位址轉成 bus address 嗎?3. Does the IOMMU translate CPU addresses into bus addresses?3. IOMMU は CPU のアドレスをバスアドレスへ変換するのか?

iommu translate the address for cpu to bus address?

不是,方向剛好相反,而且 CPU 完全不參與。 SMMU 位於裝置與記憶體之間,不是 CPU 與匯流排之間。 No — the direction is the opposite, and the CPU is not involved at all. The SMMU sits between devices and memory, not between the CPU and the bus.いいえ — 向きは逆であり、そもそも CPU は関与しません。SMMU は CPU とバスの間ではなく、デバイスとメモリの間に位置する。

CPU 側: VA ──[ CPU MMU ]──▶ PA ──▶ interconnect ──▶ DRAM 或 MMIO 裝置側: IOVA ──[ SMMU ]──▶ PA ──▶ interconnect ──▶ DRAMCPU side: VA ──[ CPU MMU ]──▶ PA ──▶ interconnect ──▶ DRAM or MMIO Device side: IOVA ──[ SMMU ]──▶ PA ──▶ interconnect ──▶ DRAMCPU 側: VA ──[ CPU MMU ]──▶ PA ──▶ interconnect ──▶ DRAM または MMIO デバイス側: IOVA ──[ SMMU ]──▶ PA ──▶ interconnect ──▶ DRAM
轉譯器Translator変換する主体 服務對象Serves対象 轉譯方向Direction向き 依據Based on根拠
MMU CPU VA → PA process / kernel page table (TTBR0/1_EL1)
SMMU 會發起 DMA 的裝置Devices that initiate DMADMA を起こすデバイス IOVA → PA StreamID 查 stream table,再走該裝置 domain 的 page tableLooks up the stream table by StreamID, then walks that device domain's page tableStreamID でストリームテーブルを引き、そのデバイスドメインのページテーブルをウォークする

裝置放上匯流排的那個位址就是 IOVA, 也就是 Linux DMA API 裡 dma_addr_t 所裝的數值。 CPU 的 load/store 從來不會經過 SMMU。 這正是為什麼節點上加了 iommus, 對「CPU 讀寫該週邊的 register」完全沒有影響。 The address a device puts on the bus is the IOVA — the value carried in dma_addr_t in the Linux DMA API. A CPU load/store never passes through the SMMU. That is exactly why adding iommus to a node has no effect whatsoever on “the CPU reading and writing that peripheral's registers”.デバイスがバス上へ出すアドレスが IOVA であり、Linux DMA API の dma_addr_t が運ぶ値そのものである。CPU のロード/ストアが SMMU を通ることはない。だからこそ、ノードに iommus を足しても「CPU がその周辺デバイスのレジスタを読み書きすること」にはまったく影響しない。

真正做「CPU ↔ bus 位址」轉換的是這兩個,但都不是 IOMMUThe two things that really do translate “CPU ↔ bus address” — neither of which is an IOMMU本当に「CPU ↔ バスアドレス」を変換する 2 つのもの — どちらも IOMMU ではない

屬性Propertyプロパティ 方向Direction向き 性質Nature性質
ranges child bus → parent bus
(往 CPU 側翻譯 reg(translates reg toward the CPU side)reg を CPU 側へ変換する)
靜態位移。純粹的位址算術,在 DT 解析階段由軟體完成, 沒有硬體 page table。A static offset. Pure address arithmetic, performed by software while parsing the DT; no hardware page table involved.静的なオフセット。純粋なアドレス計算であり、DT を解析する際にソフトウェアが行う。ハードウェアのページテーブルは関与しない。
dma-ranges 裝置 → 記憶體Device → memoryデバイス → メモリ 同樣靜態。描述 interconnect 固定套用的視窗/位移。 即使完全沒有 IOMMU,它也會讓 dma_addr_t ≠ PAAlso static. Describes a fixed window/offset applied by the interconnect. It makes dma_addr_t ≠ PA even when there is no IOMMU at all.これも静的である。インターコネクトが適用する固定の窓/オフセットを記述する。IOMMU がまったく無くても dma_addr_t ≠ PA になりうる。

三個位址空間 — 只有兩個有機會相等Three address spaces — only two can ever be equal3 つのアドレス空間 — 等しくなれるのは常に 2 つまで

發起者Initiator起点となるもの 它送出的位址The address it emitsそこが出すアドレス 被誰轉譯Translated by変換する主体
CPU (kernel / user) VA MMU → PA
Linux 裝置做 DMAA Linux device doing DMADMA を行う Linux のデバイス IOVA (dma_addr_t) SMMU → PA
SDM(remapper 啟用時)SDM (with the remapper enabled)SDM(リマッパ有効時) 經 SDM remapper 的位址An address passed through the SDM remapperSDM のリマッパを通されたアドレス SDM 自己的硬體 remapperThe SDM's own hardware remapperSDM 自身のハードウェアリマッパ
SDM(remapper 停用時)SDM (with the remapper disabled)SDM(リマッパ無効時) IOVA + 0x8000_0000 SMMU (StreamID 10)
關於 SDM 的重要修正: 在 Agilex 5 上,SDM 讀取 DRAM 的路徑確實掛在 SMMU 後面, 對應的就是 StreamID 10。 SDM 另外有一顆自己的硬體 remapper; 當 Linux 決定用 SMMU 時,驅動會發 SMC 把那顆 remapper 關掉, 改由 SMMU 負責轉譯。詳見第 6 節。 An important correction about the SDM: on Agilex 5 the SDM's DRAM read path does sit behind the SMMU, and it corresponds to StreamID 10. The SDM additionally has a hardware remapper of its own; when Linux chooses to use the SMMU, the driver issues an SMC to disable that remapper and let the SMMU do the translating instead. See section 6.SDM に関する重要な訂正:Agilex 5 では SDM の DRAM 読み出し経路は実際に SMMU の背後にある。これが StreamID 10 に対応する。SDM はさらに自前のハードウェアリマッパも持っており、Linux が SMMU を使うと決めた場合、ドライバは SMC を発行してそのリマッパを無効化し、代わりに SMMU にアドレス変換を任せる。第 6 節を参照。
因此「SDM 完全不在 SMMU 後面、只認 PA」並不適用於 Agilex 5。 這一點推翻了「移除 iommus 就能讓兩者相等」的想法 — 見第 7 節的 -ENODEV 分析。 So “the SDM is entirely outside the SMMU and only understands PAs” does not apply to Agilex 5. That fact demolishes the idea that “removing iommus makes the two equal” — see the -ENODEV analysis in section 7.したがって「SDM は完全に SMMU の外側にあり PA しか理解しない」という説明は Agilex 5 には当てはまらない。この事実は「iommus を外せば両者が一致する」という考えを崩す — 第 7 節の -ENODEV の分析を参照。

4. svc 是一個 node 還是一個 kernel module?4. Is svc a node or a kernel module?4. svc はノードなのか、カーネルモジュールなのか?

svc is a node or kernel module?

兩者都是 — 而且是同一條繫結(binding)的兩端。 svc 這個名字是 DT 節點;stratix10-svc 是綁上去的驅動。 Both — and they are the two ends of one binding. The name svc is the DT node; stratix10-svc is the driver bound to it.その両方であり、両者は一つのバインディングの両端である。名前としての svc は DT のノードであり、stratix10-svc はそこにバインドされるドライバである。

DT 節點The DT nodeDT のノード

firmware {
    svc {
        compatible    = "intel,agilex5-svc";
        method        = "smc";
        memory-region = <&svcbuffer>;      /* svcbuffer@0,保留的 32 MiB *//* svcbuffer@0, the reserved 32 MiB *//* svcbuffer@0、予約された 32 MiB */
        iommus        = <&smmu 10>;         /* ← 造成載入失敗的那一行 *//* ← the line that causes the load failure *//* ← ロード失敗を引き起こす行 */

        fpga_mgr: fpga-mgr {
            compatible = "intel,agilex5-soc-fpga-mgr";
        };
    };
};

兩個關鍵觀察:Two key observations:重要な観察が 2 点:

驅動The driverドライバ

drivers/firmware/stratix10-svc.c, config 為 CONFIG_INTEL_STRATIX10_SERVICE(tristate,因此可以stratix10-svc.ko,但 Altera 的預設 config 通常是 built-in)。 它註冊成 platform driver 來 match 上面那個 compatibledrivers/firmware/stratix10-svc.c, under CONFIG_INTEL_STRATIX10_SERVICE (tristate, so it can be stratix10-svc.ko, though Altera's default config usually builds it in). It registers as a platform driver matching the compatible above.drivers/firmware/stratix10-svc.cCONFIG_INTEL_STRATIX10_SERVICE の下にある(tristate なので stratix10-svc.ko にもできるが、Altera の既定コンフィグでは通常ビルトインされる)。上記の compatible に一致するプラットフォームドライバとして登録される。

它提供的是一個 service layer — 給其他驅動呼叫的 in-kernel API:What it provides is a service layer — an in-kernel API for other drivers to call:提供するのはサービス層 — 他のドライバから呼び出すためのカーネル内 API である:

stratix10_svc_request_channel_byname(client, "fpga");
stratix10_svc_allocate_memory();   /* 從 svcbuffer@0 切一塊 *//* carve a piece out of svcbuffer@0 *//* svcbuffer@0 から一部を切り出す */
stratix10_svc_send();              /* → SMC → ATF → SDM */

它的 consumer 是 drivers/fpga/stratix10-soc.c(FPGA manager)與 stratix10-rsu.cIts consumers are drivers/fpga/stratix10-soc.c (the FPGA manager) and stratix10-rsu.c.利用者は drivers/fpga/stratix10-soc.c(FPGA マネージャ)と stratix10-rsu.c である。

所以 log 為什麼寫 firmware:svc:fpga-mgrSo why does the log say firmware:svc:fpga-mgr?では、なぜログには firmware:svc:fpga-mgr と出るのか?

因為帶有 compatible 的 DT 節點會被實例化成 platform device, 而 device 名稱就是把 DT 路徑的 / 換成 :Because a DT node carrying a compatible is instantiated as a platform device, and the device name is the DT path with / replaced by ::compatible を持つ DT ノードはプラットフォームデバイスとして実体化され、そのデバイス名は DT のパスの /: に置き換えたものになるからである:

DT 路徑DT pathDT のパス Linux device 名稱Linux device nameLinux のデバイス名 驅動Driverドライバ
/firmware/svc firmware:svc stratix10-svc
/firmware/svc/fpga-mgr firmware:svc:fpga-mgr stratix10-soc (FPGA mgr)
Stratix10 SoC FPGA manager firmware:svc:fpga-mgr: timeout waiting for svc layer buffers ↑ 子節點(fpga-mgr)抱怨父節點(service layer)沒交出可用的 buffer↑ the child node (fpga-mgr) complaining that the parent (the service layer) never handed over a usable buffer↑ 親(サービス層)が使えるバッファを渡してくれない、と子ノード(fpga-mgr)が訴えている
最關鍵的一點:firmware:svc 是一個有 DT 節點的真實 struct device, 這正是 iommus 會生效、以及你會看到 stratix10-svc firmware:svc: Adding to iommu group 3 的原因。 一個純粹的 kernel module、沒有 DT 節點的話,永遠不會拿到 SMMU StreamID。 The crucial point: firmware:svc is a real struct device backed by a DT node, which is precisely why iommus takes effect and why you see stratix10-svc firmware:svc: Adding to iommu group 3. A plain kernel module with no DT node would never be given an SMMU StreamID.肝心なのは、firmware:svcDT ノードに裏打ちされた本物の struct device だという点である。だからこそ iommus が効き、stratix10-svc firmware:svc: Adding to iommu group 3 が出る。DT ノードを持たない単なるカーネルモジュールに SMMU の StreamID が与えられることはない。

在板子上驗證Verifying it on the boardボード上での確認

ls /proc/device-tree/firmware/svc/
ls -l /sys/bus/platform/devices/firmware:svc/driver
grep -i stratix10 /proc/modules      # 若是 built-in 則為空# empty if built in# ビルトインなら空

5. method = "smc" 是什麼意思?5. What does method = "smc" mean?5. method = "smc" は何を意味するのか?

what does method = "smc" mean?

它選擇 conduit — 驅動用哪一條 ARM 指令呼叫韌體。 與 PSCI 的 method 是同一個屬性、同樣只有兩種合法值。 It selects the conduitwhich ARM instruction the driver uses to call firmware. It is the same property as PSCI's method, with the same two legal values.これは conduit を選ぶ — ドライバがファームウェアを呼ぶのにどの ARM 命令を使うかである。PSCI の method と同じプロパティで、取りうる値も同じ 2 つである。

Value 指令Instruction命令 trap 到Traps toトラップ先 由誰處理Handled by処理する主体
"smc" SMC #0 EL3 Secure Monitor — TF-A / ATF BL31
"hvc" HVC #0 EL2 Hypervisor

你的板子上 Linux 跑在 EL1 並且直接擁有 EL3 呼叫權,所以是 "smc"。 只有當 Linux 是 guest、且 EL2 的 hypervisor 要代為攔截/轉送韌體呼叫時,才會改用 "hvc"On your board Linux runs at EL1 and holds the right to call EL3 directly, so it is "smc". "hvc" is used only when Linux is a guest and a hypervisor at EL2 must intercept or forward firmware calls on its behalf.このボードでは Linux は EL1 で動作し、EL3 を直接呼ぶ権利を持っているので "smc" になる。"hvc" は Linux がゲストであり、EL2 のハイパーバイザがファームウェア呼び出しを代理で横取り・転送しなければならない場合にだけ使われる。

驅動拿這個字串做什麼What the driver does with the stringドライバはこの文字列を何に使うのか

stratix10-svc.c 只是用它挑一個 function pointer:stratix10-svc.c only uses it to pick a function pointer:stratix10-svc.c はこれを関数ポインタの選択にしか使わない:

if (!strcmp(method, "smc"))
        sh->invoke_fn = svc_smccc_smc;   /* → arm_smccc_1_1_smc() */
else if (!strcmp(method, "hvc"))
        sh->invoke_fn = svc_smccc_hvc;   /* → arm_smccc_1_1_hvc() */
else
        return -EINVAL;

之後每一次請求都走 sh->invoke_fn(...)。 這個字串是兩條路徑唯一的差別 — 參數的排列方式完全相同。 Every subsequent request then goes through sh->invoke_fn(...). That string is the only difference between the two paths — the argument layout is identical.以降のリクエストはすべて sh->invoke_fn(...) を経由する。この文字列が 2 つの経路の唯一の違いであり、引数の並びは同一である。

呼叫本身(SMCCC)The call itself (SMCCC)呼び出しそのもの(SMCCC)

參數放在 x0x7,其中 x0 是 function ID; 回傳值放在 x0x3。 Altera 使用 SiP(Silicon Provider)廠商保留範圍Arguments go in x0x7, with x0 holding the function ID; return values come back in x0x3. Altera uses the SiP (Silicon Provider) vendor-reserved range:引数は x0x7 に入り、x0 が関数 ID を保持する。戻り値は x0x3 で返る。Altera は SiP(Silicon Provider)ベンダ予約領域を使う:

INTEL_SIP_SMC_FPGA_CONFIG_START            0xC2000001
INTEL_SIP_SMC_FPGA_CONFIG_WRITE           0xC2000002
INTEL_SIP_SMC_FPGA_CONFIG_COMPLETED_WRITE
INTEL_SIP_SMC_FPGA_CONFIG_ISDONE

0xC2… 解碼為:fast call / SMC64 / owner = SiP。 0xC2… decodes as: fast call / SMC64 / owner = SiP.0xC2… は fast call / SMC64 / owner = SiP と解釈される。

fpga-mgr stratix10-svc SMC #0 EL3 TF-A SDM mailbox SDM CRAM (fabric)

所以 svc 是一個門鈴(doorbell),不是週邊 — 這也解釋了為什麼它有 methodmemory-region,卻沒有 regSo svc is a doorbell, not a peripheral — which explains why it has method and memory-region but no reg.つまり svc は周辺デバイスではなく呼び鈴である。methodmemory-region を持ちながら reg を持たないのはそのためである。

這一點如何連回那個 bugHow this ties back to the bugこれが不具合とどう結びつくか

Bitstream 遠遠塞不進八個 register,所以 FPGA_CONFIG_WRITEx1x2 裡傳的是一個位址與一個長度,指向 svcbuffer@0。 EL3 的 TF-A 與 SDM 把那個數值當成裸的實體位址解參考 — 兩者皆不在 SMMU 後面,也都不會去查 Linux 的 IOMMU page table。

但因為 /firmware/svc 帶著 iommus = <&smmu 10>, DMA API 交給驅動的是 IOVA。 於是:memcpy 進 buffer 成功(CPU 路徑,只經過 MMU)、SMC 也正常送達, 然後 SDM 去讀一個與 bitstream 實際位置毫無關係的實體位址 → timeout waiting for svc layer buffers

Conduit 本身運作完美;出錯的是穿過它的那個「位址」屬於錯誤的位址空間。
A bitstream is far too large for eight registers, so FPGA_CONFIG_WRITE passes an address and a length in x1/x2, pointing at svcbuffer@0. Both TF-A at EL3 and the SDM dereference that value as a bare physical address — neither is behind the SMMU, and neither consults Linux's IOMMU page tables.

But because /firmware/svc carries iommus = <&smmu 10>, the DMA API hands the driver an IOVA. So: the memcpy into the buffer succeeds (a CPU path, through the MMU only), the SMC is delivered correctly, and then the SDM reads a physical address bearing no relation to where the bitstream actually istimeout waiting for svc layer buffers.

The conduit works perfectly; what is wrong is that the address passing through it belongs to the wrong address space.
ビットストリームはレジスタ 8 本にはとうてい収まらないので、FPGA_CONFIG_WRITEx1/x2アドレスと長さを渡し、svcbuffer@0 を指し示す。EL3 の TF-A と SDM のどちらもその値を素の物理アドレスとして参照する — いずれも SMMU の背後にはおらず、Linux の IOMMU のページテーブルを見ることもない。

ところが /firmware/svciommus = <&smmu 10> を持つため、DMA API はドライバに IOVA を返す。結果として、バッファへの memcpy は成功し(CPU 経路で MMU だけを通る)、SMC も正しく届くが、SDM はビットストリームの実際の位置とは何の関係もない物理アドレスを読みにいく → timeout waiting for svc layer buffers

conduit は完璧に機能している。おかしいのは、そこを通るアドレスが違うアドレス空間に属していることである。

6. altr,smmu_enable_quirk 是什麼?6. What is altr,smmu_enable_quirk?6. altr,smmu_enable_quirk とは何か?

altr,smmu_enable_quirk <-- ?

Altera 自訂的 boolean(有無即代表真假) DT 屬性。 它告訴驅動「這個平台的 SMMU 是啟用的,請走 SMMU-aware 的位址路徑」。 在 Agilex 5 上它不是可選的 — 缺了它 svc 根本不會 probe 成功。 An Altera-specific boolean DT property (its mere presence means true). It tells the driver “the SMMU is enabled on this platform, so take the SMMU-aware address path”. On Agilex 5 it is not optional — without it svc will not probe successfully at all.Altera 固有のブール型 DT プロパティである(存在すること自体が true を意味する)。ドライバに対して「このプラットフォームでは SMMU が有効なので、SMMU を意識したアドレス経路を取れ」と伝える。Agilex 5 では省略可能ではない — これが無いと svc はそもそも probe に成功しない。

兩份 binding 文件都有記載,內容一字不差:Both binding documents record it, word for word:2 つのバインディング文書がどちらも、そのままの文言で記載している:

Documentation/devicetree/bindings/firmware/intel,stratix10-svc.txt:42
Documentation/devicetree/bindings/fpga/intel-stratix10-soc-fpga-mgr.txt:14

  - altr,smmu_enable_quirk: set when SMMU is enabled for the platform.

而在 arch/arm64/boot/dts/intel/socfpga_agilex5.dtsi 裡, 它同時出現在兩個節點上(第 226 與第 230 行): And in arch/arm64/boot/dts/intel/socfpga_agilex5.dtsi it appears on two nodes at once (lines 226 and 230):そして arch/arm64/boot/dts/intel/socfpga_agilex5.dtsi では2 つのノードに同時に現れる(226 行目と 230 行目):

svc {
    compatible = "intel,agilex5-svc";
    iommus     = <&smmu 10>;
    altr,smmu_enable_quirk;                     /* :226 */

    fpga_mgr: fpga-mgr {
        compatible = "intel,agilex5-soc-fpga-mgr";
        altr,smmu_enable_quirk;                 /* :230 */
    };
};

svc 端:drivers/firmware/stratix10-svc.c:3607The svc side: drivers/firmware/stratix10-svc.c:3607svc 側:drivers/firmware/stratix10-svc.c:3607

if (of_device_is_compatible(node, "intel,agilex5-svc")) {
    if (iommu_present(&platform_bus_type) &&
        device_property_read_bool(dev, "altr,smmu_enable_quirk")) {

            controller->is_smmu_enabled     = true;
            controller->sdm_dma_addr_offset = AGILEX5_SDM_DMA_ADDR_OFFSET;  /* 0x8000_0000 */
            controller->domain = iommu_get_dma_domain(dev);
            if (!controller->domain) { ret = -ENODEV; goto err_destroy_pool; }

            iova_cache_get();
            iommu_attach_device(controller->domain, dev);
            init_iova_domain(&controller->carveout.domain, ..., IOMMU_STARTING_ADDR);  /* 0x0        */
            controller->carveout.limit = IOMMU_LIMIT_ADDR - PAGE_SIZE;                 /* 0x2000_0000 */

    } else {
            ret = -ENODEV; goto err_destroy_pool;   /* ← 沒有 non-SMMU 分支 *//* ← no non-SMMU branch *//* ← 非 SMMU の分岐は存在しない */
    }

    /* SMMU 接手轉譯,所以把 SDM 自己那顆 remapper 關掉 *//* the SMMU takes over translation, so disable the SDM's own remapper *//* SMMU がアドレス変換を引き受けるので、SDM 自身のリマッパは無効化する */
    controller->invoke_fn(INTEL_SIP_SMC_SDM_REMAPPER_CONFIG,
                          is_smmu_enabled ? DISABLE_REMAPPER : ENABLE_REMAPPER, ...);
常數Constant定数 Value 用途Purpose用途
AGILEX5_SDM_DMA_ADDR_OFFSET 0x8000_0000 送給 SDM 前加在 IOVA 上的位移The offset added to the IOVA before it is sent to the SDMSDM へ渡す前に IOVA へ加算されるオフセット
IOMMU_STARTING_ADDR 0x0 svc 專屬 IOVA domain 的起點The base of svc's dedicated IOVA domainsvc 専用 IOVA ドメインのベース
IOMMU_LIMIT_ADDR 0x2000_0000 IOVA domain 上限(實際 limit 再減一個 PAGE_SIZE)The top of the IOVA domain (the actual limit is one PAGE_SIZE lower)IOVA ドメインの上限(実際の限界はここから PAGE_SIZE 1 つ分低い)
INTEL_SIP_SMC_FUNCID_SDM_REMAPPER_CONFIG 513 開關 SDM remapper 的 SMC function(需 ATF 支援)The SMC function that enables/disables the SDM remapper (requires ATF support)SDM のリマッパを有効/無効にする SMC 関数(ATF 側の対応が必要)

fpga-mgr 端:drivers/fpga/stratix10-soc.cThe fpga-mgr side: drivers/fpga/stratix10-soc.cfpga-mgr 側:drivers/fpga/stratix10-soc.c

同一個屬性在子節點上決定 bitstream buffer 要不要做 DMA mapping:The same property on the child node decides whether the bitstream buffer is DMA-mapped:子ノード側の同じプロパティが、ビットストリーム用バッファを DMA マップするかどうかを決める:

/* :459 */
priv->is_smmu_enabled = device_property_read_bool(dev, "altr,smmu_enable_quirk");

/* :302 — 每個 buffer 送出前 *//* :302 — before each buffer is submitted *//* :302 — 各バッファを投入する直前 */
if (priv->is_smmu_enabled)
        priv->svc_bufs[i].dma_addr = dma_map_single(dev, svc_buf, SVC_BUF_SIZE, DMA_TO_DEVICE);

/* :139 — buffer 回收時 *//* :139 — when the buffer is reclaimed *//* :139 — バッファを回収するとき */
if (priv->is_smmu_enabled == true)
        dma_unmap_single(priv->client.dev, priv->svc_bufs[i].dma_addr, SVC_BUF_SIZE, DMA_TO_DEVICE);

然後在 svc 送出訊息時補上位移(stratix10-svc.c:3253):The offset is then added when svc sends the message (stratix10-svc.c:3253):svc がメッセージを送る際に、このオフセットが加算される(stratix10-svc.c:3253):

if (p_msg->command == COMMAND_RECONFIG_DATA_SUBMIT && chan->ctrl->is_smmu_enabled)
        p_data->paddr += chan->ctrl->sdm_dma_addr_offset;   /* IOVA + 0x8000_0000 → SDM */

結構體註解(:271)寫得很直白: "dma addr offset to append to the IOVA sent to SDM"The struct comment (:271) says it plainly: "dma addr offset to append to the IOVA sent to SDM".構造体のコメント(:271)が端的に述べている:"dma addr offset to append to the IOVA sent to SDM"

結論:SMMU + svc 是「刻意設計」要能運作的組合,不是天生壞掉的搭配。 設計意圖是:Linux 用 SMMU 管 SDM 的 DRAM 存取(StreamID 10), 把 SDM 自己的 remapper 關掉,並在傳址時補上 0x8000_0000 的固定位移。 這條路徑需要 kernel、DTB、ATF 三者版本一致才會成立。 Conclusion: SMMU + svc is a combination deliberately designed to work, not an inherently broken pairing. The design intent is that Linux governs the SDM's DRAM access through the SMMU (StreamID 10), disables the SDM's own remapper, and adds a fixed 0x8000_0000 offset when passing addresses. This path only holds together when kernel, DTB and ATF are all at matching versions.結論:SMMU と svc の組み合わせは、意図的に動くよう設計されたものであり、本質的に壊れた取り合わせではない。設計意図は、Linux が SMMU(StreamID 10)を通じて SDM の DRAM アクセスを管理し、SDM 自身のリマッパを無効化し、アドレスを渡す際に固定の 0x8000_0000 オフセットを加える、というものである。この経路が成立するのはカーネル・DTB・ATF のバージョンがすべて揃っているときだけである。

7. 可以只移除 svciommus 嗎?7. Can you remove just svc's iommus?7. svciommus だけを外せるか?

can i remove iommus only for svc? / remove iommus for svc would not affect other device?

在 Agilex 5 上不行。 intel,agilex5-svc 的 probe 路徑沒有 non-SMMU 分支, 移除後 svc 會直接 -ENODEV 失敗。 Not on Agilex 5. The intel,agilex5-svc probe path has no non-SMMU branch, so with the property removed svc simply fails with -ENODEV.Agilex 5 では不可能である。intel,agilex5-svc の probe 経路には非 SMMU の分岐が存在しないため、プロパティを外すと svc は単に -ENODEV で失敗する。

兩種移除方式都會失敗Both ways of removing it fail外し方はどちらも失敗する

你做的修改The change you make加える変更 程式碼走到哪裡Where the code ends upコードが辿り着く先 結果Result結果
只移除 iommus,保留 quirkRemove only iommus, keep the quirkiommus だけを外し、quirk は残す iommu_present() 仍為真、quirk 仍為真 → 進入 SMMU 分支, 但 iommu_get_dma_domain(dev) 回傳 NULLiommu_present() is still true and the quirk is still true → it enters the SMMU branch, but iommu_get_dma_domain(dev) returns NULLiommu_present() は依然 true、quirk も true → SMMU 分岐に入るが、iommu_get_dma_domain(dev)NULL を返す -ENODEV
兩個都移除Remove both両方とも外す 條件不成立 → 走 elseThe condition is false → it falls to the else条件が false → else に落ちる -ENODEV
svc probe 失敗的連帶損失: fpga-mgrhwmonfcs-config 都是 svc子節點, 父節點沒 probe 成功就不會被建立。 也就是整個 FPGA 重組態、RSU、溫度電壓監測、FCS 全部一起失效 — 代價遠大於原本那一個 bug。 The collateral damage when svc fails to probe: fpga-mgr, hwmon and fcs-config are all child nodes of svc, and they are never created if the parent does not probe. That means FPGA reconfiguration, RSU, temperature/voltage monitoring and FCS all stop working together — a far higher price than the original bug.svc の probe が失敗したときの巻き添え:fpga-mgrhwmonfcs-config はいずれも svc子ノードであり、親が probe しなければ生成すらされない。つまり FPGA 再構成、RSU、温度/電圧モニタ、FCS がまとめて動かなくなる — 元の不具合よりはるかに高い代償である。
那為什麼舊平台可以? 整個 quirk 區塊被 of_device_is_compatible(node, "intel,agilex5-svc") 包住。 intel,stratix10-svcintel,agilex-svc 根本不會進入這個分支,所以在那些 SoC 上移除 iommus 是可行的。 這個限制是 Agilex 5 專屬的。 So why is it fine on older platforms? The whole quirk block is wrapped in of_device_is_compatible(node, "intel,agilex5-svc"). intel,stratix10-svc and intel,agilex-svc never enter this branch, so removing iommus is viable on those SoCs. This restriction is specific to Agilex 5.では、なぜ旧プラットフォームでは問題ないのか?この quirk のブロック全体が of_device_is_compatible(node, "intel,agilex5-svc") で囲まれている。intel,stratix10-svcintel,agilex-svcこの分岐に入らないので、それらの SoC では iommus を外す手が使える。この制約は Agilex 5 に固有である。

順帶訂正:StreamID 10 有真實流量An incidental correction: StreamID 10 does carry real traffic付随する訂正:StreamID 10 は実際のトラフィックを運んでいる

本文早期版本推測「firmware:svc 沒有 reg、不 master 任何東西, 所以 SID 10 上大概沒有真實流量」。這是錯的。 INTEL_SIP_SMC_SDM_REMAPPER_CONFIG 的存在本身就證明了: SDM 有一條會被 remapper 或 SMMU 轉譯的 DRAM 存取路徑, 而那條路徑對應的就是 StreamID 10firmware:svc 是 Linux 端代為持有並設定這個 StreamID 的 proxy deviceAn earlier version of this document speculated that “firmware:svc has no reg and masters nothing, so SID 10 probably carries no real traffic”. That is wrong. The very existence of INTEL_SIP_SMC_SDM_REMAPPER_CONFIG proves it: the SDM has a DRAM access path that is translated by either the remapper or the SMMU, and that path corresponds to StreamID 10. firmware:svc is the proxy device that holds and configures this StreamID on Linux's behalf.本書の以前の版では「firmware:svcreg を持たず何もマスタしないので、SID 10 には実トラフィックは無いだろう」と推測していた。これは誤りである。INTEL_SIP_SMC_SDM_REMAPPER_CONFIG が存在すること自体がその証拠であり、SDM にはリマッパまたは SMMU のいずれかでアドレス変換される DRAM アクセス経路があって、その経路が StreamID 10 に対応する。firmware:svcLinux に代わってこの StreamID を保持し設定するプロキシデバイスである。

iommus 逐節點生效」這件事仍然成立iommus takes effect per node” is still trueiommus はノード単位で効く」は依然として正しい

第 7 節結論改變的是「該不該對 svc 動手」, 而不是 iommus 的作用範圍。 of_iommu_configure() 依然只讀該節點自己的 iommus, 所以下列理解不變: What changed in section 7 is whether you should touch svc, not the scope of iommus. of_iommu_configure() still reads only that node's own iommus, so the following remains correct:第 7 節で変わったのは svc に手を入れてよいかどうかであって、iommus の作用範囲ではない。of_iommu_configure() は今もそのノード自身の iommus しか読まないので、以下は正しいままである:

節點Nodeノード 若移除 svc 的 iommusIf svc's iommus is removedsvc の iommus を外した場合 說明Notes備考
sdhci-cdns / USB / EMAC 完全不受影響Entirely unaffectedまったく影響を受けない 各自保有 iommus、domain 與 STEEach keeps its own iommus, domain and STEそれぞれが自分の iommus、ドメイン、STE を保持する
/firmware/svc probe 失敗Probe failsprobe が失敗する 並非「安靜地退回 dma-direct」,而是驅動主動拒絕上線Not “quietly falling back to dma-direct” — the driver actively refuses to come up「黙って dma-direct にフォールバックする」のではなく、ドライバが積極的に起動を拒む
所以 iommu.passthrough=1 會弄壞 sdhci-cdns 的原因依然如第 3 節所述 — 它翻轉的是全域的 default domain type。 「逐節點」的判斷正確;錯的是把 svc 當成可以安全下手的那個節點。 So the reason iommu.passthrough=1 breaks sdhci-cdns is still exactly as described in section 3 — it flips the global default domain type. The “per node” reasoning was right; what was wrong was treating svc as a node you can safely touch.したがって iommu.passthrough=1sdhci-cdns を壊す理由は第 3 節で述べたとおりのままである — グローバルな既定ドメイン種別を切り替えてしまうからだ。「ノード単位」という理屈は正しかった。誤っていたのは、svc を安全に触れるノードだと見なした点である。

8. 那實際上該檢查什麼?8. So what should you actually check?8. では、実際に何を確認すべきか?

svc 在你的板子上 probe 成功的(否則 fpga-mgr 不會存在、也就印不出那行 timeout),所以 SMMU 路徑本身已經起來了。 問題出在下游的 buffer/位址處理,而最可能的原因是版本不一致svc does probe successfully on your board (otherwise fpga-mgr would not exist and could not print that timeout line), so the SMMU path itself is up. The problem lies downstream in buffer/address handling, and the most likely cause is a version mismatch.このボードでは svc の probe は成功している(そうでなければ fpga-mgr が存在せず、あのタイムアウト行も出せない)ので、SMMU 経路そのものは立ち上がっている。問題はその先のバッファ/アドレスの扱いにあり、最も疑わしいのはバージョンの不一致である。

版本落差The version gapバージョンの隔たり

項目Item項目 版本Versionバージョン 來源Source出典
失效的執行環境The failing runtime environment失敗している実行環境 6.12.11 板子上的 uname -runame -r on the boardボード上の uname -r
本地含完整 quirk 支援的樹The local tree with full quirk supportquirk に完全対応したローカルのツリー 6.12.43 /home/vivado/kernel/linux-socfpga-6.12
tag QPDS25.3.1_REL_FCS_FIX, refdes 25.3.1

最可能的單一根因:quirk 只加在其中一個節點The single most likely root cause: the quirk added to only one node最有力の根本原因:quirk が片方のノードにしか入っていない

quirk 在 svc 上、卻漏在 fpga-mgr 上時:
When the quirk is on svc but missing from fpga-mgr:
quirk が svc にはあるのに fpga-mgr には無い場合:

在板子上要跑的檢查Checks to run on the boardボード上で実行する確認

uname -r

# quirk 必須「兩個節點都有」# the quirk must be present on BOTH nodes# quirk は両方のノードに存在しなければならない
ls /proc/device-tree/firmware/svc/altr,smmu_enable_quirk
ls /proc/device-tree/firmware/svc/fpga-mgr/altr,smmu_enable_quirk

# remapper 交握是否成功# did the remapper handshake succeed?# リマッパのハンドシェイクは成功したか?
dmesg | grep -i 'remapper\|Service Layer'
怎麼讀這些輸出:How to read the output:出力の読み方:

建議的修正順序Suggested order for the fix修正の推奨手順

順序Order順番 動作Actionやること 理由Rationale理由
1 確認執行中的 DTB 兩個節點都有 quirkConfirm the running DTB has the quirk on both nodes実際に動いている DTB で quirk が両方のノードにあることを確認する 零風險,且可能直接就是答案Zero risk, and it may well be the answer on its ownリスクはゼロで、これだけで解決する可能性も十分ある
2 把 kernel、DTB、ATF 全部對齊到同一個 release (本機這棵 25.3.1 樹)Align kernel, DTB and ATF to the same release (the local 25.3.1 tree)カーネル・DTB・ATF を同一リリース(ローカルの 25.3.1 ツリー)に揃える IOVA 視窗、0x8000_0000 位移、funcid 513 三者是同一份協定,混版就會失效The IOVA window, the 0x8000_0000 offset and funcid 513 are one single protocol; mixing versions breaks itIOVA の窓、0x8000_0000 のオフセット、funcid 513 はひとつのプロトコルである。バージョンを混ぜると成立しない
3 仍失敗才考慮改驅動Only consider patching the driver if it still failsそれでも直らないときに初めてドライバへのパッチを検討する 在確認協定版本一致之前改驅動,只會掩蓋真正的不一致Patching the driver before confirming the protocol versions match merely hides the real inconsistencyプロトコルのバージョン一致を確かめる前にドライバへ手を入れても、本当の不整合を覆い隠すだけである
不要再走的兩條路: iommu.passthrough=1(全域,會弄壞 sdhci-cdns) 與移除 svciommus(Agilex 5 上會讓 svc 完全不上線)。 兩者都不是這個平台的正解。 Two roads not to go down again: iommu.passthrough=1 (global, and it breaks sdhci-cdns) and removing svc's iommus (on Agilex 5 it stops svc coming up at all). Neither is the right answer for this platform.二度と踏み込むべきでない 2 つの道:iommu.passthrough=1(グローバルに効き、sdhci-cdns を壊す)と、svciommus を外すこと(Agilex 5 では svc がそもそも立ち上がらなくなる)。どちらもこのプラットフォームでは正解ではない。