From 02a791b16faa1e4be115ab442f29ba8084fb8d38 Mon Sep 17 00:00:00 2001 From: 11311623 Date: Thu, 25 Jun 2026 03:06:17 +0000 Subject: [PATCH] gc2-es: Fix dimm-util err_inj related error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [Task Description] * Related to GC20T5T7-131、 GC20T5T7-230 * After injecting a DIMM PMIC error that causes the system to shut down, the following expected behavior was not observed: 1. host power off 2. err_list display the correct error type [Motivation] * Expect the behavior of gc2 to align with that of yv35, which has the same architecture [Design] * Refer to yv35 and implement a method that reads via I3C whenever DC OFF is detected. [Test Plan] 1. Verify that there are no errors in the current DIMM $ dimm-util server --pmic --err_list 2. DIMM PMIC error injection $ dimm-util server --pmic --dimm 0 --err_inj 3. Check error $ dimm-util server --pmic --err_list $ log-util all --print | tail -20 4. Check power status $ power-util server status 5. Recovery $ power-util server 12V-cycle [Test Log] ``` [SWAout_OV] root@bmc-oob:/tmp# dimm-util server --pmic --err_list DIMM A2 PMIC Error: No Error DIMM A3 PMIC Error: No DIMM DIMM A6 PMIC Error: No DIMM DIMM A7 PMIC Error: No DIMM root@bmc-oob:/tmp# dimm-util server --pmic --dimm 0 --err_inj SWAout_OV Error inject successfully on DIMM A2 root@bmc-oob:/tmp# dimm-util server --pmic --err_list DIMM A2 PMIC Error: SWAout_OV DIMM A3 PMIC Error: No DIMM DIMM A6 PMIC Error: No DIMM DIMM A7 PMIC Error: No DIMM root@bmc-oob:/tmp# log-util all --print | tail -20 2026 Jun 07 23:28:50 log-util: User cleared all logs 0 all 2026-06-07 23:28:50 healthd ASSERT: Verified boot failure (4,41) 0 all 2026-06-07 23:28:50 healthd Verified boot failure reason: The intermediate keys were not verified using the ROM keys 1 server 2026-06-07 23:34:55 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-07 23:34:55, Sensor: VR_FAULT (0xB1), Event Data: (001A41) PVCCIN_CPU0 status: 0x1a41 Assertion 1 server 2026-06-07 23:34:55 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-07 23:34:55, Sensor: VR_FAULT (0xB1), Event Data: (007841) PVCCIN_CPU0 status: 0x7841 Assertion 1 server 2026-06-07 23:34:55 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-07 23:34:55, Sensor: VR_FAULT (0xB1), Event Data: (007A00) PVCCIN_CPU0 status: 0x7a00 Assertion 1 server 2026-06-07 23:34:55 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-07 23:34:55, Sensor: VR_FAULT (0xB1), Event Data: (007B00) PVCCIN_CPU0 status: 0x7b00 Assertion 1 server 2026-06-07 23:34:55 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-07 23:34:55, Sensor: VR_FAULT (0xB1), Event Data: (007C00) PVCCIN_CPU0 status: 0x7c00 Assertion 1 server 2026-06-07 23:34:55 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-07 23:34:55, Sensor: VR_FAULT (0xB1), Event Data: (007D00) PVCCIN_CPU0 status: 0x7d00 Assertion 1 server 2026-06-07 23:34:55 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-07 23:34:55, Sensor: VR_FAULT (0xB1), Event Data: (007E00) PVCCIN_CPU0 status: 0x7e00 Assertion 1 server 2026-06-07 23:34:55 gpiod FRU: 1, Server is powered off 1 server 2026-06-07 23:34:55 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-07 23:34:55, Sensor: VR_FAULT (0xB1), Event Data: (007F01) PVCCIN_CPU0 status: 0x7f01 Assertion 1 server 2026-06-07 23:34:55 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-07 23:34:55, Sensor: VR_FAULT (0xB1), Event Data: (008010) PVCCIN_CPU0 status: 0x8010 Assertion 1 server 2026-06-07 23:34:55 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-07 23:34:55, Sensor: PMIC_ERROR (0xB4), Event Data: (000000) PMIC_ERROR DIMM A2 SWAOUT_OV Assertion 1 server 2026-06-07 23:35:00 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-07 23:35:00, Sensor: ME_POWER_STATE (0x16), Event Data: (000000) RUNNING Assertion 1 server 2026-06-07 23:35:09 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-07 23:35:09, Sensor: SYSTEM_STATUS (0x10), Event Data: (0AFFFF) SYS_VRWATCHDOG Assertion root@bmc-oob:/tmp# power-util server status Power status for fru 1 : OFF root@bmc-oob:~# power-util server 12V-cycle 12V Power cycling fru 1... [SWCout_OV] root@bmc-oob:/tmp# dimm-util server --pmic --err_list DIMM A2 PMIC Error: No Error DIMM A3 PMIC Error: No DIMM DIMM A6 PMIC Error: No DIMM DIMM A7 PMIC Error: No DIMM root@bmc-oob:/tmp# dimm-util server --pmic --dimm 0 --err_inj SWCout_OV Error inject successfully on DIMM A2 root@bmc-oob:/tmp# dimm-util server --pmic --err_list DIMM A2 PMIC Error: SWCout_OV DIMM A3 PMIC Error: No DIMM DIMM A6 PMIC Error: No DIMM DIMM A7 PMIC Error: No DIMM root@bmc-oob:/tmp# log-util all --print | tail -20 2026 Jun 07 23:48:08 log-util: User cleared all logs 0 all 2026-06-07 23:48:09 healthd ASSERT: Verified boot failure (4,41) 0 all 2026-06-07 23:48:09 healthd Verified boot failure reason: The intermediate keys were not verified using the ROM keys 1 server 2026-06-07 23:48:44 ipmid SEL Entry: FRU: 1, Record: Facebook Unified SEL (0xFB), GeneralInfo: POST(0x28), POST Failure Event: System PXE boot fail, Fail Type: IPv6 fail, Error Code: 0x10 1 server 2026-06-07 23:52:49 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-07 23:52:49, Sensor: VR_FAULT (0xB1), Event Data: (001A41) PVCCIN_CPU0 status: 0x1a41 Assertion 1 server 2026-06-07 23:52:49 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-07 23:52:49, Sensor: VR_FAULT (0xB1), Event Data: (007841) PVCCIN_CPU0 status: 0x7841 Assertion 1 server 2026-06-07 23:52:49 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-07 23:52:49, Sensor: VR_FAULT (0xB1), Event Data: (007A00) PVCCIN_CPU0 status: 0x7a00 Assertion 1 server 2026-06-07 23:52:49 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-07 23:52:49, Sensor: VR_FAULT (0xB1), Event Data: (007B00) PVCCIN_CPU0 status: 0x7b00 Assertion 1 server 2026-06-07 23:52:49 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-07 23:52:49, Sensor: VR_FAULT (0xB1), Event Data: (007C00) PVCCIN_CPU0 status: 0x7c00 Assertion 1 server 2026-06-07 23:52:49 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-07 23:52:49, Sensor: VR_FAULT (0xB1), Event Data: (007D00) PVCCIN_CPU0 status: 0x7d00 Assertion 1 server 2026-06-07 23:52:49 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-07 23:52:49, Sensor: VR_FAULT (0xB1), Event Data: (007E00) PVCCIN_CPU0 status: 0x7e00 Assertion 1 server 2026-06-07 23:52:49 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-07 23:52:49, Sensor: VR_FAULT (0xB1), Event Data: (007F01) PVCCIN_CPU0 status: 0x7f01 Assertion 1 server 2026-06-07 23:52:49 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-07 23:52:49, Sensor: VR_FAULT (0xB1), Event Data: (008010) PVCCIN_CPU0 status: 0x8010 Assertion 1 server 2026-06-07 23:52:49 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-07 23:52:49, Sensor: PMIC_ERROR (0xB4), Event Data: (000200) PMIC_ERROR DIMM A2 SWCOUT_OV Assertion 1 server 2026-06-07 23:52:49 gpiod FRU: 1, Server is powered off 1 server 2026-06-07 23:52:54 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-07 23:52:54, Sensor: ME_POWER_STATE (0x16), Event Data: (000000) RUNNING Assertion 1 server 2026-06-07 23:53:03 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-07 23:53:03, Sensor: SYSTEM_STATUS (0x10), Event Data: (0AFFFF) SYS_VRWATCHDOG Assertion root@bmc-oob:/tmp# power-util server status Power status for fru 1 : OFF root@bmc-oob:~# power-util server 12V-cycle 12V Power cycling fru 1... [SWDout_OV] root@bmc-oob:/tmp# dimm-util server --pmic --err_list DIMM A2 PMIC Error: No Error DIMM A3 PMIC Error: No DIMM DIMM A6 PMIC Error: No DIMM DIMM A7 PMIC Error: No DIMM root@bmc-oob:/tmp# dimm-util server --pmic --dimm 0 --err_inj SWDout_OV Error inject successfully on DIMM A2 root@bmc-oob:/tmp# dimm-util server --pmic --err_list DIMM A2 PMIC Error: SWDout_OV DIMM A3 PMIC Error: No DIMM DIMM A6 PMIC Error: No DIMM DIMM A7 PMIC Error: No DIMM root@bmc-oob:/tmp# log-util all --print | tail -20 2026 Jun 08 00:00:21 log-util: User cleared all logs 0 all 2026-06-08 00:00:21 healthd ASSERT: Verified boot failure (4,41) 0 all 2026-06-08 00:00:21 healthd Verified boot failure reason: The intermediate keys were not verified using the ROM keys 1 server 2026-06-08 00:00:28 ipmid SEL Entry: FRU: 1, Record: Facebook Unified SEL (0xFB), GeneralInfo: POST(0x28), POST Failure Event: System HTTP boot fail, Fail Type: IPv6 fail, Error Code: 0x63 1 server 2026-06-08 00:00:56 gpiod FRU: 1, Server is powered off 1 server 2026-06-08 00:00:56 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 00:00:56, Sensor: PMIC_ERROR (0xB4), Event Data: (000300) PMIC_ERROR DIMM A2 SWDOUT_OV Assertion 1 server 2026-06-08 00:01:01 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 00:01:01, Sensor: ME_POWER_STATE (0x16), Event Data: (000000) RUNNING Assertion 1 server 2026-06-08 00:01:10 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 00:01:10, Sensor: SYSTEM_STATUS (0x10), Event Data: (0AFFFF) SYS_VRWATCHDOG Assertion root@bmc-oob:/tmp# power-util server status Power status for fru 1 : OFF root@bmc-oob:~# power-util server 12V-cycle 12V Power cycling fru 1... [VinB_OV] root@bmc-oob:/tmp# dimm-util server --pmic --err_list DIMM A2 PMIC Error: No Error DIMM A3 PMIC Error: No DIMM DIMM A6 PMIC Error: No DIMM DIMM A7 PMIC Error: No DIMM root@bmc-oob:/tmp# dimm-util server --pmic --dimm 0 --err_inj VinB_OV Error inject successfully on DIMM A2 root@bmc-oob:/tmp# dimm-util server --pmic --err_list DIMM A2 PMIC Error: VinB_OV DIMM A3 PMIC Error: No DIMM DIMM A6 PMIC Error: No DIMM DIMM A7 PMIC Error: No DIMM root@bmc-oob:/tmp# log-util all --print | tail -20 2026 Jun 08 01:39:59 log-util: User cleared all logs 0 all 2026-06-08 01:40:00 healthd ASSERT: Verified boot failure (4,41) 0 all 2026-06-08 01:40:00 healthd Verified boot failure reason: The intermediate keys were not verified using the ROM keys 1 server 2026-06-08 01:40:30 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 01:40:30, Sensor: VR_FAULT (0xB1), Event Data: (001A41) PVCCIN_CPU0 status: 0x1a41 Assertion 1 server 2026-06-08 01:40:30 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 01:40:30, Sensor: VR_FAULT (0xB1), Event Data: (007841) PVCCIN_CPU0 status: 0x7841 Assertion 1 server 2026-06-08 01:40:30 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 01:40:30, Sensor: VR_FAULT (0xB1), Event Data: (007A00) PVCCIN_CPU0 status: 0x7a00 Assertion 1 server 2026-06-08 01:40:30 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 01:40:30, Sensor: VR_FAULT (0xB1), Event Data: (007B00) PVCCIN_CPU0 status: 0x7b00 Assertion 1 server 2026-06-08 01:40:30 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 01:40:30, Sensor: VR_FAULT (0xB1), Event Data: (007C00) PVCCIN_CPU0 status: 0x7c00 Assertion 1 server 2026-06-08 01:40:30 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 01:40:30, Sensor: VR_FAULT (0xB1), Event Data: (007D00) PVCCIN_CPU0 status: 0x7d00 Assertion 1 server 2026-06-08 01:40:30 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 01:40:30, Sensor: VR_FAULT (0xB1), Event Data: (007E00) PVCCIN_CPU0 status: 0x7e00 Assertion 1 server 2026-06-08 01:40:30 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 01:40:30, Sensor: VR_FAULT (0xB1), Event Data: (007F01) PVCCIN_CPU0 status: 0x7f01 Assertion 1 server 2026-06-08 01:40:30 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 01:40:30, Sensor: VR_FAULT (0xB1), Event Data: (008010) PVCCIN_CPU0 status: 0x8010 Assertion 1 server 2026-06-08 01:40:30 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 01:40:30, Sensor: PMIC_ERROR (0xB4), Event Data: (000400) PMIC_ERROR DIMM A2 VIN_BULK_OV Assertion 1 server 2026-06-08 01:40:31 gpiod FRU: 1, Server is powered off 1 server 2026-06-08 01:40:35 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 01:40:35, Sensor: ME_POWER_STATE (0x16), Event Data: (000000) RUNNING Assertion 1 server 2026-06-08 01:40:44 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 01:40:44, Sensor: SYSTEM_STATUS (0x10), Event Data: (0AFFFF) SYS_VRWATCHDOG Assertion root@bmc-oob:/tmp# power-util server status Power status for fru 1 : OFF root@bmc-oob:~# power-util server 12V-cycle 12V Power cycling fru 1... [SWAout_UV] root@bmc-oob:/tmp# dimm-util server --pmic --err_list DIMM A2 PMIC Error: No Error DIMM A3 PMIC Error: No DIMM DIMM A6 PMIC Error: No DIMM DIMM A7 PMIC Error: No DIMM root@bmc-oob:/tmp# dimm-util server --pmic --dimm 0 --err_inj SWAout_UV Error inject successfully on DIMM A2 root@bmc-oob:/tmp# dimm-util server --pmic --err_list DIMM A2 PMIC Error: SWAout_UV DIMM A3 PMIC Error: No DIMM DIMM A6 PMIC Error: No DIMM DIMM A7 PMIC Error: No DIMM root@bmc-oob:/tmp# log-util all --print | tail -20 2026 Jun 08 00:36:48 log-util: User cleared all logs 0 all 2026-06-08 00:36:51 healthd ASSERT: Verified boot failure (4,41) 0 all 2026-06-08 00:36:51 healthd Verified boot failure reason: The intermediate keys were not verified using the ROM keys 1 server 2026-06-08 00:37:55 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 00:37:55, Sensor: VR_FAULT (0xB1), Event Data: (001A41) PVCCIN_CPU0 status: 0x1a41 Assertion 1 server 2026-06-08 00:37:55 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 00:37:55, Sensor: VR_FAULT (0xB1), Event Data: (007841) PVCCIN_CPU0 status: 0x7841 Assertion 1 server 2026-06-08 00:37:55 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 00:37:55, Sensor: VR_FAULT (0xB1), Event Data: (007A00) PVCCIN_CPU0 status: 0x7a00 Assertion 1 server 2026-06-08 00:37:55 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 00:37:55, Sensor: VR_FAULT (0xB1), Event Data: (007B00) PVCCIN_CPU0 status: 0x7b00 Assertion 1 server 2026-06-08 00:37:55 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 00:37:55, Sensor: VR_FAULT (0xB1), Event Data: (007C00) PVCCIN_CPU0 status: 0x7c00 Assertion 1 server 2026-06-08 00:37:55 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 00:37:55, Sensor: VR_FAULT (0xB1), Event Data: (007D00) PVCCIN_CPU0 status: 0x7d00 Assertion 1 server 2026-06-08 00:37:55 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 00:37:55, Sensor: VR_FAULT (0xB1), Event Data: (007E00) PVCCIN_CPU0 status: 0x7e00 Assertion 1 server 2026-06-08 00:37:55 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 00:37:55, Sensor: VR_FAULT (0xB1), Event Data: (007F01) PVCCIN_CPU0 status: 0x7f01 Assertion 1 server 2026-06-08 00:37:55 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 00:37:55, Sensor: VR_FAULT (0xB1), Event Data: (008010) PVCCIN_CPU0 status: 0x8010 Assertion 1 server 2026-06-08 00:37:55 gpiod FRU: 1, Server is powered off 1 server 2026-06-08 00:37:55 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 00:37:55, Sensor: PMIC_ERROR (0xB4), Event Data: (000600) PMIC_ERROR DIMM A2 SWAOUT_UV Assertion 1 server 2026-06-08 00:38:00 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 00:38:00, Sensor: ME_POWER_STATE (0x16), Event Data: (000000) RUNNING Assertion 1 server 2026-06-08 00:38:09 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 00:38:09, Sensor: SYSTEM_STATUS (0x10), Event Data: (0AFFFF) SYS_VRWATCHDOG Assertion root@bmc-oob:/tmp# power-util server status Power status for fru 1 : OFF root@bmc-oob:~# power-util server 12V-cycle 12V Power cycling fru 1... [SWCout_UV] root@bmc-oob:/tmp# dimm-util server --pmic --err_list DIMM A2 PMIC Error: No Error DIMM A3 PMIC Error: No DIMM DIMM A6 PMIC Error: No DIMM DIMM A7 PMIC Error: No DIMM root@bmc-oob:/tmp# dimm-util server --pmic --dimm 0 --err_inj SWCout_UV Error inject successfully on DIMM A2 root@bmc-oob:/tmp# dimm-util server --pmic --err_list DIMM A2 PMIC Error: SWCout_UV DIMM A3 PMIC Error: No DIMM DIMM A6 PMIC Error: No DIMM DIMM A7 PMIC Error: No DIMM root@bmc-oob:/tmp# log-util all --print | tail -20 2026 Jun 08 00:56:15 log-util: User cleared all logs 0 all 2026-06-08 00:56:18 healthd ASSERT: Verified boot failure (4,41) 0 all 2026-06-08 00:56:18 healthd Verified boot failure reason: The intermediate keys were not verified using the ROM keys 1 server 2026-06-08 00:58:46 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 00:58:46, Sensor: VR_FAULT (0xB1), Event Data: (001A41) PVCCIN_CPU0 status: 0x1a41 Assertion 1 server 2026-06-08 00:58:46 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 00:58:46, Sensor: VR_FAULT (0xB1), Event Data: (007841) PVCCIN_CPU0 status: 0x7841 Assertion 1 server 2026-06-08 00:58:46 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 00:58:46, Sensor: VR_FAULT (0xB1), Event Data: (007A00) PVCCIN_CPU0 status: 0x7a00 Assertion 1 server 2026-06-08 00:58:46 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 00:58:46, Sensor: VR_FAULT (0xB1), Event Data: (007B00) PVCCIN_CPU0 status: 0x7b00 Assertion 1 server 2026-06-08 00:58:46 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 00:58:46, Sensor: VR_FAULT (0xB1), Event Data: (007C00) PVCCIN_CPU0 status: 0x7c00 Assertion 1 server 2026-06-08 00:58:46 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 00:58:46, Sensor: VR_FAULT (0xB1), Event Data: (007D00) PVCCIN_CPU0 status: 0x7d00 Assertion 1 server 2026-06-08 00:58:46 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 00:58:46, Sensor: VR_FAULT (0xB1), Event Data: (007E00) PVCCIN_CPU0 status: 0x7e00 Assertion 1 server 2026-06-08 00:58:46 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 00:58:46, Sensor: VR_FAULT (0xB1), Event Data: (007F01) PVCCIN_CPU0 status: 0x7f01 Assertion 1 server 2026-06-08 00:58:46 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 00:58:46, Sensor: VR_FAULT (0xB1), Event Data: (008010) PVCCIN_CPU0 status: 0x8010 Assertion 1 server 2026-06-08 00:58:46 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 00:58:46, Sensor: PMIC_ERROR (0xB4), Event Data: (000800) PMIC_ERROR DIMM A2 SWCOUT_UV Assertion 1 server 2026-06-08 00:58:46 gpiod FRU: 1, Server is powered off 1 server 2026-06-08 00:58:51 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 00:58:51, Sensor: ME_POWER_STATE (0x16), Event Data: (000000) RUNNING Assertion 1 server 2026-06-08 00:59:00 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 00:59:00, Sensor: SYSTEM_STATUS (0x10), Event Data: (0AFFFF) SYS_VRWATCHDOG Assertion root@bmc-oob:/tmp# power-util server status Power status for fru 1 : OFF root@bmc-oob:~# power-util server 12V-cycle 12V Power cycling fru 1... [SWDout_UV] root@bmc-oob:/tmp# dimm-util server --pmic --err_list DIMM A2 PMIC Error: No Error DIMM A3 PMIC Error: No DIMM DIMM A6 PMIC Error: No DIMM DIMM A7 PMIC Error: No DIMM root@bmc-oob:/tmp# dimm-util server --pmic --dimm 0 --err_inj SWDout_UV Error inject successfully on DIMM A2 root@bmc-oob:/tmp# dimm-util server --pmic --err_list DIMM A2 PMIC Error: SWDout_UV DIMM A3 PMIC Error: No DIMM DIMM A6 PMIC Error: No DIMM DIMM A7 PMIC Error: No DIMM root@bmc-oob:/tmp# log-util all --print | tail -20 2026 Jun 08 01:19:35 log-util: User cleared all logs 0 all 2026-06-08 01:19:36 healthd ASSERT: Verified boot failure (4,41) 0 all 2026-06-08 01:19:36 healthd Verified boot failure reason: The intermediate keys were not verified using the ROM keys 1 server 2026-06-08 01:20:12 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 01:20:12, Sensor: VR_FAULT (0xB1), Event Data: (001A41) PVCCIN_CPU0 status: 0x1a41 Assertion 1 server 2026-06-08 01:20:12 gpiod FRU: 1, Server is powered off 1 server 2026-06-08 01:20:12 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 01:20:12, Sensor: VR_FAULT (0xB1), Event Data: (007841) PVCCIN_CPU0 status: 0x7841 Assertion 1 server 2026-06-08 01:20:12 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 01:20:12, Sensor: VR_FAULT (0xB1), Event Data: (007A00) PVCCIN_CPU0 status: 0x7a00 Assertion 1 server 2026-06-08 01:20:12 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 01:20:12, Sensor: VR_FAULT (0xB1), Event Data: (007B00) PVCCIN_CPU0 status: 0x7b00 Assertion 1 server 2026-06-08 01:20:12 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 01:20:12, Sensor: VR_FAULT (0xB1), Event Data: (007C00) PVCCIN_CPU0 status: 0x7c00 Assertion 1 server 2026-06-08 01:20:12 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 01:20:12, Sensor: VR_FAULT (0xB1), Event Data: (007D00) PVCCIN_CPU0 status: 0x7d00 Assertion 1 server 2026-06-08 01:20:12 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 01:20:12, Sensor: VR_FAULT (0xB1), Event Data: (007E00) PVCCIN_CPU0 status: 0x7e00 Assertion 1 server 2026-06-08 01:20:12 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 01:20:12, Sensor: VR_FAULT (0xB1), Event Data: (007F01) PVCCIN_CPU0 status: 0x7f01 Assertion 1 server 2026-06-08 01:20:12 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 01:20:12, Sensor: VR_FAULT (0xB1), Event Data: (008010) PVCCIN_CPU0 status: 0x8010 Assertion 1 server 2026-06-08 01:20:12 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 01:20:12, Sensor: PMIC_ERROR (0xB4), Event Data: (000900) PMIC_ERROR DIMM A2 SWDOUT_UV Assertion 1 server 2026-06-08 01:20:17 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 01:20:17, Sensor: ME_POWER_STATE (0x16), Event Data: (000000) RUNNING Assertion 1 server 2026-06-08 01:20:26 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 01:20:26, Sensor: SYSTEM_STATUS (0x10), Event Data: (0AFFFF) SYS_VRWATCHDOG Assertion root@bmc-oob:/tmp# power-util server status Power status for fru 1 : OFF root@bmc-oob:~# power-util server 12V-cycle 12V Power cycling fru 1... [VinB_UV] root@bmc-oob:/tmp# dimm-util server --pmic --err_list DIMM A2 PMIC Error: No Error DIMM A3 PMIC Error: No DIMM DIMM A6 PMIC Error: No DIMM DIMM A7 PMIC Error: No DIMM root@bmc-oob:/tmp# dimm-util server --pmic --dimm 0 --err_inj VinB_UV Error inject successfully on DIMM A2 root@bmc-oob:/tmp# dimm-util server --pmic --err_list DIMM A2 PMIC Error: VinB_UV DIMM A3 PMIC Error: No DIMM DIMM A6 PMIC Error: No DIMM DIMM A7 PMIC Error: No DIMM root@bmc-oob:/tmp# log-util all --print | tail -20 2026 Jun 08 02:02:18 log-util: User cleared all logs 0 all 2026-06-08 02:02:18 healthd ASSERT: Verified boot failure (4,41) 0 all 2026-06-08 02:02:18 healthd Verified boot failure reason: The intermediate keys were not verified using the ROM keys 1 server 2026-06-08 02:04:10 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 02:04:10, Sensor: VR_FAULT (0xB1), Event Data: (001A41) PVCCIN_CPU0 status: 0x1a41 Assertion 1 server 2026-06-08 02:04:10 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 02:04:10, Sensor: VR_FAULT (0xB1), Event Data: (007841) PVCCIN_CPU0 status: 0x7841 Assertion 1 server 2026-06-08 02:04:10 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 02:04:10, Sensor: VR_FAULT (0xB1), Event Data: (007A00) PVCCIN_CPU0 status: 0x7a00 Assertion 1 server 2026-06-08 02:04:10 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 02:04:10, Sensor: VR_FAULT (0xB1), Event Data: (007B00) PVCCIN_CPU0 status: 0x7b00 Assertion 1 server 2026-06-08 02:04:10 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 02:04:10, Sensor: VR_FAULT (0xB1), Event Data: (007C00) PVCCIN_CPU0 status: 0x7c00 Assertion 1 server 2026-06-08 02:04:10 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 02:04:10, Sensor: VR_FAULT (0xB1), Event Data: (007D00) PVCCIN_CPU0 status: 0x7d00 Assertion 1 server 2026-06-08 02:04:10 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 02:04:10, Sensor: VR_FAULT (0xB1), Event Data: (007E00) PVCCIN_CPU0 status: 0x7e00 Assertion 1 server 2026-06-08 02:04:10 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 02:04:10, Sensor: VR_FAULT (0xB1), Event Data: (007F01) PVCCIN_CPU0 status: 0x7f01 Assertion 1 server 2026-06-08 02:04:10 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 02:04:10, Sensor: VR_FAULT (0xB1), Event Data: (008010) PVCCIN_CPU0 status: 0x8010 Assertion 1 server 2026-06-08 02:04:10 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 02:04:10, Sensor: PMIC_ERROR (0xB4), Event Data: (000A00) PMIC_ERROR DIMM A2 VIN_BULK_UV Assertion 1 server 2026-06-08 02:04:10 gpiod FRU: 1, Server is powered off 1 server 2026-06-08 02:04:15 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 02:04:15, Sensor: ME_POWER_STATE (0x16), Event Data: (000000) RUNNING Assertion 1 server 2026-06-08 02:04:24 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 02:04:24, Sensor: SYSTEM_STATUS (0x10), Event Data: (0AFFFF) SYS_VRWATCHDOG Assertion root@bmc-oob:/tmp# power-util server status Power status for fru 1 : OFF root@bmc-oob:~# power-util server 12V-cycle 12V Power cycling fru 1... [critical_temp_shutdown] root@bmc-oob:/tmp# dimm-util server --pmic --err_list DIMM A2 PMIC Error: No Error DIMM A3 PMIC Error: No DIMM DIMM A6 PMIC Error: No DIMM DIMM A7 PMIC Error: No DIMM root@bmc-oob:/tmp# dimm-util server --pmic --dimm 0 --err_inj critical_temp_shutdown Error inject successfully on DIMM A2 root@bmc-oob:/tmp# dimm-util server --pmic --err_list DIMM A2 PMIC Error: critical_temp_shutdown DIMM A3 PMIC Error: No DIMM DIMM A6 PMIC Error: No DIMM DIMM A7 PMIC Error: No DIMM root@bmc-oob:/tmp# log-util all --print | tail -20 2026 Jun 08 01:46:03 log-util: User cleared all logs 0 all 2026-06-08 01:46:03 healthd ASSERT: Verified boot failure (4,41) 0 all 2026-06-08 01:46:03 healthd Verified boot failure reason: The intermediate keys were not verified using the ROM keys 1 server 2026-06-08 01:46:22 gpiod FRU: 1, Server is powered off 1 server 2026-06-08 01:46:22 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 01:46:22, Sensor: PMIC_ERROR (0xB4), Event Data: (001000) PMIC_ERROR DIMM A2 CRITICAL_TEMP_SHUTDOWN Assertion 1 server 2026-06-08 01:46:27 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 01:46:27, Sensor: ME_POWER_STATE (0x16), Event Data: (000000) RUNNING Assertion 1 server 2026-06-08 01:46:36 ipmid SEL Entry: FRU: 1, Record: Standard (0x02), Time: 2026-06-08 01:46:36, Sensor: SYSTEM_STATUS (0x10), Event Data: (0AFFFF) SYS_VRWATCHDOG Assertion root@bmc-oob:/tmp# power-util server status Power status for fru 1 : OFF root@bmc-oob:~# power-util server 12V-cycle 12V Power cycling fru 1... --- meta-facebook/gc2-es/src/ipmi/plat_ipmi.c | 166 ++++++++ meta-facebook/gc2-es/src/platform/plat_dimm.c | 391 ++++++++++++++++++ meta-facebook/gc2-es/src/platform/plat_dimm.h | 84 ++++ meta-facebook/gc2-es/src/platform/plat_i3c.h | 5 +- meta-facebook/gc2-es/src/platform/plat_init.c | 3 +- meta-facebook/gc2-es/src/platform/plat_isr.c | 7 + meta-facebook/gc2-es/src/platform/plat_pmic.c | 235 ++++++----- meta-facebook/gc2-es/src/platform/plat_pmic.h | 22 +- .../gc2-es/src/platform/plat_sensor_table.c | 22 + .../gc2-es/src/platform/plat_sensor_table.h | 1 + 10 files changed, 811 insertions(+), 125 deletions(-) create mode 100644 meta-facebook/gc2-es/src/platform/plat_dimm.c create mode 100644 meta-facebook/gc2-es/src/platform/plat_dimm.h diff --git a/meta-facebook/gc2-es/src/ipmi/plat_ipmi.c b/meta-facebook/gc2-es/src/ipmi/plat_ipmi.c index cc58c4f1a0..13f5ac130f 100644 --- a/meta-facebook/gc2-es/src/ipmi/plat_ipmi.c +++ b/meta-facebook/gc2-es/src/ipmi/plat_ipmi.c @@ -20,10 +20,12 @@ #include "fru.h" #include "hal_gpio.h" #include "ipmi.h" +#include "power_status.h" #include "libutil.h" #include "plat_class.h" #include "plat_fru.h" #include "plat_ipmb.h" +#include "plat_dimm.h" #include #include #include @@ -263,3 +265,167 @@ void OEM_1S_SET_GPIO_CONFIG(ipmi_msg *msg) msg->data_len = 0; msg->completion_code = CC_SUCCESS; } + +/* +Byte 0 - DIMM location + 00h - A0 + 01h - A2 + 02h - A3 + 03h - A4 + 04h - A6 + 05h - A7 +Byte 1: Device type + 00h - SPD + 01h - SPD NVM + 02h - PMIC +Byte 2: Read/write data length +Byte 3:4: 2byte offset +Byte 5:~ write data +*/ +void OEM_1S_WRITE_READ_DIMM(ipmi_msg *msg) +{ + CHECK_NULL_ARG(msg); + + // At least include DIMM location, device type, write/read len, offset + if (msg->data_len < 4) { + msg->completion_code = CC_INVALID_LENGTH; + return; + } + + int ret = 0; + uint8_t dimm_id = msg->data[0]; + uint8_t device_type = msg->data[1]; + + // If host is DC on, BIC can't read DIMM information via I3C + // Return failed and BMC asks ME + if (get_DC_status()) { + msg->completion_code = CC_NOT_SUPP_IN_CURR_STATE; + return; + } + + I3C_MSG i3c_msg = { 0 }; + i3c_msg.bus = I3C_BUS3; + i3c_msg.tx_len = msg->data_len - 3; + i3c_msg.rx_len = msg->data[2]; + + // Check offset byte count: SPD_NVM has 2 bytes offset + if (device_type == DIMM_SPD_NVM) { + if (i3c_msg.tx_len < 2) { + msg->completion_code = CC_INVALID_DATA_FIELD; + return; + } + } else { + // One byte offset + if (i3c_msg.tx_len < 1) { + msg->completion_code = CC_INVALID_DATA_FIELD; + return; + } + } + + memcpy(&i3c_msg.data[0], &msg->data[3], i3c_msg.tx_len); + msg->data_len = i3c_msg.rx_len; + + if (k_mutex_lock(&i3c_dimm_mux_mutex, K_MSEC(I3C_DIMM_MUX_MUTEX_TIMEOUT_MS))) { + LOG_ERR("Failed to lock I3C dimm MUX"); + msg->completion_code = CC_NODE_BUSY; + return; + } + + ret = switch_i3c_dimm_mux(I3C_MUX_TO_BIC, dimm_id / (MAX_COUNT_DIMM / 2)); + if (ret < 0) { + msg->completion_code = CC_UNSPECIFIED_ERROR; + goto exit; + } + + // I3C_CCC_RSTDAA: Reset dynamic address assignment + // I3C_CCC_SETAASA: Set all addresses to static address + ret = all_brocast_ccc(&i3c_msg); + if (ret != 0) { + LOG_ERR("Failed to brocast CCC, ret%d bus%d", ret, i3c_msg.bus); + msg->completion_code = CC_UNSPECIFIED_ERROR; + goto exit; + } + + switch (device_type) { + case DIMM_SPD: + case DIMM_SPD_NVM: + i3c_msg.target_addr = spd_i3c_addr_list[dimm_id % (MAX_COUNT_DIMM / 2)]; + + if (device_type == DIMM_SPD_NVM) { + ret = i3c_spd_reg_read(&i3c_msg, true); + } else { + ret = i3c_spd_reg_read(&i3c_msg, false); + } + + if (ret != 0) { + LOG_ERR("Failed to read SPD addr0x%x offset0x%x, ret%d", + i3c_msg.target_addr, i3c_msg.data[0], ret); + msg->completion_code = CC_UNSPECIFIED_ERROR; + } else { + memcpy(&msg->data[0], &i3c_msg.data, i3c_msg.rx_len); + msg->data_len = i3c_msg.rx_len; + msg->completion_code = CC_SUCCESS; + } + break; + + case DIMM_PMIC: + i3c_msg.target_addr = pmic_i3c_addr_list[dimm_id % (MAX_COUNT_DIMM / 2)]; + + ret = i3c_transfer(&i3c_msg); + if (ret != 0) { + LOG_ERR("Failed to read PMIC addr0x%x offset0x%x, ret%d bus%d", + i3c_msg.target_addr, i3c_msg.data[0], ret, i3c_msg.bus); + msg->completion_code = CC_UNSPECIFIED_ERROR; + } else { + memcpy(&msg->data[0], &i3c_msg.data, i3c_msg.rx_len); + msg->data_len = i3c_msg.rx_len; + msg->completion_code = CC_SUCCESS; + } + break; + + default: + msg->completion_code = CC_INVALID_DATA_FIELD; + break; + } + +exit: + // Switch I3C MUX to CPU after read finish + switch_i3c_dimm_mux(I3C_MUX_TO_CPU, DIMM_MUX_TO_DIMM_A0A1A3); + + if (k_mutex_unlock(&i3c_dimm_mux_mutex)) { + LOG_ERR("Failed to unlock I3C dimm MUX"); + } +} + +void OEM_1S_GET_DIMM_I3C_MUX_SELECTION(ipmi_msg *msg) +{ + CHECK_NULL_ARG(msg); + + I2C_MSG i2c_msg = { 0 }; + int ret = 0, retry = 3; + + i2c_msg.bus = I2C_BUS1; + i2c_msg.target_addr = CPLD_ADDR; + i2c_msg.tx_len = 1; + i2c_msg.rx_len = 1; + i2c_msg.data[0] = DIMM_I3C_MUX_CONTROL_OFFSET; + + ret = i2c_master_read(&i2c_msg, retry); + if (ret != 0) { + LOG_ERR("Failed to read I3C MUX status, ret=%d", ret); + return; + } + + if (GETBIT(i2c_msg.data[0], 0) == I3C_MUX_TO_CPU) { + msg->data[0] = I3C_MUX_TO_CPU; + } else if (GETBIT(i2c_msg.data[0], 0) == I3C_MUX_TO_BIC) { + msg->data[0] = I3C_MUX_TO_BIC; + } else { + msg->completion_code = CC_UNSPECIFIED_ERROR; + return; + } + + msg->completion_code = CC_SUCCESS; + msg->data_len = 1; + return; +} diff --git a/meta-facebook/gc2-es/src/platform/plat_dimm.c b/meta-facebook/gc2-es/src/platform/plat_dimm.c new file mode 100644 index 0000000000..8a4443d3b2 --- /dev/null +++ b/meta-facebook/gc2-es/src/platform/plat_dimm.c @@ -0,0 +1,391 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "plat_dimm.h" + +#include +#include +#include +#include +#include +#include "sensor.h" +#include "libutil.h" +#include "power_status.h" +#include "pmic.h" +#include "plat_class.h" +#include "plat_i2c.h" +#include "plat_i3c.h" +#include "plat_pmic.h" +#include "plat_sensor_table.h" + +LOG_MODULE_REGISTER(plat_dimm); + +K_THREAD_STACK_DEFINE(get_dimm_info_stack, GET_DIMM_INFO_STACK_SIZE); +struct k_thread get_dimm_info_thread; +k_tid_t get_dimm_info_tid; + +struct k_mutex i3c_dimm_mux_mutex; + +uint8_t pmic_i3c_addr_list[MAX_COUNT_DIMM / 2] = { PMIC_A2_A6_ADDR, PMIC_A3_A7_ADDR }; +uint8_t spd_i3c_addr_list[MAX_COUNT_DIMM / 2] = { DIMM_SPD_A2_A6_ADDR, DIMM_SPD_A3_A7_ADDR }; + +dimm_info dimm_data[MAX_COUNT_DIMM]; + +static bool is_dimm_data_init = false; + +void start_get_dimm_info_thread(void) +{ + LOG_INF("Start thread to get DIMM information"); + + get_dimm_info_tid = + k_thread_create(&get_dimm_info_thread, get_dimm_info_stack, + K_THREAD_STACK_SIZEOF(get_dimm_info_stack), get_dimm_info_handler, + NULL, NULL, NULL, CONFIG_MAIN_THREAD_PRIORITY, 0, K_NO_WAIT); + k_thread_name_set(&get_dimm_info_thread, "get_dimm_info_thread"); +} + +void init_i3c_dimm(void) +{ + I3C_MSG i3c_msg = { 0 }; + int i = 0, ret = 0; + + i3c_msg.bus = I3C_BUS3; + + /* Attach DIMM SPD addr and PMIC addr */ + for (i = 0; i < (MAX_COUNT_DIMM / 2); i++) { + i3c_msg.target_addr = pmic_i3c_addr_list[i]; + ret = i3c_attach(&i3c_msg); + if (ret < 0) { + LOG_ERR("Failed to attach PMIC addr 0x%x", i3c_msg.target_addr); + } + i3c_msg.target_addr = spd_i3c_addr_list[i]; + ret = i3c_attach(&i3c_msg); + if (ret < 0) { + LOG_ERR("Failed to attach SPD addr 0x%x", i3c_msg.target_addr); + } + } + + /* Init mutex */ + if (k_mutex_init(&i3c_dimm_mux_mutex)) { + LOG_ERR("i3c_dimm_mux_mutex mutex init fail"); + } +} + +void init_i3c_dimm_data(void) +{ + I3C_MSG i3c_msg = { 0 }; + int i = 0, ret = 0; + + /* Clear DIMM data */ + memset(dimm_data, 0, sizeof(dimm_data)); + + i3c_msg.bus = I3C_BUS3; + + /* Init DIMM present status by attempting to read SPD */ + for (i = 0; i < MAX_COUNT_DIMM; i++) { + /* Read SPD vendor to check DIMM present */ + switch_i3c_dimm_mux(I3C_MUX_TO_BIC, i / (MAX_COUNT_DIMM / 2)); + all_brocast_ccc(&i3c_msg); + + i3c_msg.target_addr = spd_i3c_addr_list[i % (MAX_COUNT_DIMM / 2)]; + i3c_msg.tx_len = 1; + i3c_msg.rx_len = 1; + i3c_msg.data[0] = 0x00; + + ret = i3c_transfer(&i3c_msg); + if (ret == -EIO) { + dimm_data[i].is_present = false; + clear_unaccessible_dimm_data(i); + } else { + dimm_data[i].is_present = true; + } + } + + is_dimm_data_init = true; +} + +int all_brocast_ccc(I3C_MSG *i3c_msg) +{ + CHECK_NULL_ARG_WITH_RETURN(i3c_msg, -1); + + int ret = 0; + + ret = i3c_brocast_ccc(i3c_msg, I3C_CCC_RSTDAA, I3C_BROADCAST_ADDR); + if (ret != 0) { + return ret; + } + + ret = i3c_brocast_ccc(i3c_msg, I3C_CCC_SETAASA, I3C_BROADCAST_ADDR); + if (ret != 0) { + return ret; + } + + return ret; +} + +int switch_i3c_dimm_mux(uint8_t i3c_mux_position, uint8_t dimm_mux_position) +{ + I2C_MSG i2c_msg = { 0 }; + int ret = 0, retry = 3; + + i2c_msg.bus = I2C_BUS1; + i2c_msg.target_addr = CPLD_ADDR; + i2c_msg.tx_len = 2; + i2c_msg.rx_len = 0; + i2c_msg.data[0] = DIMM_I3C_MUX_CONTROL_OFFSET; + i2c_msg.data[1] = (dimm_mux_position << 1) | i3c_mux_position; + + ret = i2c_master_write(&i2c_msg, retry); + if (ret != 0) { + LOG_ERR("Failed to switch I3C MUX: 0x%x, ret=%d", i3c_mux_position, ret); + } + return ret; +} + +void get_dimm_info_handler(void *p1, void *p2, void *p3) +{ + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); + I3C_MSG i3c_msg = { 0 }; + + init_i3c_dimm(); + + /* Switch I3C mux to BIC when host post complete but BIC reset */ + if (get_post_status()) { + if (k_mutex_lock(&i3c_dimm_mux_mutex, K_MSEC(I3C_DIMM_MUX_MUTEX_TIMEOUT_MS))) { + LOG_ERR("Failed to lock I3C dimm MUX"); + } else { + switch_i3c_dimm_mux(I3C_MUX_TO_BIC, DIMM_MUX_TO_DIMM_A0A1A3); + + if (k_mutex_unlock(&i3c_dimm_mux_mutex)) { + LOG_ERR("Failed to unlock I3C dimm MUX"); + } + } + } + + while (1) { + int dimm_id = 0, ret = 0; + + /* Only monitor after post complete and I3C mux is to BIC */ + if (!get_post_status() || !is_i3c_mux_to_bic()) { + k_msleep(GET_DIMM_INFO_TIME_MS); + continue; + } + + if (!is_dimm_data_init) { + init_i3c_dimm_data(); + } + + if (k_mutex_lock(&i3c_dimm_mux_mutex, K_MSEC(I3C_DIMM_MUX_MUTEX_TIMEOUT_MS))) { + LOG_ERR("Failed to lock I3C dimm MUX"); + k_msleep(GET_DIMM_INFO_TIME_MS); + continue; + } + + for (dimm_id = 0; dimm_id < MAX_COUNT_DIMM; dimm_id++) { + /* Read all DIMM related information */ + /* DIMM temp: 2 byte, PMIC error: 47 byte, PMIC power: 1 byte */ + if (!dimm_data[dimm_id].is_present) { + continue; + } + + i3c_msg.bus = I3C_BUS3; + ret = switch_i3c_dimm_mux(I3C_MUX_TO_BIC, dimm_id / (MAX_COUNT_DIMM / 2)); + if (ret != 0) { + clear_unaccessible_dimm_data(dimm_id); + continue; + } + + /* I3C_CCC_RSTDAA: Reset dynamic address assignment */ + /* I3C_CCC_SETAASA: Set all addresses to static address */ + ret = all_brocast_ccc(&i3c_msg); + if (ret != 0) { + clear_unaccessible_dimm_data(dimm_id); + continue; + } + + /* Double check before read each DIMM info */ + if (!get_post_status()) { + break; + } + + /* Read DIMM SPD temperature */ + i3c_msg.target_addr = spd_i3c_addr_list[dimm_id % (MAX_COUNT_DIMM / 2)]; + i3c_msg.tx_len = 1; + i3c_msg.rx_len = MAX_LEN_I3C_GET_SPD_TEMP; + i3c_msg.data[0] = DIMM_SPD_TEMP_OFFSET; + + ret = i3c_transfer(&i3c_msg); + if (ret != 0) { + clear_unaccessible_dimm_data(dimm_id); + LOG_ERR("Failed to read DIMM %d SPD temperature via I3C, ret%d", + dimm_id, ret); + } else { + memcpy(&dimm_data[dimm_id].spd_temp_data, &i3c_msg.data, + sizeof(dimm_data[dimm_id].spd_temp_data)); + } + + /* Double check before read each DIMM info */ + if (!get_post_status()) { + break; + } + + /* Read DIMM PMIC power */ + i3c_msg.target_addr = pmic_i3c_addr_list[dimm_id % (MAX_COUNT_DIMM / 2)]; + i3c_msg.tx_len = 1; + i3c_msg.rx_len = MAX_LEN_I3C_GET_PMIC_PWR; + i3c_msg.data[0] = DIMM_PMIC_SWA_PWR_OFFSET; + + ret = i3c_transfer(&i3c_msg); + if (ret != 0) { + clear_unaccessible_dimm_data(dimm_id); + LOG_ERR("Failed to read DIMM %d PMIC power via I3C, ret%d", dimm_id, + ret); + continue; + } else { + memcpy(&dimm_data[dimm_id].pmic_pwr_data, &i3c_msg.data, + sizeof(dimm_data[dimm_id].pmic_pwr_data)); + } + + /* Double check before read each DIMM info */ + if (!get_post_status()) { + break; + } + + /* Read DIMM PMIC error */ + i3c_msg.target_addr = pmic_i3c_addr_list[dimm_id % (MAX_COUNT_DIMM / 2)]; + i3c_msg.tx_len = 1; + i3c_msg.rx_len = MAX_LEN_I3C_GET_PMIC_ERR; + i3c_msg.data[0] = PMIC_POR_ERROR_LOG_ADDR_VAL; + + ret = i3c_transfer(&i3c_msg); + if (ret != 0) { + clear_unaccessible_dimm_data(dimm_id); + LOG_ERR("Failed to read DIMM %d PMIC error via I3C, ret%d", dimm_id, + ret); + continue; + } else { + memcpy(&dimm_data[dimm_id].pmic_error_data, &i3c_msg.data, + sizeof(dimm_data[dimm_id].pmic_error_data)); + } + } + + if (k_mutex_unlock(&i3c_dimm_mux_mutex)) { + LOG_ERR("Failed to unlock I3C dimm MUX"); + } + + k_msleep(GET_DIMM_INFO_TIME_MS); + } +} + +bool is_i3c_mux_to_bic(void) +{ + I2C_MSG i2c_msg = { 0 }; + int ret = 0, retry = 3; + + i2c_msg.bus = I2C_BUS1; + i2c_msg.target_addr = CPLD_ADDR; + i2c_msg.tx_len = 1; + i2c_msg.rx_len = 1; + i2c_msg.data[0] = DIMM_I3C_MUX_CONTROL_OFFSET; + + ret = i2c_master_read(&i2c_msg, retry); + if (ret != 0) { + LOG_ERR("Failed to read I3C MUX status, ret=%d", ret); + return false; + } + + if (GETBIT(i2c_msg.data[0], 0) == I3C_MUX_TO_BIC) { + return true; + } else { + return false; + } +} + +bool is_dimm_present(uint8_t dimm_id) +{ + if (dimm_id >= MAX_COUNT_DIMM) { + return false; + } + return dimm_data[dimm_id].is_present; +} + +bool is_dimm_init(void) +{ + return is_dimm_data_init; +} + +void clear_unaccessible_dimm_data(uint8_t dimm_id) +{ + if (dimm_id >= MAX_COUNT_DIMM) { + return; + } + + memset(dimm_data[dimm_id].pmic_error_data, SENSOR_FAIL, + sizeof(dimm_data[dimm_id].pmic_error_data)); + memset(dimm_data[dimm_id].pmic_pwr_data, SENSOR_FAIL, + sizeof(dimm_data[dimm_id].pmic_pwr_data)); + memset(dimm_data[dimm_id].spd_temp_data, SENSOR_FAIL, + sizeof(dimm_data[dimm_id].spd_temp_data)); +} + +int get_pmic_error_raw_data(int dimm_index, uint8_t *data) +{ + CHECK_NULL_ARG_WITH_RETURN(data, -1); + + if (dimm_index >= MAX_COUNT_DIMM) { + return -1; + } + + int i = 0, fail_count = 0; + + for (i = 0; i < (int)sizeof(dimm_data[dimm_index].pmic_error_data); i++) { + if (dimm_data[dimm_index].pmic_error_data[i] == SENSOR_FAIL) { + fail_count++; + } + } + + /* PMIC error data read failed */ + if (fail_count == (int)sizeof(dimm_data[dimm_index].pmic_error_data)) { + return -1; + } + + memcpy(data, &dimm_data[dimm_index].pmic_error_data, + sizeof(dimm_data[dimm_index].pmic_error_data)); + + return 0; +} + +void get_pmic_power_raw_data(int dimm_index, uint8_t *data) +{ + if ((data == NULL) || (dimm_index >= MAX_COUNT_DIMM)) { + return; + } + + memcpy(data, &dimm_data[dimm_index].pmic_pwr_data, + sizeof(dimm_data[dimm_index].pmic_pwr_data)); +} + +void get_spd_temp_raw_data(int dimm_index, uint8_t *data) +{ + if ((data == NULL) || (dimm_index >= MAX_COUNT_DIMM)) { + return; + } + + memcpy(data, &dimm_data[dimm_index].spd_temp_data, + sizeof(dimm_data[dimm_index].spd_temp_data)); +} diff --git a/meta-facebook/gc2-es/src/platform/plat_dimm.h b/meta-facebook/gc2-es/src/platform/plat_dimm.h new file mode 100644 index 0000000000..5139a8bd5b --- /dev/null +++ b/meta-facebook/gc2-es/src/platform/plat_dimm.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PLAT_DIMM_H +#define PLAT_DIMM_H + +#include +#include +#include "plat_i3c.h" +#include "plat_pmic.h" + +/* ---------- Thread ---------- */ +#define GET_DIMM_INFO_STACK_SIZE 4096 +#define GET_DIMM_INFO_TIME_MS 1000 /* 1 second polling interval */ + +/* ---------- I3C MUX mutex timeout ---------- */ +#define I3C_DIMM_MUX_MUTEX_TIMEOUT_MS 1000 + +/* ---------- I3C read lengths ---------- */ +#define MAX_LEN_I3C_GET_PMIC_ERR 47 +#define MAX_LEN_I3C_GET_PMIC_PWR 1 +#define MAX_LEN_I3C_GET_SPD_TEMP 2 + +/* ---------- SPD register offset ---------- */ +#define DIMM_SPD_TEMP_OFFSET 0x31 + +/* ---------- PMIC register offset ---------- */ +#define DIMM_PMIC_SWA_PWR_OFFSET 0x39 + +/* ---------- SPD I3C address (GC2: only A2/A6 and A3/A7) ---------- */ +enum I3C_DIMM_SPD_ADDR { + DIMM_SPD_A2_A6_ADDR = 0x54, + DIMM_SPD_A3_A7_ADDR = 0x56, +}; + +enum DIMM_DEVICE_TYPE { + DIMM_SPD = 0x00, + DIMM_SPD_NVM = 0x01, + DIMM_PMIC = 0x02, +}; + +/* ---------- DIMM info structure ---------- */ +typedef struct dimm_info { + bool is_present; + uint8_t pmic_error_data[MAX_LEN_I3C_GET_PMIC_ERR]; + uint8_t pmic_pwr_data[MAX_LEN_I3C_GET_PMIC_PWR]; + uint8_t spd_temp_data[MAX_LEN_I3C_GET_SPD_TEMP]; +} dimm_info; + +/* ---------- Globals ---------- */ +extern struct k_mutex i3c_dimm_mux_mutex; +extern uint8_t pmic_i3c_addr_list[MAX_COUNT_DIMM / 2]; +extern uint8_t spd_i3c_addr_list[MAX_COUNT_DIMM / 2]; +extern dimm_info dimm_data[MAX_COUNT_DIMM]; + +/* ---------- Function prototypes ---------- */ +void start_get_dimm_info_thread(void); +void get_dimm_info_handler(void *p1, void *p2, void *p3); +void init_i3c_dimm(void); +void init_i3c_dimm_data(void); +void clear_unaccessible_dimm_data(uint8_t dimm_id); +int switch_i3c_dimm_mux(uint8_t i3c_mux_position, uint8_t dimm_mux_position); +bool is_i3c_mux_to_bic(void); +bool is_dimm_present(uint8_t dimm_id); +bool is_dimm_init(void); +int all_brocast_ccc(I3C_MSG *i3c_msg); +int get_pmic_error_raw_data(int dimm_index, uint8_t *data); +void get_pmic_power_raw_data(int dimm_index, uint8_t *data); +void get_spd_temp_raw_data(int dimm_index, uint8_t *data); + +#endif diff --git a/meta-facebook/gc2-es/src/platform/plat_i3c.h b/meta-facebook/gc2-es/src/platform/plat_i3c.h index ca1df26b7b..f7c85d4f3d 100644 --- a/meta-facebook/gc2-es/src/platform/plat_i3c.h +++ b/meta-facebook/gc2-es/src/platform/plat_i3c.h @@ -19,12 +19,9 @@ #include "hal_i3c.h" - #define I3C_BUS3 3 -enum I3C_PMIC_ADDR -{ - PMIC_A0_A4_ADDR = 0x48, +enum I3C_PMIC_ADDR { PMIC_A2_A6_ADDR = 0x4c, PMIC_A3_A7_ADDR = 0x4e, }; diff --git a/meta-facebook/gc2-es/src/platform/plat_init.c b/meta-facebook/gc2-es/src/platform/plat_init.c index 24cf37ff95..da647b4883 100644 --- a/meta-facebook/gc2-es/src/platform/plat_init.c +++ b/meta-facebook/gc2-es/src/platform/plat_init.c @@ -24,6 +24,7 @@ #include "plat_pmic.h" #include "util_worker.h" #include "plat_isr.h" +#include "plat_dimm.h" SCU_CFG scu_cfg[] = { //register value @@ -52,7 +53,7 @@ void pal_post_init() void pal_device_init() { init_me_firmware(); - + init_i3c_dimm(); start_monitor_pmic_error_thread(); } diff --git a/meta-facebook/gc2-es/src/platform/plat_isr.c b/meta-facebook/gc2-es/src/platform/plat_isr.c index c06fccdef1..635b788aab 100644 --- a/meta-facebook/gc2-es/src/platform/plat_isr.c +++ b/meta-facebook/gc2-es/src/platform/plat_isr.c @@ -108,10 +108,13 @@ void ISR_POST_COMPLETE() } K_WORK_DELAYABLE_DEFINE(set_DC_on_5s_work, set_DC_on_delayed_status); +K_WORK_DELAYABLE_DEFINE(read_pmic_critical_work, read_pmic_error_via_i3c); #define DC_ON_5_SECOND 5 #define VR_EVENT_DELAY_MS 10 +// The PMIC needs a total of 200ms from CAMP signal assertion to complete the write operation +#define READ_PMIC_CRITICAL_ERROR_MS 200 void ISR_DC_ON() { set_DC_status(PWRGD_SYS_PWROK); @@ -123,9 +126,13 @@ void ISR_DC_ON() if (dc_status) { k_work_schedule(&set_DC_on_5s_work, K_SECONDS(DC_ON_5_SECOND)); + clear_pmic_error(); } else { set_DC_on_delayed_status(); + // Read PMIC error when DC off + k_work_schedule(&read_pmic_critical_work, K_MSEC(READ_PMIC_CRITICAL_ERROR_MS)); + if ((gpio_get(FM_SLPS3_PLD_N) == GPIO_HIGH) && (gpio_get(RST_RSMRST_BMC_N) == GPIO_HIGH)) { common_addsel_msg_t sel_msg; diff --git a/meta-facebook/gc2-es/src/platform/plat_pmic.c b/meta-facebook/gc2-es/src/platform/plat_pmic.c index bbad96d8bd..372c9dc87f 100644 --- a/meta-facebook/gc2-es/src/platform/plat_pmic.c +++ b/meta-facebook/gc2-es/src/platform/plat_pmic.c @@ -34,6 +34,7 @@ #include "plat_sensor_table.h" #include "plat_class.h" #include "plat_i2c.h" +#include "plat_dimm.h" LOG_MODULE_REGISTER(plat_pmic); @@ -41,36 +42,34 @@ K_THREAD_STACK_DEFINE(monitor_pmic_error_stack, MONITOR_PMIC_ERROR_STACK_SIZE); struct k_thread monitor_pmic_error_thread; k_tid_t monitor_pmic_error_tid; -static const char dimm_lable[MAX_COUNT_DIMM][4] = { "A0", "A2", "A3", "A4", "A6", "A7" }; -static const uint8_t pmic_err_data_index[MAX_LEN_GET_PMIC_ERROR_INFO] = { 3, 4, 6, 7, 8, 9 }; -static const uint8_t pmic_err_pattern[MAX_COUNT_PMIC_ERROR_TYPE][MAX_LEN_GET_PMIC_ERROR_INFO] = { - // R05, R06, R08, R09, R0A, R0B - { 0x02, 0x08, 0x00, 0x00, 0x00, 0x00 }, // SWAOUT_OV - { 0x02, 0x04, 0x00, 0x00, 0x00, 0x00 }, // SWBOUT_OV - { 0x02, 0x02, 0x00, 0x00, 0x00, 0x00 }, // SWCOUT_OV - { 0x02, 0x01, 0x00, 0x00, 0x00, 0x00 }, // SWDOUT_OV - { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 }, // VIN_BULK_OV - { 0x00, 0x00, 0x02, 0x00, 0x02, 0x00 }, // VIN_MGMT_OV - { 0x02, 0x80, 0x00, 0x00, 0x00, 0x00 }, // SWAOUT_UV - { 0x02, 0x40, 0x00, 0x00, 0x00, 0x00 }, // SWBOUT_UV - { 0x02, 0x20, 0x00, 0x00, 0x00, 0x00 }, // SWCOUT_UV - { 0x02, 0x10, 0x00, 0x00, 0x00, 0x00 }, // SWDOUT_UV - { 0x00, 0x00, 0x80, 0x00, 0x00, 0x00 }, // VIN_BULK_UV - { 0x00, 0x00, 0x00, 0x10, 0x02, 0x00 }, // VIN_MGMT_TO_VIN_BUCK_SWITCHOVER - { 0x00, 0x00, 0x00, 0x80, 0x02, 0x00 }, // HIGH_TEMP_WARNING - { 0x00, 0x00, 0x00, 0x20, 0x02, 0x00 }, // VOUT_1V8_PG - { 0x00, 0x00, 0x00, 0x0F, 0x02, 0x00 }, // HIGH_CURRENT_WARNING - { 0x00, 0x00, 0x00, 0x00, 0x02, 0xF0 }, // CURRENT_LIMIT_WARNING - { 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 }, // CURRENT_TEMP_SHUTDOWN +static const char dimm_lable[MAX_COUNT_DIMM][4] = { "A2", "A3", "A6", "A7" }; +static const uint8_t pmic_err_data_index[MAX_COUNT_PMIC_ERROR_OFFSET] = { 3, 4, 6, 7, 8, 9, 0xFF }; +static const uint8_t pmic_err_pattern[MAX_COUNT_PMIC_ERROR_TYPE][MAX_COUNT_PMIC_ERROR_OFFSET] = { + // R05, R06, R08, R09, R0A, R0B, R33 + { 0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 }, // SWAOUT_OV + { 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 }, // SWBOUT_OV + { 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 }, // SWCOUT_OV + { 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 }, // SWDOUT_OV + { 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 }, // VIN_BULK_OV + { 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00 }, // VIN_MGMT_OV + { 0x02, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00 }, // SWAOUT_UV + { 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00 }, // SWBOUT_UV + { 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00 }, // SWCOUT_UV + { 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00 }, // SWDOUT_UV + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08 }, // VIN_BULK_UV + { 0x00, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00 }, // VIN_MGMT_TO_VIN_BUCK_SWITCHOVER + { 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00 }, // HIGH_TEMP_WARNING + { 0x00, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00 }, // VOUT_1V8_PG + { 0x00, 0x00, 0x00, 0x0F, 0x02, 0x00, 0x00 }, // HIGH_CURRENT_WARNING + { 0x00, 0x00, 0x00, 0x00, 0x02, 0xF0, 0x00 }, // CURRENT_LIMIT_WARNING + { 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00 }, // CURRENT_TEMP_SHUTDOWN }; static bool is_pmic_error_flag[MAX_COUNT_DIMM][MAX_COUNT_PMIC_ERROR_TYPE]; -static uint8_t pmic_i3c_err_data_index[MAX_LEN_GET_PMIC_ERROR_INFO] = { 0, 1, 3, 4, 5, 6 }; -static uint8_t pmic_i3c_addr_list[MAX_COUNT_DIMM / 2] = { PMIC_A0_A4_ADDR, PMIC_A2_A6_ADDR, - PMIC_A3_A7_ADDR }; +static uint8_t pmic_i3c_err_data_index[MAX_COUNT_PMIC_ERROR_OFFSET] = { 0, 1, 3, 4, 5, 6, 46 }; -void start_monitor_pmic_error_thread() +void start_monitor_pmic_error_thread(void) { LOG_INF("Start thread to monitor PMIC error"); @@ -165,6 +164,7 @@ int get_dimm_info(uint8_t dimm_id, uint8_t *bus, uint8_t *addr) return -1; } + // GC2: group 0 (A2, A3) / group 1 (A6, A7) if (dimm_id < (MAX_COUNT_DIMM / 2)) { *bus = BUS_ID_DIMM_CHANNEL_0_TO_3; } else { @@ -173,12 +173,9 @@ int get_dimm_info(uint8_t dimm_id, uint8_t *bus, uint8_t *addr) switch (dimm_id % (MAX_COUNT_DIMM / 2)) { case 0: - *addr = ADDR_DIMM_CHANNEL_0_4; - break; - case 1: *addr = ADDR_DIMM_CHANNEL_2_6; break; - case 2: + case 1: *addr = ADDR_DIMM_CHANNEL_3_7; break; default: @@ -218,7 +215,7 @@ int compare_pmic_error(uint8_t dimm_id, uint8_t *pmic_err_data, uint8_t pmic_err } for (err_index = 0; err_index < MAX_COUNT_PMIC_ERROR_TYPE; err_index++) { - for (reg_index = 0; reg_index < MAX_LEN_GET_PMIC_ERROR_INFO; reg_index++) { + for (reg_index = 0; reg_index < MAX_COUNT_PMIC_ERROR_OFFSET; reg_index++) { switch (read_path) { case READ_PMIC_ERROR_VIA_ME: data_index = pmic_err_data_index[reg_index]; @@ -231,13 +228,16 @@ int compare_pmic_error(uint8_t dimm_id, uint8_t *pmic_err_data, uint8_t pmic_err return -1; } + pattern = pmic_err_pattern[err_index][reg_index]; + // Not enough data if (data_index >= pmic_err_data_len) { + if (pattern == 0x00) { + continue; + } break; } - pattern = pmic_err_pattern[err_index][reg_index]; - // Not match if ((pmic_err_data[data_index] & pattern) != pattern) { break; @@ -245,7 +245,7 @@ int compare_pmic_error(uint8_t dimm_id, uint8_t *pmic_err_data, uint8_t pmic_err } // All bytes of error pattern are match - if (reg_index == MAX_LEN_GET_PMIC_ERROR_INFO) { + if (reg_index == MAX_COUNT_PMIC_ERROR_OFFSET) { if (is_pmic_error_flag[dimm_id][err_index] == false) { add_pmic_error_sel(dimm_id, err_index); is_pmic_error_flag[dimm_id][err_index] = true; @@ -279,28 +279,9 @@ void add_pmic_error_sel(uint8_t dimm_id, uint8_t error_type) int get_pmic_fault_status() { - uint8_t cpld_bus = 0; + const uint8_t cpld_bus = I2C_BUS4; ipmb_error status = IPMB_ERROR_UNKNOWN; ipmi_msg ipmi_msg = { 0 }; - - // Get slot ID - ipmi_msg.InF_source = SELF; - ipmi_msg.InF_target = BMC_IPMB; - ipmi_msg.netfn = NETFN_OEM_REQ; - ipmi_msg.cmd = CMD_OEM_GET_BOARD_ID; - ipmi_msg.data_len = 0; - status = ipmb_read(&ipmi_msg, IPMB_inf_index_map[ipmi_msg.InF_target]); - if (status != IPMB_ERROR_SUCCESS) { - LOG_ERR("Failed to get slot ID, status 0x%x", status); - return -1; - } - - // slot1 SB CPLD BUS is 4 - // slot2 SB CPLD BUS is 5 - // slot3 SB CPLD BUS is 6 - // slot4 SB CPLD BUS is 7 - cpld_bus = ipmi_msg.data[2] + 3; - // Read SB CPLD (BMC channel) to know which PMIC happen critical error ipmi_msg.InF_source = SELF; ipmi_msg.InF_target = BMC_IPMB; @@ -321,42 +302,13 @@ int get_pmic_fault_status() return ipmi_msg.data[0]; } -int switch_i3c_dimm_mux(uint8_t i3c_mux_position, uint8_t dimm_mux_position) -{ - I2C_MSG i2c_msg = { 0 }; - int ret = 0, retry = 3; - - i2c_msg.bus = I2C_BUS1; - i2c_msg.target_addr = CPLD_ADDR; - i2c_msg.tx_len = 2; - i2c_msg.rx_len = 0; - i2c_msg.data[0] = DIMM_I3C_MUX_CONTROL_OFFSET; // CPLD_I3C_DIMM_MUX - i2c_msg.data[1] = (dimm_mux_position << 1) | i3c_mux_position; - - ret = i2c_master_write(&i2c_msg, retry); - if (ret != 0) { - LOG_ERR("Failed to switch I3C MUX: 0x%x, ret=%d", i3c_mux_position, ret); - } - return ret; -} - void read_pmic_error_via_i3c() { - int ret = 0, i = 0; + int ret = 0; uint8_t dimm_id = 0; int pmic_fault_status = 0; I3C_MSG i3c_msg = { 0 }; - bool is_pmic_fault[MAX_COUNT_DIMM] = { false, false, false, false, false, false }; - - // Attach PMIC I3C address - i3c_msg.bus = I3C_BUS3; - for (i = 0; i < (MAX_COUNT_DIMM / 2); i++) { - i3c_msg.target_addr = pmic_i3c_addr_list[i]; - ret = i3c_attach(&i3c_msg); - if (ret < 0) { - LOG_ERR("Failed to attach addr 0x%x", i3c_msg.target_addr); - } - } + bool is_pmic_fault[MAX_COUNT_DIMM] = { false, false, false, false }; // Check PMIC fault status from SB CPLD (BMC channel) pmic_fault_status = get_pmic_fault_status(); @@ -369,24 +321,21 @@ void read_pmic_error_via_i3c() } // Check which PMIC is error - // DIMM PMIC Fault (1: Fault 0: Normal) + // GC2 DIMM PMIC Fault bit mapping (1: Fault 0: Normal) // bit 0: DIMM A6 A7 Fault - // bit 1: DIMM A4 A5 Fault // bit 2: DIMM A2 A3 Fault - // bit 3: DIMM A0 A1 Fault if (GETBIT(pmic_fault_status, 0)) { is_pmic_fault[DIMM_ID_A6] = true; is_pmic_fault[DIMM_ID_A7] = true; } - if (GETBIT(pmic_fault_status, 1)) { - is_pmic_fault[DIMM_ID_A4] = true; - } if (GETBIT(pmic_fault_status, 2)) { is_pmic_fault[DIMM_ID_A2] = true; is_pmic_fault[DIMM_ID_A3] = true; } - if (GETBIT(pmic_fault_status, 3)) { - is_pmic_fault[DIMM_ID_A0] = true; + + if (k_mutex_lock(&i3c_dimm_mux_mutex, K_MSEC(I3C_DIMM_MUX_MUTEX_TIMEOUT_MS))) { + LOG_ERR("Failed to lock I3C dimm MUX"); + return; } for (dimm_id = 0; dimm_id < MAX_COUNT_DIMM; dimm_id++) { @@ -396,34 +345,24 @@ void read_pmic_error_via_i3c() } // Switch I3C mux to BIC and switch DIMM mux - switch (dimm_id / (MAX_COUNT_DIMM / 2)) { - case 0: - switch_i3c_dimm_mux(I3C_MUX_TO_BIC, DIMM_MUX_TO_DIMM_A0A1A3); - break; - case 1: - switch_i3c_dimm_mux(I3C_MUX_TO_BIC, DIMM_MUX_TO_DIMM_A4A6A7); - break; - default: - LOG_ERR("Invalid dimm id %d", dimm_id); - return; - } - - // Brocase CCC after switch DIMM mux - ret = i3c_brocast_ccc(&i3c_msg, I3C_CCC_RSTDAA, I3C_BROADCAST_ADDR); + ret = switch_i3c_dimm_mux(I3C_MUX_TO_BIC, dimm_id / (MAX_COUNT_DIMM / 2)); if (ret < 0) { continue; } - ret = i3c_brocast_ccc(&i3c_msg, I3C_CCC_SETAASA, I3C_BROADCAST_ADDR); - if (ret < 0) { + // Broadcast CCC after switch DIMM mux + i3c_msg.bus = I3C_BUS3; + ret = all_brocast_ccc(&i3c_msg); + if (ret != 0) { + LOG_ERR("Failed to broadcast CCC, ret%d bus%d", ret, i3c_msg.bus); continue; } // Read PMIC error via I3C i3c_msg.target_addr = pmic_i3c_addr_list[dimm_id % (MAX_COUNT_DIMM / 2)]; i3c_msg.tx_len = 1; - i3c_msg.rx_len = MAX_LEN_I3C_GET_PMIC_ERROR_INFO; - memset(&i3c_msg.data, 0, MAX_LEN_I3C_GET_PMIC_ERROR_INFO); + i3c_msg.rx_len = MAX_LEN_I3C_GET_PMIC_ERR; + memset(&i3c_msg.data, 0, MAX_LEN_I3C_GET_PMIC_ERR); i3c_msg.data[0] = PMIC_POR_ERROR_LOG_ADDR_VAL; ret = i3c_transfer(&i3c_msg); @@ -431,6 +370,17 @@ void read_pmic_error_via_i3c() LOG_ERR("Failed to read PMIC error via I3C"); continue; } + LOG_INF("[I3C] DIMM %s PMIC registers:" + " R05=0x%02x R06=0x%02x R08=0x%02x" + " R09=0x%02x R0A=0x%02x R0B=0x%02x R33=0x%02x", + dimm_lable[dimm_id], + i3c_msg.data[pmic_i3c_err_data_index[0]], // R05 = data[0] + i3c_msg.data[pmic_i3c_err_data_index[1]], // R06 = data[1] + i3c_msg.data[pmic_i3c_err_data_index[2]], // R08 = data[3] + i3c_msg.data[pmic_i3c_err_data_index[3]], // R09 = data[4] + i3c_msg.data[pmic_i3c_err_data_index[4]], // R0A = data[5] + i3c_msg.data[pmic_i3c_err_data_index[5]], // R0B = data[6] + i3c_msg.data[pmic_i3c_err_data_index[6]]); // R33 = data[46] // Compare error pattern, add SEL to BMC and update record ret = compare_pmic_error(dimm_id, i3c_msg.data, i3c_msg.rx_len, @@ -440,7 +390,72 @@ void read_pmic_error_via_i3c() } } + if (k_mutex_unlock(&i3c_dimm_mux_mutex)) { + LOG_ERR("Failed to unlock I3C dimm MUX"); + } + // Switch I3C MUX to CPU after read finish switch_i3c_dimm_mux(I3C_MUX_TO_CPU, DIMM_MUX_TO_DIMM_A0A1A3); return; } + +void clear_pmic_error() +{ + int dimm_id = 0, ret = 0; + uint8_t dimm_status = SENSOR_INIT_STATUS; + I3C_MSG i3c_msg = { 0 }; + + if (k_mutex_lock(&i3c_dimm_mux_mutex, K_MSEC(I3C_DIMM_MUX_MUTEX_TIMEOUT_MS))) { + LOG_ERR("Failed to lock I3C dimm MUX"); + return; + } + + for (dimm_id = 0; dimm_id < MAX_COUNT_DIMM; dimm_id++) { + dimm_status = get_dimm_status(dimm_id); + if ((dimm_status == SENSOR_INIT_STATUS) || (dimm_status == SENSOR_NOT_PRESENT) || + (dimm_status == SENSOR_POLLING_DISABLE)) { + continue; + } + + ret = switch_i3c_dimm_mux(I3C_MUX_TO_BIC, dimm_id / (MAX_COUNT_DIMM / 2)); + if (ret < 0) { + continue; + } + + i3c_msg.bus = I3C_BUS3; + all_brocast_ccc(&i3c_msg); + + i3c_msg.target_addr = pmic_i3c_addr_list[dimm_id % (MAX_COUNT_DIMM / 2)]; + i3c_msg.tx_len = 2; + i3c_msg.rx_len = 1; + memset(i3c_msg.data, 0, sizeof(i3c_msg.data)); + + // Set R39 to clear registers R04 ~ R07 + // Host Region Codes: 0x74 + // Clear Registers R04 to R07, Erase MTP memory for R04 Register + i3c_msg.data[0] = PMIC_VENDOR_PASSWORD_CONTROL_OFFSET; + i3c_msg.data[1] = 0x74; + ret = i3c_transfer(&i3c_msg); + if (ret != 0) { + continue; + } + + // Set R14 to clear registers R08 ~ R0B, R33 + // R14[0]: GLOBAL_CLEAR_STATUS, Clear all status bits + i3c_msg.data[0] = PMIC_CLEAR_STATUS_BITS4_OFFSET; + i3c_msg.data[1] = 0x01; + ret = i3c_transfer(&i3c_msg); + if (ret != 0) { + continue; + } + } + + if (k_mutex_unlock(&i3c_dimm_mux_mutex)) { + LOG_ERR("Failed to unlock I3C dimm MUX"); + } + + // Switch I3C MUX to CPU after clear finish + switch_i3c_dimm_mux(I3C_MUX_TO_CPU, DIMM_MUX_TO_DIMM_A0A1A3); + + return; +} diff --git a/meta-facebook/gc2-es/src/platform/plat_pmic.h b/meta-facebook/gc2-es/src/platform/plat_pmic.h index e3aecd0ff1..972486bc70 100644 --- a/meta-facebook/gc2-es/src/platform/plat_pmic.h +++ b/meta-facebook/gc2-es/src/platform/plat_pmic.h @@ -4,7 +4,7 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software @@ -18,14 +18,15 @@ #define PLAT_PMIC_H #include +#include #define MONITOR_PMIC_ERROR_STACK_SIZE 4096 #define MONITOR_PMIC_ERROR_TIME_MS (3 * 1000) // 3s #define MAX_LEN_GET_PMIC_ERROR_INFO 6 -#define MAX_LEN_I3C_GET_PMIC_ERROR_INFO 7 +#define MAX_COUNT_PMIC_ERROR_OFFSET 7 -#define MAX_COUNT_DIMM 6 +#define MAX_COUNT_DIMM 4 #define MAX_COUNT_PMIC_ERROR_TYPE 17 #define I3C_MUX_TO_BIC 0x1 @@ -34,14 +35,15 @@ #define DIMM_MUX_TO_DIMM_A4A6A7 0x1 #define CL_CPLD_BMC_CHANNEL_ADDR 0x1E // 8 bits -#define PMIC_FAULT_STATUS_OFFSET 0x0B -#define DIMM_I3C_MUX_CONTROL_OFFSET 0x0B +#define PMIC_FAULT_STATUS_OFFSET 0x0D +#define DIMM_I3C_MUX_CONTROL_OFFSET 0x20 + +#define PMIC_CLEAR_STATUS_BITS4_OFFSET 0x14 +#define PMIC_VENDOR_PASSWORD_CONTROL_OFFSET 0x39 enum DIMM_ID { - DIMM_ID_A0 = 0, - DIMM_ID_A2, + DIMM_ID_A2 = 0, DIMM_ID_A3, - DIMM_ID_A4, DIMM_ID_A6, DIMM_ID_A7, }; @@ -57,8 +59,8 @@ int compare_pmic_error(uint8_t dimm_id, uint8_t *pmic_err_data, uint8_t pmic_err uint8_t read_path); int get_dimm_info(uint8_t dimm_id, uint8_t *bus, uint8_t *addr); void add_pmic_error_sel(uint8_t dimm_id, uint8_t error_type); -int switch_i3c_dimm_mux(uint8_t i3c_mux_position, uint8_t dimm_mux_position); -void read_pmic_error_via_i3c(); int get_pmic_fault_status(); +void read_pmic_error_via_i3c(); +void clear_pmic_error(); #endif diff --git a/meta-facebook/gc2-es/src/platform/plat_sensor_table.c b/meta-facebook/gc2-es/src/platform/plat_sensor_table.c index b6cd552f02..be44686241 100644 --- a/meta-facebook/gc2-es/src/platform/plat_sensor_table.c +++ b/meta-facebook/gc2-es/src/platform/plat_sensor_table.c @@ -935,3 +935,25 @@ bool vr_access(uint8_t sensor_num) return get_vr_monitor_status(); } + +static int sensor_get_idx_by_sensor_num(uint16_t sensor_num) +{ + int sensor_idx = 0; + for (sensor_idx = 0; sensor_idx < sensor_config_count; sensor_idx++) { + if (sensor_num == sensor_config[sensor_idx].num) + return sensor_idx; + } + + return -1; +} + +uint8_t get_dimm_status(uint8_t dimm_index) +{ + int sensor_index = + sensor_get_idx_by_sensor_num(dimm_pmic_map_table[dimm_index].dimm_sensor_num); + if (sensor_index < 0) { + return SENSOR_NOT_SUPPORT; + } + + return sensor_config[sensor_index].cache_status; +} diff --git a/meta-facebook/gc2-es/src/platform/plat_sensor_table.h b/meta-facebook/gc2-es/src/platform/plat_sensor_table.h index 9a2cf46d3e..eeb1219225 100644 --- a/meta-facebook/gc2-es/src/platform/plat_sensor_table.h +++ b/meta-facebook/gc2-es/src/platform/plat_sensor_table.h @@ -157,5 +157,6 @@ uint8_t plat_get_config_size(); uint8_t pal_get_extend_sensor_config(); void load_sensor_config(void); bool disable_dimm_pmic_sensor(uint8_t sensor_num); +uint8_t get_dimm_status(uint8_t dimm_index); #endif