1.. SPDX-License-Identifier: GPL-2.0 2 3Debugging AMD Zen systems 4+++++++++++++++++++++++++ 5 6Introduction 7============ 8 9This document describes techniques that are useful for debugging issues with 10AMD Zen systems. It is intended for use by developers and technical users 11to help identify and resolve issues. 12 13S3 vs s2idle 14============ 15 16On AMD systems, it's not possible to simultaneously support suspend-to-RAM (S3) 17and suspend-to-idle (s2idle). To confirm which mode your system supports you 18can look at ``cat /sys/power/mem_sleep``. If it shows ``s2idle [deep]`` then 19*S3* is supported. If it shows ``[s2idle]`` then *s2idle* is 20supported. 21 22On systems that support *S3*, the firmware will be utilized to put all hardware into 23the appropriate low power state. 24 25On systems that support *s2idle*, the kernel will be responsible for transitioning devices 26into the appropriate low power state. When all devices are in the appropriate low 27power state, the hardware will transition into a hardware sleep state. 28 29After a suspend cycle you can tell how much time was spent in a hardware sleep 30state by looking at ``cat /sys/power/suspend_stats/last_hw_sleep``. 31 32This flowchart explains how the AMD s2idle suspend flow works. 33 34.. kernel-figure:: suspend.svg 35 36This flowchart explains how the amd s2idle resume flow works. 37 38.. kernel-figure:: resume.svg 39 40s2idle debugging tool 41===================== 42 43As there are a lot of places that problems can occur, a debugging tool has been 44created at 45`amd-debug-tools <https://git.kernel.org/pub/scm/linux/kernel/git/superm1/amd-debug-tools.git/about/>`_ 46that can help test for common problems and offer suggestions. 47 48If you have an s2idle issue, it's best to start with this and follow instructions 49from its findings. If you continue to have an issue, raise a bug with the 50report generated from this script to 51`drm/amd gitlab <https://gitlab.freedesktop.org/drm/amd/-/issues/new?issuable_template=s2idle_BUG_TEMPLATE>`_. 52 53Spurious s2idle wakeups from an IRQ 54=================================== 55 56Spurious wakeups will generally have an IRQ set to ``/sys/power/pm_wakeup_irq``. 57This can be matched to ``/proc/interrupts`` to determine what device woke the system. 58 59If this isn't enough to debug the problem, then the following sysfs files 60can be set to add more verbosity to the wakeup process: :: 61 62 # echo 1 | sudo tee /sys/power/pm_debug_messages 63 # echo 1 | sudo tee /sys/power/pm_print_times 64 65After making those changes, the kernel will display messages that can 66be traced back to kernel s2idle loop code as well as display any active 67GPIO sources while waking up. 68 69If the wakeup is caused by the ACPI SCI, additional ACPI debugging may be 70needed. These commands can enable additional trace data: :: 71 72 # echo enable | sudo tee /sys/module/acpi/parameters/trace_state 73 # echo 1 | sudo tee /sys/module/acpi/parameters/aml_debug_output 74 # echo 0x0800000f | sudo tee /sys/module/acpi/parameters/debug_level 75 # echo 0xffff0000 | sudo tee /sys/module/acpi/parameters/debug_layer 76 77Spurious s2idle wakeups from a GPIO 78=================================== 79 80If a GPIO is active when waking up the system ideally you would look at the 81schematic to determine what device it is associated with. If the schematic 82is not available, another tactic is to look at the ACPI _EVT() entry 83to determine what device is notified when that GPIO is active. 84 85For a hypothetical example, say that GPIO 59 woke up the system. You can 86look at the SSDT to determine what device is notified when GPIO 59 is active. 87 88First convert the GPIO number into hex. :: 89 90 $ python3 -c "print(hex(59))" 91 0x3b 92 93Next determine which ACPI table has the ``_EVT`` entry. For example: :: 94 95 $ sudo grep EVT /sys/firmware/acpi/tables/SSDT* 96 grep: /sys/firmware/acpi/tables/SSDT27: binary file matches 97 98Decode this table:: 99 100 $ sudo cp /sys/firmware/acpi/tables/SSDT27 . 101 $ sudo iasl -d SSDT27 102 103Then look at the table and find the matching entry for GPIO 0x3b. :: 104 105 Case (0x3B) 106 { 107 M000 (0x393B) 108 M460 (" Notify (\\_SB.PCI0.GP17.XHC1, 0x02)\n", Zero, Zero, Zero, Zero, Zero, Zero) 109 Notify (\_SB.PCI0.GP17.XHC1, 0x02) // Device Wake 110 } 111 112You can see in this case that the device ``\_SB.PCI0.GP17.XHC1`` is notified 113when GPIO 59 is active. It's obvious this is an XHCI controller, but to go a 114step further you can figure out which XHCI controller it is by matching it to 115ACPI.:: 116 117 $ grep "PCI0.GP17.XHC1" /sys/bus/acpi/devices/*/path 118 /sys/bus/acpi/devices/device:2d/path:\_SB_.PCI0.GP17.XHC1 119 /sys/bus/acpi/devices/device:2e/path:\_SB_.PCI0.GP17.XHC1.RHUB 120 /sys/bus/acpi/devices/device:2f/path:\_SB_.PCI0.GP17.XHC1.RHUB.PRT1 121 /sys/bus/acpi/devices/device:30/path:\_SB_.PCI0.GP17.XHC1.RHUB.PRT1.CAM0 122 /sys/bus/acpi/devices/device:31/path:\_SB_.PCI0.GP17.XHC1.RHUB.PRT1.CAM1 123 /sys/bus/acpi/devices/device:32/path:\_SB_.PCI0.GP17.XHC1.RHUB.PRT2 124 /sys/bus/acpi/devices/LNXPOWER:0d/path:\_SB_.PCI0.GP17.XHC1.PWRS 125 126Here you can see it matches to ``device:2d``. Look at the ``physical_node`` 127to determine what PCI device that actually is. :: 128 129 $ ls -l /sys/bus/acpi/devices/device:2d/physical_node 130 lrwxrwxrwx 1 root root 0 Feb 12 13:22 /sys/bus/acpi/devices/device:2d/physical_node -> ../../../../../pci0000:00/0000:00:08.1/0000:c2:00.4 131 132So there you have it: the PCI device associated with this GPIO wakeup was ``0000:c2:00.4``. 133 134The ``amd_s2idle.py`` script will capture most of these artifacts for you. 135 136s2idle PM debug messages 137======================== 138 139During the s2idle flow on AMD systems, the ACPI LPS0 driver is responsible 140to check all uPEP constraints. Failing uPEP constraints does not prevent 141s0i3 entry. This means that if some constraints are not met, it is possible 142the kernel may attempt to enter s2idle even if there are some known issues. 143 144To activate PM debugging, either specify ``pm_debug_messagess`` kernel 145command-line option at boot or write to ``/sys/power/pm_debug_messages``. 146Unmet constraints will be displayed in the kernel log and can be 147viewed by logging tools that process kernel ring buffer like ``dmesg`` or 148``journalctl``." 149 150If the system freezes on entry/exit before these messages are flushed, a 151useful debugging tactic is to unbind the ``amd_pmc`` driver to prevent 152notification to the platform to start s0i3 entry. This will stop the 153system from freezing on entry or exit and let you view all the failed 154constraints. :: 155 156 cd /sys/bus/platform/drivers/amd_pmc 157 ls | grep AMD | sudo tee unbind 158 159After doing this, run the suspend cycle and look specifically for errors around: :: 160 161 ACPI: LPI: Constraint not met; min power state:%s current power state:%s 162 163Historical examples of s2idle issues 164==================================== 165 166To help understand the types of issues that can occur and how to debug them, 167here are some historical examples of s2idle issues that have been resolved. 168 169Core offlining 170-------------- 171An end user had reported that taking a core offline would prevent the system 172from properly entering s0i3. This was debugged using internal AMD tools 173to capture and display a stream of metrics from the hardware showing what changed 174when a core was offlined. It was determined that the hardware didn't get 175notification the offline cores were in the deepest state, and so it prevented 176CPU from going into the deepest state. The issue was debugged to a missing 177command to put cores into C3 upon offline. 178 179`commit d6b88ce2eb9d2 ("ACPI: processor idle: Allow playing dead in C3 state") <https://git.kernel.org/torvalds/c/d6b88ce2eb9d2>`_ 180 181Corruption after resume 182----------------------- 183A big problem that occurred with Rembrandt was that there was graphical 184corruption after resume. This happened because of a misalignment of PSP 185and driver responsibility. The PSP will save and restore DMCUB, but the 186driver assumed it needed to reset DMCUB on resume. 187This actually was a misalignment for earlier silicon as well, but was not 188observed. 189 190`commit 79d6b9351f086 ("drm/amd/display: Don't reinitialize DMCUB on s0ix resume") <https://git.kernel.org/torvalds/c/79d6b9351f086>`_ 191 192Back to Back suspends fail 193-------------------------- 194When using a wakeup source that triggers the IRQ to wakeup, a bug in the 195pinctrl-amd driver may capture the wrong state of the IRQ and prevent the 196system going back to sleep properly. 197 198`commit b8c824a869f22 ("pinctrl: amd: Don't save/restore interrupt status and wake status bits") <https://git.kernel.org/torvalds/c/b8c824a869f22>`_ 199 200Spurious timer based wakeup after 5 minutes 201------------------------------------------- 202The HPET was being used to program the wakeup source for the system, however 203this was causing a spurious wakeup after 5 minutes. The correct alarm to use 204was the ACPI alarm. 205 206`commit 3d762e21d5637 ("rtc: cmos: Use ACPI alarm for non-Intel x86 systems too") <https://git.kernel.org/torvalds/c/3d762e21d5637>`_ 207 208Disk disappears after resume 209---------------------------- 210After resuming from s2idle, the NVME disk would disappear. This was due to the 211BIOS not specifying the _DSD StorageD3Enable property. This caused the NVME 212driver not to put the disk into the expected state at suspend and to fail 213on resume. 214 215`commit e79a10652bbd3 ("ACPI: x86: Force StorageD3Enable on more products") <https://git.kernel.org/torvalds/c/e79a10652bbd3>`_ 216 217Spurious IRQ1 218------------- 219A number of Renoir, Lucienne, Cezanne, & Barcelo platforms have a 220platform firmware bug where IRQ1 is triggered during s0i3 resume. 221 222This was fixed in the platform firmware, but a number of systems didn't 223receive any more platform firmware updates. 224 225`commit 8e60615e89321 ("platform/x86/amd: pmc: Disable IRQ1 wakeup for RN/CZN") <https://git.kernel.org/torvalds/c/8e60615e89321>`_ 226 227Hardware timeout 228---------------- 229The hardware performs many actions besides accepting the values from 230amd-pmc driver. As the communication path with the hardware is a mailbox, 231it's possible that it might not respond quickly enough. 232This issue manifested as a failure to suspend: :: 233 234 PM: dpm_run_callback(): acpi_subsys_suspend_noirq+0x0/0x50 returns -110 235 amd_pmc AMDI0005:00: PM: failed to suspend noirq: error -110 236 237The timing problem was identified by comparing the values of the idle mask. 238 239`commit 3c3c8e88c8712 ("platform/x86: amd-pmc: Increase the response register timeout") <https://git.kernel.org/torvalds/c/3c3c8e88c8712>`_ 240 241Failed to reach hardware sleep state with panel on 242-------------------------------------------------- 243On some Strix systems certain panels were observed to block the system from 244entering a hardware sleep state if the internal panel was on during the sequence. 245 246Even though the panel got turned off during suspend it exposed a timing problem 247where an interrupt caused the display hardware to wake up and block low power 248state entry. 249 250`commit 40b8c14936bd2 ("drm/amd/display: Disable unneeded hpd interrupts during dm_init") <https://git.kernel.org/torvalds/c/40b8c14936bd2>`_ 251 252Runtime power consumption issues 253================================ 254 255Runtime power consumption is influenced by many factors, including but not 256limited to the configuration of the PCIe Active State Power Management (ASPM), 257the display brightness, the EPP policy of the CPU, and the power management 258of the devices. 259 260ASPM 261---- 262For the best runtime power consumption, ASPM should be programmed as intended 263by the BIOS from the hardware vendor. To accomplish this the Linux kernel 264should be compiled with ``CONFIG_PCIEASPM_DEFAULT`` set to ``y`` and the 265sysfs file ``/sys/module/pcie_aspm/parameters/policy`` should not be modified. 266 267Most notably, if L1.2 is not configured properly for any devices, the SoC 268will not be able to enter the deepest idle state. 269 270EPP Policy 271---------- 272The ``energy_performance_preference`` sysfs file can be used to set a bias 273of efficiency or performance for a CPU. This has a direct relationship on 274the battery life when more heavily biased towards performance. 275 276 277BIOS debug messages 278=================== 279 280Most OEM machines don't have a serial UART for outputting kernel or BIOS 281debug messages. However BIOS debug messages are useful for understanding 282both BIOS bugs and bugs with the Linux kernel drivers that call BIOS AML. 283 284As the BIOS on most OEM AMD systems are based off an AMD reference BIOS, 285the infrastructure used for exporting debugging messages is often the same 286as AMD reference BIOS. 287 288Manually Parsing 289---------------- 290There is generally an ACPI method ``\M460`` that different paths of the AML 291will call to emit a message to the BIOS serial log. This method takes 2927 arguments, with the first being a string and the rest being optional 293integers:: 294 295 Method (M460, 7, Serialized) 296 297Here is an example of a string that BIOS AML may call out using ``\M460``:: 298 299 M460 (" OEM-ASL-PCIe Address (0x%X)._REG (%d %d) PCSA = %d\n", DADR, Arg0, Arg1, PCSA, Zero, Zero) 300 301Normally when executed, the ``\M460`` method would populate the additional 302arguments into the string. In order to get these messages from the Linux 303kernel a hook has been added into ACPICA that can capture the *arguments* 304sent to ``\M460`` and print them to the kernel ring buffer. 305For example the following message could be emitted into kernel ring buffer:: 306 307 extrace-0174 ex_trace_args : " OEM-ASL-PCIe Address (0x%X)._REG (%d %d) PCSA = %d\n", ec106000, 2, 1, 1, 0, 0 308 309In order to get these messages, you need to compile with ``CONFIG_ACPI_DEBUG`` 310and then turn on the following ACPICA tracing parameters. 311This can be done either on the kernel command line or at runtime: 312 313* ``acpi.trace_method_name=\M460`` 314* ``acpi.trace_state=method`` 315 316NOTE: These can be very noisy at bootup. If you turn these parameters on 317the kernel command, please also consider turning up ``CONFIG_LOG_BUF_SHIFT`` 318to a larger size such as 17 to avoid losing early boot messages. 319 320Tool assisted Parsing 321--------------------- 322As mentioned above, parsing by hand can be tedious, especially with a lot of 323messages. To help with this, a tool has been created at 324`amd-debug-tools <https://git.kernel.org/pub/scm/linux/kernel/git/superm1/amd-debug-tools.git/about/>`_ 325to help parse the messages. 326 327Random reboot issues 328==================== 329 330When a random reboot occurs, the high-level reason for the reboot is stored 331in a register that will persist onto the next boot. 332 333There are 6 classes of reasons for the reboot: 334 * Software induced 335 * Power state transition 336 * Pin induced 337 * Hardware induced 338 * Remote reset 339 * Internal CPU event 340 341.. csv-table:: 342 :header: "Bit", "Type", "Reason" 343 :align: left 344 345 "0", "Pin", "thermal pin BP_THERMTRIP_L was tripped" 346 "1", "Pin", "power button was pressed for 4 seconds" 347 "2", "Pin", "shutdown pin was tripped" 348 "4", "Remote", "remote ASF power off command was received" 349 "9", "Internal", "internal CPU thermal limit was tripped" 350 "16", "Pin", "system reset pin BP_SYS_RST_L was tripped" 351 "17", "Software", "software issued PCI reset" 352 "18", "Software", "software wrote 0x4 to reset control register 0xCF9" 353 "19", "Software", "software wrote 0x6 to reset control register 0xCF9" 354 "20", "Software", "software wrote 0xE to reset control register 0xCF9" 355 "21", "ACPI-state", "ACPI power state transition occurred" 356 "22", "Pin", "keyboard reset pin KB_RST_L was tripped" 357 "23", "Internal", "internal CPU shutdown event occurred" 358 "24", "Hardware", "system failed to boot before failed boot timer expired" 359 "25", "Hardware", "hardware watchdog timer expired" 360 "26", "Remote", "remote ASF reset command was received" 361 "27", "Internal", "an uncorrected error caused a data fabric sync flood event" 362 "29", "Internal", "FCH and MP1 failed warm reset handshake" 363 "30", "Internal", "a parity error occurred" 364 "31", "Internal", "a software sync flood event occurred" 365 366This information is read by the kernel at bootup and printed into 367the syslog. When a random reboot occurs this message can be helpful 368to determine the next component to debug. 369