diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 68417ee..250e363 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -192,6 +192,7 @@ Blanton_TTL_Script/ │ # ↑ 三支都要 chmod +x 才能跑(見 Key Constraints) └── LTC2980_Margin_Script/ # 電壓 margin 子專案(另有獨立 repo) ├── margin.sh # margin_init/status/set/apply_profile/save + # # v2.7.0:margin_save all / margin_save blanton ├── settings/*.conf # 一個 .conf = 一顆 LTC2980(CB + SWB0/1 × CONN13~16) ├── profiles/*.conf # 16-ch 批次組合(comboA/B、high3/5、low3/5、normal、off) ├── script/*_all.sh # 跨 9 顆 LTC2980 的批次 status / apply / save @@ -251,6 +252,21 @@ Channel 定址:`ch / 8` → `CHIPS[]` index,`ch % 8` → LTC2977 PMBus PAGE > 同一顆 LTC2980 的兩個位址**相差 2**(7-bit,由規格書 8-bit 配對除以 2 而來),不是 1。 > 兩張板共用一條通道,所以同通道上的位址必須互斥 —— 上表兩組(`0x5C/0x5E` 與 `0x62/0x64`)不重疊。 +**同一批 LTC2977 也掛在原生 i2c bus 上**(2026-08-27 上機驗證):Blanton 的 SONiC 把 CB FPGA F3 +的這四條 I2C 通道同時註冊成 kernel i2c adapter,因此除了 `cb_pmbus_*` → pcimem 這條路, +還可以用 `i2cset -f -y ` 直接打到同一顆晶片: + +| FPGA F3 通道 | Linux bus | CB FPGA 路徑 | 原生 i2c 路徑 | +|---|---|---|---| +| Ch6 | 13 | `cb_pmbus_write 6 …` | `i2cset -f -y 13 …` | +| Ch7 | 14 | `cb_pmbus_write 7 …` | `i2cset -f -y 14 …` | +| Ch8 | 15 | `cb_pmbus_write 8 …` | `i2cset -f -y 15 …` | +| Ch9 | 16 | `cb_pmbus_write 9 …` | `i2cset -f -y 16 …` | + +`margin.sh` 的 `margin_save blanton` 走原生路徑(`MARGIN_BLANTON_STORE` 表), +其餘功能仍走 `TRANSPORT="swb"` 的 FPGA 路徑。兩條路到的是同一顆 LTC2977, +**不要同時用**(同一條匯流排上兩個 master 語意的存取)。 + **全通道 net / 電壓對照:`docs/LTC2980_channel_map.csv`**(9 個 `.conf` × 16ch = 144 列, 欄位 `Board,CONN,Ch,NetName,Vnom`)。查「某個 net 在哪片哪個 channel」比翻 9 個 `.conf` 快。 CSV 是產出物,不是正本 —— 改完 `.conf` 用 `./tools/gen_channel_map.sh` 重產,別手改 CSV。 @@ -330,6 +346,7 @@ PROFILE_CHANNELS=( "0:high:8" "1:low:8" ... ) # "channel:operation:change_perc | **溫度** | `temp_cb` / `temp_icb` / `temp_all` | TMP75(12-bit 左靠齊 ×0.0625)、TMP432(含 RANGE bit 的 −64 偏移、remote1/2) | | **電源資料** | `pwr_data` / `pwr_data_pdb` / `pwr_pdb_id` | SWB VRM 全軌 Vin/Vout/Iout/Temp 對齊表;MP29816 解析度**執行期從 `MFR_VOUT_SCALE_LOOP` 讀**,不寫死 | | **電壓 Margin** | `margin_init/status/set/apply_profile/save` + `*_all.sh` | 9 顆 LTC2980(CB CONN13、SWB0/1 CONN13~16)批次 high/low margin 與狀態掃描。v2.6.0 起 SWB 路徑真正接上共用 cb_i2c 後端,並有 `margin_swb_info/probe/scan/reset/sem` 除錯包裝 | +| **Margin 寫 NVM** | `margin_save` / `margin_save all` / `margin_save blanton` | ⚠️ 永久寫入。`0x15` 送 PMBus **send-byte**(不帶 data byte)。`all` = 依 `settings/` 走 9 顆、跑完還原原本載入的板子;`blanton` = 本平台捷徑,18 顆全走原生 i2c bus(`MARGIN_BLANTON_STORE` 表),不需 `margin_init`。每筆之間 `MARGIN_STORE_SETTLE`(0.5s),工具**不 poll busy bit** | | **管理網路 ping** | `mgmt_ping_monitor.sh {start\|stop\|status\|fg\|tail\|clear\|summary}` | 一輪 = 10G leg + 1G leg,各自 `ip address/route replace` 後 `ping -I ` 打自己的對端;兩張卡都保持 up。每 leg 記 `ip -s link show` 與該卡的 TX/RX packet delta,另出一行可 grep 的 `RESULT` | | **BMC 監控** | `bmc_monitor.sh {start\|stop\|status\|fg\|tail\|clear}` | 由 host 端 `bmc-manager run` 週期取樣 `free -m`,另加一組 **I2C 寫入/讀回圖樣測試**(bus 1、addr 0x41、offset 0x00C0,寫 `55AA55AA` 讀回、再寫 `AA55AA55` 讀回)。B 啟動、C 停止並 `cat log/bmc_poll.log` | | **BMC DDR 壓力** | `bmc_monitor_ddr.sh` | ⚠️ **已停用** —— B/C 內呼叫處已註解,改由 `bgctl run bmc-manager run memtester` 取代。檔案保留未刪 | @@ -435,6 +452,8 @@ pwr_data 只吃 Sr;只有純暫存器裝置兩種都行。 7. **`margin_save`(`STORE_USER_ALL`)會永久寫進 NVM**,斷電保留。測試流程中**絕不執行**, 以免覆蓋客戶出廠 config。`margin.sh` 的 auto-enable 只改 RAM(`ON_OFF_CONFIG`),斷電復原。 + `margin_save all` / `margin_save blanton`(v2.7.0)一次對 9 顆 LTC2980(18 個 LTC2977) + 下同一道命令,風險同性質但範圍是全機;命令本身是 PMBus send-byte(`0x15`,不帶 data byte)。 8. **操作硬體電壓有損壞 DUT 的風險**:套 profile 前先確認該軌 OV/UV limit 與 servo DAC 注入電阻 有 populate(本板部分 margin 電阻標 PROTO,沒 populate 的軌電壓不會動)。 9. **`ARB_LOST` 不等於裝置存在**:`vi2c_scan` 只看 `RX_ACK`,仲裁失敗會被誤報成「有裝置」。 @@ -483,7 +502,7 @@ pwr_data | **客戶機密文件** | `docs/` 內 FPGA 規格(docx/xlsx/md)屬客戶 NDA 範圍;schematic 原始檔(`*.DSN`)一律 gitignore,不進 repo | | **Remote 限制** | 只推私有 remote:`nas`(`git.et-wen.com:51222`)+ `gitea`(`etgit.et-wen.com`)。**不設 GitHub `origin`** | | **測試 log** | `logs/*.log` 含 DUT 序號、MAC、韌體版本等可識別資訊 → gitignore,只保留目錄結構(`.gitkeep`) | -| **破壞性硬體指令** | `margin_save` / `STORE_USER_ALL` 為永久 NVM 寫入,工具預設不呼叫;批次腳本 `margin_save_all.sh` 在 README 與腳本頂端都有警語 | +| **破壞性硬體指令** | `margin_save` / `margin_save all` / `margin_save blanton` / `STORE_USER_ALL` 為永久 NVM 寫入,工具預設不呼叫;`margin_save all` 與批次腳本 `margin_save_all.sh` 在 README 與程式頂端都有警語 | | **root 權限** | 全流程在 `root@sonic:~#` 下執行(pcimem / i2c 需要);腳本不留任何 `chmod 777` 或放寬權限的動作 | | **For_AI/** | AI 協作素材(截圖、草稿筆記)整個資料夾 gitignore,避免不小心把客戶圖面帶進 repo | @@ -756,6 +775,13 @@ margin status、全部 VRM 軌的 Vin/Vout/Iout/Temp、CB + ICB 溫感讀值, PktSize=324 PortList=1-259,270-565` 這組指令(含 `port all lb=mac` + `l2 learn off` 前置), 目前只能手貼。它與 `blanton_traffic_linespeed` 是兩條互斥的打流路線(都會動 loopback 與 L2 學習), 要腳本化的話得先決定兩者怎麼共存,不能同時跑。 +- **SWB 的 LTC2977 有兩條路可以到,目前工具兩條都在用**:`cb_pmbus_*`(CB FPGA F3 → pcimem) + 是 `margin_init` / `margin_status` / `margin_set` 走的路;原生 i2c bus(Ch+7 = bus 13/14/15/16) + 是 `margin_save blanton` 走的路。後者短很多 —— 不需要通道初始化、不需要 pcimem, + 單一 `i2cset` 就到。若原生 bus 在這平台夠穩,整個 `TRANSPORT="swb"` 層其實可以退成 + 「bus 號不同的 i2c 路徑」,`_swb_*`、probe、semaphore、prescale 那整套都能拿掉。 + 要動之前得先確認:讀取(`margin_status` 的 LINEAR16 word read)是否也同樣可靠, + 以及 kernel driver 有沒有搶著存取(`margin_save blanton` 帶 `-f` 就是為了繞過這件事)。 - **`settings/` 裡 SWB0 與 SWB1 是兩份相同的資料**:8 個 `.conf` 中,SWB1 的四個除了 `CHIPS[]` 的 bus 與 `CB_I2C_CH` 之外,net name 與 `VNOM` 與 SWB0 逐欄相同(見 `docs/LTC2980_channel_map.csv`)。 改一邊忘了改另一邊不會有任何警告。可考慮改成「共用 net 定義 + 各自的 transport 覆寫」兩層檔案。 diff --git a/CLAUDE.md b/CLAUDE.md index 4a216ca..3154138 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -63,6 +63,14 @@ temp_all # CB + ICB 溫感 pwr_data # SWB VRM 全軌 margin_init Blanton_CB_CONN13 && margin_status +# ── 電壓 margin 寫 NVM(⚠️ 永久,測試中絕不執行)───── +margin_save # 只寫當前 margin_init 載入的那顆(2 個 LTC2977) +margin_save all # settings/ 全部 9 顆;跑完自動切回原本載入的那顆 +margin_save blanton # Blanton SONiC 捷徑:18 顆全走原生 i2c,不用 margin_init +# 0x15 是 send-byte,不帶 data byte:i2cset -f -y 0x15 +# bus = FPGA F3 通道 + 7 → Ch6=13, Ch7=14, Ch8=15, Ch9=16(CB 本來就是 bus 4) +# ⚠️ 沒裝滿的機器:改 margin.sh 頂端的 MARGIN_BLANTON_STORE,把沒有的板子註解掉 + # ── SWB loopback 流量(bcmcmd,unit 0/1)───────────── # 不帶 -u 就是預設 TL_UNITS="0 1",兩塊 switch board 都做(TTL 三支腳本即如此) blanton_traffic_linespeed ps # 對照線的 link/speed @@ -178,6 +186,11 @@ Tera Term 連 COM port (115200-8-N-1) - ⚠️ **I2C 讀一律 Repeated START**(不是 STOP + START),否則 PMBus/SMBus 裝置(VRM、EFUSE)不理。 - ⚠️ **`margin_save` / `STORE_USER_ALL` 會永久寫 NVM**,斷電保留 → **測試流程中絕不執行**, 以免覆蓋客戶出廠 config。`margin.sh` 的 auto-enable(`ON_OFF_CONFIG=0x1a`)只改 RAM,斷電復原。 + v2.7.0 新增的 **`margin_save all` / `margin_save blanton` 一次寫 18 個 LTC2977**, + 同一個警告放大 9 倍;另外 `0x15` 現在送 send-byte,不再帶多餘的 `0x00` data byte。 +- ⚠️ **SWB 的 LTC2977 有兩條路可以到**:`cb_pmbus_*`(CB FPGA F3 Ch6/7/8/9 → pcimem)與 + 原生 i2c bus(`i2cset -f -y 13/14/15/16`,Ch+7 = bus)。`margin_save blanton` 走後者, + 其餘功能走前者。同一顆晶片,**不要同時用兩條路**。 - ⚠️ **改電壓會弄壞 DUT**:套 profile 前確認該軌 OV/UV limit,且 servo DAC 注入電阻有 populate (本板部分 margin 電阻標 PROTO,沒 populate 的軌電壓不會動,不是腳本壞掉)。 - ⚠️ **`ARB_LOST` ≠ 有裝置**:`vi2c_scan` 只看 `RX_ACK`,仲裁失敗會被誤報成裝置存在。 diff --git a/docs/release-notes/v1.0.11.md b/docs/release-notes/v1.0.11.md new file mode 100644 index 0000000..58e5666 --- /dev/null +++ b/docs/release-notes/v1.0.11.md @@ -0,0 +1,56 @@ +# v1.0.11 — Saving the margin settings to NVM is now one command, and the command is correct + +## ✨ New features + +**`margin_save blanton` — all 18 LTC2977 in one go** +* On this platform the CB FPGA's I2C channels are also exposed as ordinary Linux i2c buses, so every margin controller on the box — CB and both switch boards — can be reached with plain `i2cset`. `margin_save blanton` walks all 18 of them from one flat list: no `margin_init`, no FPGA channel setup, no `pcimem`. +* The channel-to-bus mapping it relies on (F3 Ch6 → bus 13, Ch7 → 14, Ch8 → 15, Ch9 → 16; CB is bus 4 as before) is now written down in `ARCHITECTURE.md` and the margin README, not just known at the bench. +* **A partly-populated DUT is a normal build.** Comment out the lines you do not have in `MARGIN_BLANTON_STORE` at the top of `margin.sh` rather than letting the tool talk to boards that are not there. +* Missing bus and unresponsive chip are reported as two different failures. `/dev/i2c-16 does not exist` means the FPGA's i2c adapters did not enumerate; `i2cset failed (NACK/busy)` means the board is absent or the address is wrong. Chasing the second when you have the first wastes an afternoon. + +**`margin_save all` — every board in `settings/`** +* Runs `margin_init` + `margin_save` across all nine boards, then puts back whichever board you had loaded, so a following `margin_status` still reports the board you were looking at. +* It does not stop at the first failure: a half-saved set is harder to reason about than a fully-attempted one. The summary names the boards that failed. + +Both print a per-chip line and a `N saved, M failed` tally, and both return a non-zero exit code when anything failed. + +## 🐛 Bug fixes + +**A failed NVM write still reported success** +* `margin_save` discarded the result of every write, so a NACK printed `Change Saved` exactly like a successful store. For the one operation in this tool that is permanent, that is the worst place to stay quiet. Each store is now checked and named if it fails. + +**`STORE_USER_ALL` was sent with a data byte it should not have** +* The command went out as `0x15` followed by a dummy `0x00` — an SMBus write-byte, where `STORE_USER_ALL` is a send-byte. The LTC2977 tolerated it, but tolerance is not correctness. It is now `i2cset ... 0x15 c` on the native path and a no-data `cb_pmbus_write` on the FPGA path. + +## 📦 Downloads + +| File | Contents | +|---|---| +| `Script_ABC_Blanton_V1.0.11.zip` | The full Tera Term working directory, including `Blanton_Script/` to copy onto the DUT | + +**After copying to the DUT:** + +```bash +chmod +x ~/Blanton_Script/*.sh # see below +grep -rlU $'\r' ~/Blanton_Script # expect no output +``` + +`mgmt_ping_monitor.sh` and `port_prbs_monitor.sh` launch their workers through `bash`, so those two run without the execute bit. `bmc_monitor.sh` and `usb_target.sh` still need it, and neither git (mode 100644) nor a Windows/USB copy carries it. Without the `chmod`, `start` fails with `Permission denied` and the later `cat` finds nothing: **the section ends up empty and nothing reports an error.** + +## ⚠️ Before you run + +* **`margin_save` in any form writes NVM permanently.** A power cycle does not undo it. `margin_save all` and `margin_save blanton` do it to all 18 controllers at once. Run `margin_status_all.sh` first and never call any of them during a test run — the macros do not, and should not be made to. +* **The 18 raw commands were verified on the DUT; the wrapper was not.** `margin_save blanton` issues exactly the sequence that was run by hand at the bench, and the packaging was tested against stubbed hardware, but the function itself has not been run on a DUT yet. Watch the per-chip lines the first time. +* **Declare the switch population.** `SWB_UNIT0` / `SWB_UNIT1` in `config.ttl` say which switch units this DUT has; traffic and the readiness gate both follow them. +* **Set `FAN_SPEED`.** It is applied at the start of every run. +* **Management connectivity is in use, not preserved.** Both management NICs are up and pinging — drive the run from the serial console. +* **PRBS is still not wired into the macros.** Run `port_prbs_monitor.sh` by hand if you want it; the calls in A/B/C remain commented out. +* **Two settings persist to `config_db.json`** and survive a reboot: LLDP is left disabled and the 100G uplinks are left configured. Restore them before the DUT moves on. + +## 🔗 Links + +* [ARCHITECTURE.md](https://etgit.et-wen.com/etwen/Blanton_TTL_Script/src/branch/main/ARCHITECTURE.md) — test flow, data models, constraints +* [CLAUDE.md](https://etgit.et-wen.com/etwen/Blanton_TTL_Script/src/branch/main/CLAUDE.md) — commands and the bench gotchas +* [LTC2980_Margin_Script/README.md](https://etgit.et-wen.com/etwen/Blanton_TTL_Script/src/branch/main/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/README.md) — the three `margin_save` variants and what each one sends + +**Full changelog:** [V1.0.10...V1.0.11](https://etgit.et-wen.com/etwen/Blanton_TTL_Script/compare/V1.0.10...V1.0.11) diff --git a/src/Script_ABC_Blanton/1_Blanton_Script_A.ttl b/src/Script_ABC_Blanton/1_Blanton_Script_A.ttl index 55c7280..271fb74 100644 --- a/src/Script_ABC_Blanton/1_Blanton_Script_A.ttl +++ b/src/Script_ABC_Blanton/1_Blanton_Script_A.ttl @@ -1,7 +1,7 @@ ; ============================================================================= ; Script A for Blanton -; Version : V1.0.10 -; Date : 2026-08-27 +; Version : V1.0.11 +; Date : 2026-08-28 ; Author : ETWen ; ============================================================================= ; Version History: @@ -74,6 +74,26 @@ ; tools/100G_PRBS.txt Bench command references, kept for hand-run debug ; tools/TR518.txt TR518 = built-in packet test (swutil / bcmcmd tr 518) ; tools/fan_ctrl.txt MAX31790 rebind + fan-speed-control.sh +; V1.0.11 2026-08-28 LTC2980_Margin_Script/margin.sh v2.7.0 - margin_save fixes + two new subcommands +; STORE_USER_ALL (0x15) is now a PMBus send-byte, not +; 0x15 followed by a dummy 0x00 data byte. The LTC2977 +; tolerated the old form, but it was the wrong protocol +; i2c: i2cset .. 0x15 c swb: cb_pmbus_write 0x15 +; + margin_save all - every board in settings/ (9 boards, +; 18 chips), then re-init the one loaded beforehand +; + margin_save blanton - Blanton SONiC shortcut: all 18 +; LTC2977 straight over the native i2c buses - no +; margin_init, no FPGA channel setup, no pcimem +; F3 Ch6->bus 13, Ch7->14, Ch8->15, Ch9->16 +; board list = MARGIN_BLANTON_STORE at the top of margin.sh +; The store result is now checked - a NACK used to still +; print "Change Saved" +; MARGIN_STORE_SETTLE (0.5s) between stores; nothing in this +; tool polls the part's busy bit +; LTC2980_Margin_Script/README.md What each margin_save variant sends, and the +; FPGA-channel -> i2c-bus map +; LTC2980_Margin_Script/Ref/*.md 0x15 trace note corrected to send-byte +; LTC2980_Margin_Script/script/margin_save_all.sh Point at margin_save all; keep it for subsets ; ============================================================================= include "config.ttl" diff --git a/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/README.md b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/README.md index 5b64157..74750c1 100644 --- a/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/README.md +++ b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/README.md @@ -14,6 +14,8 @@ | `margin_operation ` | 只切 OPERATION register | | `margin_apply_profile ` | 批次套用 profile(套用在當前載入的 LTC2980) | | `margin_save` | 寫入 NVM(當前 LTC2980 的兩個 LTC2977 都寫) | +| `margin_save all` | 對 `settings/` 底下**全部** LTC2980 寫入 NVM,結束後回到原本載入的那顆 | +| `margin_save blanton` | **Blanton SONiC 專用**:18 顆 LTC2977 全部走原生 i2c bus 寫入,不需要 `margin_init` | | `margin_debug [on\|off]` | 開關 debug 模式(不帶參數則 toggle) | | `margin_log [on\|off]` | 開關 log 記錄(不帶參數則 toggle,預設開啟) | @@ -79,7 +81,9 @@ margin_init Blanton_SWB1_CONN16 margin_apply_profile profiles/comboA.conf # 儲存到 NVM(斷電後保留) -margin_save +margin_save # 只寫當前載入的那顆 +margin_save all # settings/ 底下 9 顆全部寫,最後自動切回原本那顆 +margin_save blanton # Blanton SONiC 專用捷徑,18 顆一次寫完(見下) ``` ## 一次掃所有 LTC2980 @@ -131,16 +135,87 @@ PROFILES=( ## 一次把所有 LTC2980 寫入 NVM -`script/margin_save_all.sh` 對 `BOARDS` 列出的每顆 LTC2980 跑 `margin_save`。 - > ⚠️ `margin_save` 會把當前 margin / OV / UV 設定**永久寫入 NVM**, > 斷電後保留。執行前先用 `margin_status_all.sh` 確認狀態正確。 +**全部 9 顆**直接用內建的: + +```bash +margin_save all +``` + +依 `settings/*.conf` 的檔名順序跑,中途某顆失敗**不會停**(半套完成的狀態比全部試完更難查), +最後印出「幾顆成功 / 哪幾顆失敗」的總結,並把 `margin_init` 切回你呼叫前載入的那顆。 + +**只寫其中幾顆**才需要 `script/margin_save_all.sh`,編 script 頂端的 `BOARDS` 陣列: + ```bash source script/margin_save_all.sh ``` -要改寫哪幾顆,編 script 頂端的 `BOARDS` 陣列即可(同前述)。 +### 送出去的是什麼 + +`margin_save` 對每顆 LTC2977 送一次 `STORE_USER_ALL`(PMBus command `0x15`), +**不分 page**(這是整顆晶片的命令),也**不帶 data byte** —— 它是 SMBus send-byte: + +```bash +i2cset -y 4 0x5C 0x15 c # CB CONN13(原生 bus 4) +cb_pmbus_write 8 0x5C 0x15 # SWB0 CONN13(CB FPGA F3 Ch8) +``` + +> v2.7.0 之前送的是 `0x15 0x00`(write-byte)。LTC2977 在 CB 上吃得下去,但那是零件寬容, +> 不是規範。同時 v2.7.0 起會檢查回傳值 —— 以前 NACK 了還是印 `Change Saved`。 + +每顆之間會 `sleep $MARGIN_STORE_SETTLE`(預設 0.5 秒)。這不是量測值,是保守的保護: +NVM 寫入需要時間,而這支工具**沒有**去 poll 零件的 busy bit。`margin_save all` 連續送 18 次, +這個間隔就是唯一的緩衝。要關掉設成空字串即可。 + +## `margin_save blanton` — Blanton SONiC 專用 + +Blanton 這台把 CB FPGA F3 的 I2C 通道**同時掛成了原生 Linux i2c adapter**, +所以 SWB 上的 LTC2977 不必走 `cb_pmbus_*` / pcimem,用 `i2cset` 直接打得到: + +| FPGA F3 通道 | Linux bus | 板 / 接頭 | +|---|---|---| +| Ch6 | 13 | SWB0 CONN14 / CONN16 | +| Ch8 | 15 | SWB0 CONN13 / CONN15 | +| Ch7 | 14 | SWB1 CONN14 / CONN16 | +| Ch9 | 16 | SWB1 CONN13 / CONN15 | +| —(原生) | 4 | CB CONN13 | + +因此 `margin_save blanton` 就是一張平表跑完 18 顆,**不需要 `margin_init`**、 +不做 FPGA 通道初始化、不做 probe,也不會動到你當前載入的那顆板子: + +```bash +margin_save blanton +``` + +``` + CB CONN13 bus 4 0x5C : saved + SWB0 CONN13 bus 15 0x5C : saved + ... +margin_save blanton: 18 saved, 0 failed +``` + +送出去的就是這 18 行(2026-08-27 上機驗證): + +```bash +i2cset -f -y 4 0x5C 0x15 ; i2cset -f -y 4 0x5E 0x15 # CB CONN13 +i2cset -f -y 15 0x5C 0x15 ; i2cset -f -y 15 0x5E 0x15 # SWB0 CONN13 +i2cset -f -y 13 0x5C 0x15 ; i2cset -f -y 13 0x5E 0x15 # SWB0 CONN14 +i2cset -f -y 15 0x62 0x15 ; i2cset -f -y 15 0x64 0x15 # SWB0 CONN15 +i2cset -f -y 13 0x62 0x15 ; i2cset -f -y 13 0x64 0x15 # SWB0 CONN16 +i2cset -f -y 16 0x5C 0x15 ; i2cset -f -y 16 0x5E 0x15 # SWB1 CONN13 +i2cset -f -y 14 0x5C 0x15 ; i2cset -f -y 14 0x5E 0x15 # SWB1 CONN14 +i2cset -f -y 16 0x62 0x15 ; i2cset -f -y 16 0x64 0x15 # SWB1 CONN15 +i2cset -f -y 14 0x62 0x15 ; i2cset -f -y 14 0x64 0x15 # SWB1 CONN16 +``` + +`-f` 是因為這些 bus 上的 LTC2977 可能已被 kernel driver 認走;上機驗證過的指令帶 `-f`,就照原樣保留。 + +**這台沒裝滿的話**,把 `margin.sh` 頂端 `MARGIN_BLANTON_STORE` 陣列裡對應的行註解掉即可, +不要讓它去打不存在的板子。bus 節點不存在(`/dev/i2c-N` 沒有)與晶片不回應(NACK) +會分別報不同訊息 —— 前者代表 FPGA 的 i2c adapter 根本沒 enumerate,後者才是板子的問題。 ## Operation 對應 diff --git a/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/Ref/margin_command_trace.md b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/Ref/margin_command_trace.md index 7a67362..5961f0c 100644 --- a/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/Ref/margin_command_trace.md +++ b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/Ref/margin_command_trace.md @@ -424,8 +424,9 @@ SWB debug 指令(margin.sh v2.6.0 新增,皆為 `blanton_cb_i2c.sh` 的薄包裝 `Blanton_SWB0_CONN14.conf` 的第一顆也是 `0:0x5E`。兩個 CONN 現在同在 Ch6, 位址相撞。對照 SWB1 的規律(CONN13=`0x5C/0x5D`、CONN14=`0x5E/0x5F`), SWB0_CONN13 第二顆推測應為 `0:0x5D` — **尚未修改,待硬體確認**。 -- `margin_save` 走 `0x15` + data byte(`i2cset ... 0x15 0x00 b`)。PMBus 規範 - STORE_USER_ALL 是 send-byte;CB 上實測可用故保留原樣,swb 路徑沿用同一寫法。 +- `margin_save` 走 `0x15` **send-byte**(`i2cset ... 0x15 c` / `cb_pmbus_write 0x15`), + 不帶 data byte。v2.7.0 之前送的是 `0x15 0x00`(write-byte),CB 上實測可用, + 但那是零件寬容而非規範。 --- diff --git a/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/margin.sh b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/margin.sh index 50222b3..564410b 100644 --- a/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/margin.sh +++ b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/margin.sh @@ -5,6 +5,24 @@ # ============================================================================= # Version Control # ----------------------------------------------------------------------------- +# v2.7.0 margin_save fixes and batching: +# * STORE_USER_ALL (0x15) is now issued as an SMBus send-byte instead +# of a write-byte with a dummy 0x00 data byte. The LTC2977 accepted +# the old form on CB, but it was the wrong protocol. +# i2c path: i2cset ... 0x15 c swb path: cb_pmbus_write ch addr 0x15 +# * margin_save all -- STORE_USER_ALL on every board in settings/, +# then re-init whichever board was loaded beforehand. Does not stop +# on the first failure; prints a per-board summary at the end. +# * The store result is now checked. It used to be discarded, so a +# NACK still printed "Change Saved". +# * MARGIN_STORE_SETTLE (default 0.5s) between stores - nothing polls +# the part's busy bit, and `all` issues 18 of them in a row. +# * margin_save blanton -- Blanton SONiC shortcut. On this platform the +# CB FPGA F3 I2C channels also appear as native Linux i2c adapters +# (Ch6->bus 13, Ch7->14, Ch8->15, Ch9->16), so all 18 LTC2977 can be +# stored with plain i2cset: no margin_init, no FPGA channel setup, +# no pcimem. Bench-verified on the DUT 2026-08-27. The board list is +# MARGIN_BLANTON_STORE at the top of this file. # v2.6.0 SWB path actually wired to the shared CB I2C package. blanton_cb_i2c.sh # and blanton_fpga_pcimem.sh live in the PARENT dir (Blanton_Script/), not # next to margin.sh, so the backend is now searched in both places. @@ -115,6 +133,45 @@ ONOFF_ENABLE_VALUE="0x1a" # controlled_on=1, use_pmbus=1, use_control=0, b1=1 # margin_status after all channels are set. Bump this if you want margin_set's own # read-back to reflect the settled value. MARGIN_SETTLE="0.3" +# Pause after each STORE_USER_ALL. The LTC2977 is busy committing NVM once the +# command lands and nothing here polls a busy bit, so this is a plain guard +# rather than a measured value - it matters most for `margin_save all`, which +# fires 18 stores back to back. Set to "" to disable. +MARGIN_STORE_SETTLE="${MARGIN_STORE_SETTLE:-0.5}" + +# --- `margin_save blanton`: the bench-verified Blanton SONiC store list ------- +# On this platform the CB FPGA F3 I2C channels are ALSO exposed as native Linux +# i2c adapters, so every LTC2977 - CB and SWB alike - can be reached with plain +# i2cset. That path needs no FPGA channel setup, no pcimem, and no margin_init: +# one flat list, 18 commands, done. Verified on the DUT 2026-08-27. +# +# FPGA F3 channel -> Linux bus: Ch6->13 Ch7->14 Ch8->15 Ch9->16 +# +# Entry format: "bus:addr:label". Comment out the lines for boards this DUT does +# not have rather than letting them fail - a single-SWB unit is a normal build. +MARGIN_BLANTON_STORE=( + "4:0x5C:CB CONN13" + "4:0x5E:CB CONN13" + "15:0x5C:SWB0 CONN13" + "15:0x5E:SWB0 CONN13" + "13:0x5C:SWB0 CONN14" + "13:0x5E:SWB0 CONN14" + "15:0x62:SWB0 CONN15" + "15:0x64:SWB0 CONN15" + "13:0x62:SWB0 CONN16" + "13:0x64:SWB0 CONN16" + "16:0x5C:SWB1 CONN13" + "16:0x5E:SWB1 CONN13" + "14:0x5C:SWB1 CONN14" + "14:0x5E:SWB1 CONN14" + "16:0x62:SWB1 CONN15" + "16:0x64:SWB1 CONN15" + "14:0x62:SWB1 CONN16" + "14:0x64:SWB1 CONN16" +) +# -f because the LTC2977s may be claimed by a kernel driver on these buses; the +# command that was verified on the bench carries it, so it stays. +MARGIN_BLANTON_I2CSET_FLAGS="${MARGIN_BLANTON_I2CSET_FLAGS:--f -y}" _BUS="" _ADDR="" _PRE_SCOPE="" # set while inside a PRE/POST wrapped operation; prevents nested re-entry @@ -257,6 +314,20 @@ _swb_write() { return 0 } +# _swb_send -> cb_pmbus_write with NO data byte (SMBus send-byte). +# cb_pmbus_write routes a no-data call to _cbi2c_xfer_cmd_only: START, slave+W, +# command byte, STOP. That is what STORE_USER_ALL expects. +_swb_send() { + local reg=$1 + [ "$DEBUG_MODE" = "1" ] && echo -e "\033[90m[DEBG] cb_pmbus_write $CB_I2C_CH $_ADDR $reg (send-byte)\033[0m" + if ! _swb_call cb_pmbus_write "$CB_I2C_CH" "$_ADDR" "$reg" >/dev/null 2>&1; then + echo -e "[\033[31mERRO\033[0m] cb_pmbus_write ch=$CB_I2C_CH $_ADDR reg=$reg (send-byte) failed (NACK/timeout)" >&2 + _log_detail "ERRO cb_pmbus_write ch=$CB_I2C_CH $_ADDR $reg send-byte" + return 1 + fi + return 0 +} + # _swb_read_word -> echoes "0xXXXX" parsed out of cb_pmbus_read's "=> 0xXXXX" _swb_read_word() { local reg=$1 out word @@ -520,6 +591,20 @@ _i2c_write_byte() { i2cset -y "$_BUS" "$_ADDR" "$1" "$2" b >/dev/null 2>&1 } +# Send a PMBus command with NO data byte (SMBus send-byte). +# STORE_USER_ALL (0x15) and its relatives are send-byte commands: the command +# byte alone triggers them. Appending a dummy 0x00 makes it a write-byte, which +# is a different SMBus protocol - the LTC2977 happened to accept it, but that is +# tolerance, not correctness. i2cset's "c" mode is the send-byte form. +_i2c_send_byte() { + if [ "$TRANSPORT" = "swb" ]; then + _swb_send "$1" + return + fi + [ "$DEBUG_MODE" = "1" ] && echo -e "\033[90m[DEBG] i2cset -y $_BUS $_ADDR $1 c\033[0m" + i2cset -y "$_BUS" "$_ADDR" "$1" c >/dev/null 2>&1 +} + # Read a 16-bit word; echoes "0xXXXX". For swb, parse cb_pmbus_read's "=> 0xXXXX". _i2c_read_word() { if [ "$TRANSPORT" = "swb" ]; then @@ -730,20 +815,171 @@ margin_apply_profile() { } # --- Save to NVM --- +# margin_save -- STORE_USER_ALL on the currently initialised board +# margin_save all -- ... on every board in settings/, then re-init the one +# that was loaded when you called it +# margin_save blanton -- Blanton SONiC shortcut: all 18 LTC2977 straight over +# the native i2c buses, no margin_init needed +# +# ⚠️ This is the only permanent write in the tool: it commits the current +# margin / OV / UV registers to NVM, and a power cycle will NOT undo it. +# Run margin_status first and never call it during a test run. margin_save() { + if [ "${1:-}" = "all" ]; then + _margin_save_every_board + return + fi + if [ "${1:-}" = "blanton" ]; then + _margin_save_blanton + return + fi + local _own=0 _pre_enter_own && _own=1 + local chip fails=0 for chip in "${CHIPS[@]}"; do IFS=':' read -r _BUS _ADDR <<< "$chip" - _i2c_write_byte 0x15 0x00 + # STORE_USER_ALL is chip-wide (all 8 pages), so no _open_page here. + if _i2c_send_byte 0x15; then + _log_detail "STORE_USER_ALL $PART_NUMBER $_ADDR ok" + else + fails=$(( fails + 1 )) + echo -e "[\033[31mERRO\033[0m] STORE_USER_ALL failed on $_ADDR" >&2 + _log_detail "ERRO STORE_USER_ALL $PART_NUMBER $_ADDR" + fi + # The part is busy writing NVM after this; nothing here polls a busy bit, + # so leave a gap before touching it again. See MARGIN_STORE_SETTLE. + [ -n "$MARGIN_STORE_SETTLE" ] && sleep "$MARGIN_STORE_SETTLE" done - echo "Change Saved (${#CHIPS[@]} chips)" - _log_label "margin_save $PART_NUMBER (${#CHIPS[@]} chips)" + + if [ "$fails" -eq 0 ]; then + echo "Change Saved (${#CHIPS[@]} chips)" + else + echo -e "[\033[31mERRO\033[0m] $fails of ${#CHIPS[@]} chips did NOT save" + fi + _log_label "margin_save $PART_NUMBER (${#CHIPS[@]} chips, $fails failed)" [ "$_own" = "1" ] && _pre_exit + return $(( fails > 0 )) } +# margin_save all -- every .conf in settings/, in filename order. +# Deliberately does NOT stop on the first failure: a half-saved set is worse to +# diagnose than a fully-attempted one, and the summary tells you which boards +# to redo. margin_init is re-run per board because CHIPS / TRANSPORT / +# CB_I2C_CH are global state. +_margin_save_every_board() { + local files=( "$SETTINGS_DIR"/*.conf ) + if [ ! -e "${files[0]}" ]; then + echo -e "[\033[31mERRO\033[0m] no .conf found in $SETTINGS_DIR" + return 1 + fi + + local restore="$PART_NUMBER" # empty if margin_init was never run + local board f ok=0 bad=0 failed="" + + echo "-------------" + echo "margin_save all -- ${#files[@]} boards, permanent NVM write" + echo "-------------" + _log_label "margin_save all (${#files[@]} boards)" + + for f in "${files[@]}"; do + board=$(basename "$f" .conf) + echo "" + if ! margin_init "$board"; then + bad=$(( bad + 1 )); failed="$failed $board(init)" + continue + fi + if margin_save; then + ok=$(( ok + 1 )) + else + bad=$(( bad + 1 )); failed="$failed $board" + fi + done + + echo "" + echo "-------------" + printf "margin_save all: %d saved, %d failed\n" "$ok" "$bad" + [ "$bad" -gt 0 ] && echo -e "[\033[31mERRO\033[0m] failed:$failed" + echo "-------------" + _log_label "margin_save all done: $ok ok, $bad failed$failed" + + # Put back whatever board the caller had loaded, so a following + # margin_status does not silently report the last board in the list. + if [ -n "$restore" ] && [ "$restore" != "$board" ]; then + echo "" + echo -e "[\033[34mINFO\033[0m] restoring previous board: $restore" + margin_init "$restore" >/dev/null + fi + + return $(( bad > 0 )) +} + +# margin_save blanton -- Blanton SONiC only. Walks MARGIN_BLANTON_STORE and +# sends STORE_USER_ALL to each LTC2977 over the native i2c buses. +# +# Deliberately does NOT use margin_init / CHIPS / TRANSPORT: the whole point is +# that on this platform every LTC2977 is reachable with plain i2cset, so the +# FPGA channel setup and the per-board probe are not needed. That also means it +# does not touch the loaded board - PART_NUMBER is the same afterwards. +_margin_save_blanton() { + local n=${#MARGIN_BLANTON_STORE[@]} + if [ "$n" -eq 0 ]; then + echo -e "[\033[31mERRO\033[0m] MARGIN_BLANTON_STORE is empty" + return 1 + fi + + echo "-------------" + echo "margin_save blanton -- $n LTC2977, permanent NVM write" + echo "-------------" + _log_label "margin_save blanton ($n chips)" + + local entry bus addr label ok=0 bad=0 failed="" + for entry in "${MARGIN_BLANTON_STORE[@]}"; do + IFS=':' read -r bus addr label <<< "$entry" + + # "no such bus" and "chip did not answer" are different faults: the first + # means the FPGA i2c adapters did not enumerate, the second means the + # board is absent or the address is wrong. Do not blur them into one. + if [ ! -e "/dev/i2c-$bus" ]; then + echo -e "[\033[31mERRO\033[0m] $label bus $bus addr $addr : /dev/i2c-$bus does not exist" + _log_detail "ERRO STORE_USER_ALL $label bus=$bus addr=$addr no-such-bus" + bad=$(( bad + 1 )); failed="$failed [$label $addr]" + continue + fi + + [ "$DEBUG_MODE" = "1" ] && echo -e "\033[90m[DEBG] i2cset $MARGIN_BLANTON_I2CSET_FLAGS $bus $addr 0x15\033[0m" + if i2cset $MARGIN_BLANTON_I2CSET_FLAGS "$bus" "$addr" 0x15 >/dev/null 2>&1; then + printf " %-12s bus %-2s %s : saved\n" "$label" "$bus" "$addr" + ok=$(( ok + 1 )) + _log_detail "STORE_USER_ALL $label bus=$bus addr=$addr ok" + else + echo -e "[\033[31mERRO\033[0m] $label bus $bus addr $addr : i2cset failed (NACK/busy)" + _log_detail "ERRO STORE_USER_ALL $label bus=$bus addr=$addr" + bad=$(( bad + 1 )); failed="$failed [$label $addr]" + fi + + # No busy-bit poll anywhere in this tool; this gap is the only buffer. + [ -n "$MARGIN_STORE_SETTLE" ] && sleep "$MARGIN_STORE_SETTLE" + done + + echo "-------------" + printf "margin_save blanton: %d saved, %d failed\n" "$ok" "$bad" + [ "$bad" -gt 0 ] && echo -e "[\033[31mERRO\033[0m] failed:$failed" + echo "-------------" + _log_label "margin_save blanton done: $ok ok, $bad failed$failed" + + return $(( bad > 0 )) +} + +# --- Tab completion for margin_save --- +_margin_save_completions() { + [ "$COMP_CWORD" -ne 1 ] && return + COMPREPLY=($(compgen -W "all blanton" -- "${COMP_WORDS[COMP_CWORD]}")) +} +complete -F _margin_save_completions margin_save + if [ -z "$_LOG_FILE" ]; then _LOG_FILE="$LOGS_DIR/margin_$(date '+%Y%m%d_%H%M%S').log" _LOG_DETAIL_FILE="${_LOG_FILE%.log}_detail.log" diff --git a/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/script/margin_save_all.sh b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/script/margin_save_all.sh index c34249a..abe9067 100644 --- a/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/script/margin_save_all.sh +++ b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/script/margin_save_all.sh @@ -4,6 +4,10 @@ # ⚠️ margin_save 會把目前的 margin / OV / UV 設定**永久寫入 NVM**, # 斷電後仍保留。執行前請務必先 margin_status 確認各 channel 狀態正確。 # +# 全部 9 顆請直接用 margin.sh v2.7.0 內建的 `margin_save all` —— 它有成功/失敗總結, +# 跑完還會把 margin_init 切回你原本載入的那顆。這支只在「只想寫其中幾顆」時才需要, +# 編下面的 BOARDS 陣列。 +# # Usage: # source script/margin_save_all.sh