amd-debug-tools 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of amd-debug-tools might be problematic. Click here for more details.
- amd_debug/__init__.py +45 -0
- amd_debug/acpi.py +107 -0
- amd_debug/bash/amd-s2idle +89 -0
- amd_debug/battery.py +87 -0
- amd_debug/bios.py +138 -0
- amd_debug/common.py +324 -0
- amd_debug/database.py +331 -0
- amd_debug/failures.py +588 -0
- amd_debug/installer.py +404 -0
- amd_debug/kernel.py +389 -0
- amd_debug/prerequisites.py +1215 -0
- amd_debug/pstate.py +314 -0
- amd_debug/s2idle-hook +72 -0
- amd_debug/s2idle.py +406 -0
- amd_debug/sleep_report.py +453 -0
- amd_debug/templates/html +427 -0
- amd_debug/templates/md +39 -0
- amd_debug/templates/stdout +13 -0
- amd_debug/templates/txt +23 -0
- amd_debug/validator.py +863 -0
- amd_debug/wake.py +111 -0
- amd_debug_tools-0.2.0.dist-info/METADATA +180 -0
- amd_debug_tools-0.2.0.dist-info/RECORD +27 -0
- amd_debug_tools-0.2.0.dist-info/WHEEL +5 -0
- amd_debug_tools-0.2.0.dist-info/entry_points.txt +4 -0
- amd_debug_tools-0.2.0.dist-info/licenses/LICENSE +19 -0
- amd_debug_tools-0.2.0.dist-info/top_level.txt +1 -0
amd_debug/failures.py
ADDED
|
@@ -0,0 +1,588 @@
|
|
|
1
|
+
#!/usr/bin/python3
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
from datetime import timedelta
|
|
5
|
+
from amd_debug.common import print_color
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class S0i3Failure:
|
|
9
|
+
"""Base class for all S0i3 failures"""
|
|
10
|
+
|
|
11
|
+
def __init__(self):
|
|
12
|
+
self.explanation = ""
|
|
13
|
+
self.url = ""
|
|
14
|
+
self.description = ""
|
|
15
|
+
|
|
16
|
+
def get_failure(self):
|
|
17
|
+
"""Prints the failure message"""
|
|
18
|
+
if self.description:
|
|
19
|
+
print_color(self.description, "🚦")
|
|
20
|
+
if self.explanation:
|
|
21
|
+
print(self.explanation)
|
|
22
|
+
if self.url:
|
|
23
|
+
print(f"For more information on this failure see:{self.url}")
|
|
24
|
+
|
|
25
|
+
def get_description(self) -> str:
|
|
26
|
+
"""Returns the description of the failure"""
|
|
27
|
+
return self.description
|
|
28
|
+
|
|
29
|
+
def __str__(self) -> str:
|
|
30
|
+
if self.url:
|
|
31
|
+
url = f"For more information on this failure see:{self.url}"
|
|
32
|
+
else:
|
|
33
|
+
url = ""
|
|
34
|
+
return f"{self.explanation}{url}"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class RtcAlarmWrong(S0i3Failure):
|
|
38
|
+
"""RTC alarm is not configured to use ACPI"""
|
|
39
|
+
|
|
40
|
+
def __init__(self):
|
|
41
|
+
super().__init__()
|
|
42
|
+
self.description = "rtc_cmos is not configured to use ACPI alarm"
|
|
43
|
+
self.explanation = (
|
|
44
|
+
"Some problems can occur during wakeup cycles if the HPET RTC "
|
|
45
|
+
"emulation is used to wake systems. This can manifest in "
|
|
46
|
+
"unexpected wakeups or high power consumption."
|
|
47
|
+
)
|
|
48
|
+
self.url = "https://github.com/systemd/systemd/issues/24279"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class MissingAmdgpu(S0i3Failure):
|
|
52
|
+
"""AMDGPU driver is missing"""
|
|
53
|
+
|
|
54
|
+
def __init__(self):
|
|
55
|
+
super().__init__()
|
|
56
|
+
self.description = "AMDGPU driver is missing"
|
|
57
|
+
self.explanation = (
|
|
58
|
+
"The amdgpu driver is used for hardware acceleration as well "
|
|
59
|
+
"as coordination of the power states for certain IP blocks on the SOC. "
|
|
60
|
+
"Be sure that you have enabled CONFIG_AMDGPU in your kernel."
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class MissingAmdgpuFirmware(S0i3Failure):
|
|
65
|
+
"""AMDGPU firmware is missing"""
|
|
66
|
+
|
|
67
|
+
def __init__(self, errors):
|
|
68
|
+
super().__init__()
|
|
69
|
+
self.description = "AMDGPU firmware is missing"
|
|
70
|
+
self.explanation = (
|
|
71
|
+
"The amdgpu driver loads firmware from /lib/firmware/amdgpu "
|
|
72
|
+
"In some cases missing firmware will prevent a successful "
|
|
73
|
+
"suspend cycle."
|
|
74
|
+
"Upgrade to a newer snapshot at https://gitlab.com/kernel-firmware/linux-firmware"
|
|
75
|
+
)
|
|
76
|
+
self.url = "https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1053856"
|
|
77
|
+
for error in errors:
|
|
78
|
+
self.explanation += f"{error}"
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class AmdgpuPpFeatureMask(S0i3Failure):
|
|
82
|
+
"""AMDGPU ppfeaturemask has been changed"""
|
|
83
|
+
|
|
84
|
+
def __init__(self):
|
|
85
|
+
super().__init__()
|
|
86
|
+
self.description = "AMDGPU ppfeaturemask changed"
|
|
87
|
+
self.explanation = (
|
|
88
|
+
"The ppfeaturemask for the amdgpu driver has been changed "
|
|
89
|
+
"Modifying this from the defaults may cause the system to not "
|
|
90
|
+
"enter hardware sleep."
|
|
91
|
+
)
|
|
92
|
+
self.url = "https://gitlab.freedesktop.org/drm/amd/-/issues/2808#note_2379968"
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class MissingAmdPmc(S0i3Failure):
|
|
96
|
+
"""AMD-PMC driver is missing"""
|
|
97
|
+
|
|
98
|
+
def __init__(self):
|
|
99
|
+
super().__init__()
|
|
100
|
+
self.description = "AMD-PMC driver is missing"
|
|
101
|
+
self.explanation = (
|
|
102
|
+
"The amd-pmc driver is required for the kernel to instruct the "
|
|
103
|
+
"soc to enter the hardware sleep state. "
|
|
104
|
+
"Be sure that you have enabled CONFIG_AMD_PMC in your kernel. "
|
|
105
|
+
""
|
|
106
|
+
"If CONFIG_AMD_PMC is enabled but the amd-pmc driver isn't loading "
|
|
107
|
+
"then you may have found a bug and should report it."
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class MissingThunderbolt(S0i3Failure):
|
|
112
|
+
"""Thunderbolt driver is missing"""
|
|
113
|
+
|
|
114
|
+
def __init__(self):
|
|
115
|
+
super().__init__()
|
|
116
|
+
self.description = "thunderbolt driver is missing"
|
|
117
|
+
self.explanation = (
|
|
118
|
+
"The thunderbolt driver is required for the USB4 routers included "
|
|
119
|
+
"with the SOC to enter the proper power states. "
|
|
120
|
+
"Be sure that you have enabled CONFIG_USB4 in your kernel."
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
class MissingXhciHcd(S0i3Failure):
|
|
125
|
+
"""xhci_hcd driver is missing"""
|
|
126
|
+
|
|
127
|
+
def __init__(self):
|
|
128
|
+
super().__init__()
|
|
129
|
+
self.description = "xhci_hcd driver is missing"
|
|
130
|
+
self.explanation = (
|
|
131
|
+
"The xhci_hcd driver is required for the USB3 controllers included "
|
|
132
|
+
"with the SOC to enter the proper power states. "
|
|
133
|
+
"Be sure that you have enabled CONFIG_XHCI_PCI in your kernel."
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class MissingDriver(S0i3Failure):
|
|
138
|
+
"""driver is missing"""
|
|
139
|
+
|
|
140
|
+
def __init__(self, slot):
|
|
141
|
+
super().__init__()
|
|
142
|
+
self.description = f"{slot} driver is missing"
|
|
143
|
+
self.explanation = (
|
|
144
|
+
f"No driver has been bound to PCI device {slot} "
|
|
145
|
+
"Without a driver, the hardware may be able to enter a low power. "
|
|
146
|
+
"state, but there may be spurious wake up events."
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
class AcpiBiosError(S0i3Failure):
|
|
151
|
+
"""ACPI BIOS errors detected"""
|
|
152
|
+
|
|
153
|
+
def __init__(self, errors):
|
|
154
|
+
super().__init__()
|
|
155
|
+
self.description = "ACPI BIOS Errors detected"
|
|
156
|
+
self.explanation = (
|
|
157
|
+
"When running a firmware component utilized for s2idle "
|
|
158
|
+
"the ACPI interpreter in the Linux kernel encountered some "
|
|
159
|
+
"problems. This usually means it's a bug in the system BIOS "
|
|
160
|
+
"that should be fixed the system manufacturer."
|
|
161
|
+
""
|
|
162
|
+
"You may have problems with certain devices after resume or high "
|
|
163
|
+
"power consumption when this error occurs."
|
|
164
|
+
)
|
|
165
|
+
for error in errors:
|
|
166
|
+
self.explanation += f"{error}"
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
class UnsupportedModel(S0i3Failure):
|
|
170
|
+
"""Unsupported CPU model"""
|
|
171
|
+
|
|
172
|
+
def __init__(self):
|
|
173
|
+
super().__init__()
|
|
174
|
+
self.description = "Unsupported CPU model"
|
|
175
|
+
self.explanation = (
|
|
176
|
+
"This model does not support hardware s2idle. "
|
|
177
|
+
"Attempting to run s2idle will use a pure software suspend "
|
|
178
|
+
"and will not yield tangible power savings."
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
class UserNvmeConfiguration(S0i3Failure):
|
|
183
|
+
"""User has disabled NVME ACPI support"""
|
|
184
|
+
|
|
185
|
+
def __init__(self):
|
|
186
|
+
super().__init__()
|
|
187
|
+
self.description = "NVME ACPI support is disabled"
|
|
188
|
+
self.explanation = (
|
|
189
|
+
"The kernel command line has been configured to not support "
|
|
190
|
+
"NVME ACPI support. This is required for the NVME device to "
|
|
191
|
+
"enter the proper power state."
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
class AcpiNvmeStorageD3Enable(S0i3Failure):
|
|
196
|
+
"""NVME device is missing ACPI attributes"""
|
|
197
|
+
|
|
198
|
+
def __init__(self, disk, num_ssds):
|
|
199
|
+
super().__init__()
|
|
200
|
+
self.description = f"{disk} missing ACPI attributes"
|
|
201
|
+
self.explanation = (
|
|
202
|
+
"An NVME device was found, but it doesn't specify the StorageD3Enable "
|
|
203
|
+
"attribute in the device specific data (_DSD). "
|
|
204
|
+
"This is a BIOS bug, but it may be possible to work around in the kernel. "
|
|
205
|
+
)
|
|
206
|
+
if num_ssds > 1:
|
|
207
|
+
self.explanation += (
|
|
208
|
+
""
|
|
209
|
+
"If you added an aftermarket SSD to your system, the system vendor might not have added this "
|
|
210
|
+
"property to the BIOS for the second port which could cause this behavior. "
|
|
211
|
+
""
|
|
212
|
+
"Please re-run this script with the --acpidump argument and file a bug to "
|
|
213
|
+
"investigate."
|
|
214
|
+
)
|
|
215
|
+
self.url = "https://bugzilla.kernel.org/show_bug.cgi?id=216440"
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
class DevSlpHostIssue(S0i3Failure):
|
|
219
|
+
"""AHCI controller doesn't support DevSlp"""
|
|
220
|
+
|
|
221
|
+
def __init__(self):
|
|
222
|
+
super().__init__()
|
|
223
|
+
self.description = "AHCI controller doesn't support DevSlp"
|
|
224
|
+
self.explanation = (
|
|
225
|
+
"The AHCI controller is not configured to support DevSlp. "
|
|
226
|
+
"This must be enabled in BIOS for s2idle in Linux."
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
class DevSlpDiskIssue(S0i3Failure):
|
|
231
|
+
"""SATA disk doesn't support DevSlp"""
|
|
232
|
+
|
|
233
|
+
def __init__(self):
|
|
234
|
+
super().__init__()
|
|
235
|
+
self.description = "SATA disk doesn't support DevSlp"
|
|
236
|
+
self.explanation = (
|
|
237
|
+
"The SATA disk does not support DevSlp. "
|
|
238
|
+
"s2idle in Linux requires SATA disks that support this feature."
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
class SleepModeWrong(S0i3Failure):
|
|
243
|
+
"""System is not configured for Modern Standby"""
|
|
244
|
+
|
|
245
|
+
def __init__(self):
|
|
246
|
+
super().__init__()
|
|
247
|
+
self.description = (
|
|
248
|
+
"The system hasn't been configured for Modern Standby in BIOS setup"
|
|
249
|
+
)
|
|
250
|
+
self.explanation = (
|
|
251
|
+
"AMD systems must be configured for Modern Standby in BIOS setup "
|
|
252
|
+
"for s2idle to function properly in Linux. "
|
|
253
|
+
"On some OEM systems this is referred to as 'Windows' sleep mode. "
|
|
254
|
+
"If the BIOS is configured for S3 and you manually select s2idle "
|
|
255
|
+
"in /sys/power/mem_sleep, the system will not enter the deepest hardware state."
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
class DeepSleep(S0i3Failure):
|
|
260
|
+
"""Deep sleep is configured on the kernel command line"""
|
|
261
|
+
|
|
262
|
+
def __init__(self):
|
|
263
|
+
super().__init__()
|
|
264
|
+
self.description = (
|
|
265
|
+
"The kernel command line is asserting the system to use deep sleep"
|
|
266
|
+
)
|
|
267
|
+
self.explanation = (
|
|
268
|
+
"Adding mem_sleep_default=deep doesn't work on AMD systems. "
|
|
269
|
+
"Please remove it from the kernel command line."
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
class FadtWrong(S0i3Failure):
|
|
274
|
+
"""FADT doesn't support low power idle"""
|
|
275
|
+
|
|
276
|
+
def __init__(self):
|
|
277
|
+
super().__init__()
|
|
278
|
+
self.description = (
|
|
279
|
+
"The kernel didn't emit a message that low power idle was supported"
|
|
280
|
+
)
|
|
281
|
+
self.explanation = (
|
|
282
|
+
"Low power idle is a bit documented in the FADT to indicate that "
|
|
283
|
+
"low power idle is supported. "
|
|
284
|
+
"Only newer kernels support emitting this message, so if you run on "
|
|
285
|
+
"an older kernel you may get a false negative. "
|
|
286
|
+
"When launched as root this script will try to directly introspect the "
|
|
287
|
+
"ACPI tables to confirm this."
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
class Irq1Workaround(S0i3Failure):
|
|
292
|
+
"""IRQ1 wakeup source is active"""
|
|
293
|
+
|
|
294
|
+
def __init__(self):
|
|
295
|
+
super().__init__()
|
|
296
|
+
self.description = "The wakeup showed an IRQ1 wakeup source, which might be a platform firmware bug"
|
|
297
|
+
self.explanation = (
|
|
298
|
+
"A number of Renoir, Lucienne, Cezanne, & Barcelo platforms have a platform firmware "
|
|
299
|
+
"bug where IRQ1 is triggered during s0i3 resume. "
|
|
300
|
+
"You may have tripped up on this bug as IRQ1 was active during resume. "
|
|
301
|
+
"If you didn't press a keyboard key to wakeup the system then this can be "
|
|
302
|
+
"the cause of spurious wakeups."
|
|
303
|
+
""
|
|
304
|
+
"To fix it, first try to upgrade to the latest firmware from your manufacturer. "
|
|
305
|
+
"If you're already upgraded to the latest firmware you can use one of two workarounds: "
|
|
306
|
+
" 1. Manually disable wakeups from IRQ1 by running this command each boot: "
|
|
307
|
+
" echo 'disabled' | sudo tee /sys/bus/serio/devices/serio0/power/wakeup "
|
|
308
|
+
" 2. Use the below linked patch in your kernel."
|
|
309
|
+
)
|
|
310
|
+
self.url = "https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/drivers/platform/x86/amd/pmc.c?id=8e60615e8932167057b363c11a7835da7f007106"
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
class KernelRingBufferWrapped(S0i3Failure):
|
|
314
|
+
"""Kernel ringbuffer has wrapped"""
|
|
315
|
+
|
|
316
|
+
def __init__(self):
|
|
317
|
+
super().__init__()
|
|
318
|
+
self.description = "Kernel ringbuffer has wrapped"
|
|
319
|
+
self.explanation = (
|
|
320
|
+
"This script relies upon analyzing the kernel log for markers. "
|
|
321
|
+
"The kernel's log provided by dmesg uses a ring buffer. "
|
|
322
|
+
"When the ring buffer fills up it will wrap around and overwrite old messages. "
|
|
323
|
+
""
|
|
324
|
+
"In this case it's not possible to look for some of these markers "
|
|
325
|
+
""
|
|
326
|
+
"Passing the pre-requisites check won't be possible without rebooting the machine. "
|
|
327
|
+
"If you are sure your system meets pre-requisites, you can re-run the script using. "
|
|
328
|
+
"the systemd logger or with --force."
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
class AmdHsmpBug(S0i3Failure):
|
|
333
|
+
"""AMD HSMP is built into the kernel"""
|
|
334
|
+
|
|
335
|
+
def __init__(self):
|
|
336
|
+
super().__init__()
|
|
337
|
+
self.description = "amd-hsmp built in to kernel"
|
|
338
|
+
self.explanation = (
|
|
339
|
+
"The kernel has been compiled with CONFIG_AMD_HSMP=y. "
|
|
340
|
+
"This has been shown to cause suspend failures on some systems. "
|
|
341
|
+
""
|
|
342
|
+
"Either recompile the kernel without CONFIG_AMD_HSMP, "
|
|
343
|
+
"or use initcall_blacklist=hsmp_plt_init on your kernel command line to avoid triggering problems "
|
|
344
|
+
""
|
|
345
|
+
)
|
|
346
|
+
self.url = "https://gitlab.freedesktop.org/drm/amd/-/issues/2414"
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
class WCN6855Bug(S0i3Failure):
|
|
350
|
+
"""WCN6855 firmware causes spurious wakeups"""
|
|
351
|
+
|
|
352
|
+
def __init__(self):
|
|
353
|
+
super().__init__()
|
|
354
|
+
self.description = "The firmware loaded for the WCN6855 causes spurious wakeups"
|
|
355
|
+
self.explanation = (
|
|
356
|
+
"During s2idle on AMD systems PCIe devices are put into D3cold. During wakeup they're transitioned back "
|
|
357
|
+
"into the state they were before s2idle. For many implementations this is D3hot. "
|
|
358
|
+
"If an ACPI event has been triggered by the EC, the hardware will resume from s2idle, "
|
|
359
|
+
"but the kernel should process the event and then put it back into s2idle. "
|
|
360
|
+
""
|
|
361
|
+
"When this bug occurs, a GPIO connected to the WLAN card is active on the system making "
|
|
362
|
+
"he GPIO controller IRQ also active. The kernel sees that the ACPI event IRQ and GPIO "
|
|
363
|
+
"controller IRQ are both active and resumes the system. "
|
|
364
|
+
""
|
|
365
|
+
"Some non-exhaustive events that will trigger this behavior: "
|
|
366
|
+
" * Suspending the system and then closing the lid. "
|
|
367
|
+
" * Suspending the system and then unplugging the AC adapter. "
|
|
368
|
+
" * Suspending the system and the EC notifying the OS of a battery level change. "
|
|
369
|
+
""
|
|
370
|
+
"This issue is fixed by updated WCN6855 firmware which will avoid triggering the GPIO. "
|
|
371
|
+
"The version string containing the fix is 'WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23' "
|
|
372
|
+
)
|
|
373
|
+
self.url = "https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/commit/?id=c7a57ef688f7d99d8338a5d8edddc8836ff0e6de"
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
class I2CHidBug(S0i3Failure):
|
|
377
|
+
"""I2C HID device causes spurious wakeups"""
|
|
378
|
+
|
|
379
|
+
def __init__(self, name, remediation):
|
|
380
|
+
super().__init__()
|
|
381
|
+
self.description = f"The {name} device has been reported to cause high power consumption and spurious wakeups"
|
|
382
|
+
self.explanation = (
|
|
383
|
+
"I2C devices work in an initiator/receiver relationship where the device is the receiver. In order for the receiver to indicate "
|
|
384
|
+
"the initiator needs to read data they will assert an attention GPIO pin. "
|
|
385
|
+
"When a device misbehaves it may assert this pin spuriously which can cause the SoC to wakeup prematurely. "
|
|
386
|
+
"This typically manifests as high power consumption at runtime and spurious wakeups at suspend. "
|
|
387
|
+
""
|
|
388
|
+
"This issue can be worked around by unbinding the device from the kernel using this command: "
|
|
389
|
+
""
|
|
390
|
+
f"{remediation}"
|
|
391
|
+
""
|
|
392
|
+
"To fix this issue permanently the kernel will need to avoid binding to this device. "
|
|
393
|
+
)
|
|
394
|
+
self.url = "https://gitlab.freedesktop.org/drm/amd/-/issues/2812"
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
class SpuriousWakeup(S0i3Failure):
|
|
398
|
+
"""System woke up prematurely"""
|
|
399
|
+
|
|
400
|
+
def __init__(self, requested, wake):
|
|
401
|
+
super().__init__()
|
|
402
|
+
self.description = (
|
|
403
|
+
f"Userspace wasn't asleep at least {timedelta(seconds=requested)}"
|
|
404
|
+
)
|
|
405
|
+
self.explanation = (
|
|
406
|
+
f"The system was programmed to sleep for {timedelta(seconds=requested)}, but woke up prematurely after {wake}. "
|
|
407
|
+
"This typically happens when the system was woken up from a non-timer based source. "
|
|
408
|
+
"If you didn't intentionally wake it up, then there may be a kernel or firmware bug."
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
class LowHardwareSleepResidency(S0i3Failure):
|
|
413
|
+
"""System had low hardware sleep residency"""
|
|
414
|
+
|
|
415
|
+
def __init__(self, duration, percent):
|
|
416
|
+
super().__init__()
|
|
417
|
+
self.description = "System had low hardware sleep residency"
|
|
418
|
+
self.explanation = (
|
|
419
|
+
f"The system was asleep for {timedelta(seconds=duration)}, but only spent {percent:.2%} "
|
|
420
|
+
"of this time in a hardware sleep state. In sleep cycles that are at least "
|
|
421
|
+
"60 seconds long it's expected you spend above 90 percent of the cycle in "
|
|
422
|
+
"hardware sleep."
|
|
423
|
+
)
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
class MSRFailure(S0i3Failure):
|
|
427
|
+
"""MSR access failed"""
|
|
428
|
+
|
|
429
|
+
def __init__(self):
|
|
430
|
+
super().__init__()
|
|
431
|
+
self.description = "PC6 or CC6 state disabled"
|
|
432
|
+
self.explanation = (
|
|
433
|
+
"The PC6 state of the package or the CC6 state of CPU cores was disabled. "
|
|
434
|
+
"This will prevent the system from getting to the deepest sleep state over suspend."
|
|
435
|
+
)
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
class TaintedKernel(S0i3Failure):
|
|
439
|
+
"""Kernel is tainted"""
|
|
440
|
+
|
|
441
|
+
def __init__(self):
|
|
442
|
+
super().__init__()
|
|
443
|
+
self.description = "Kernel is tainted"
|
|
444
|
+
self.explanation = (
|
|
445
|
+
"A tainted kernel may exhibit unpredictable bugs that are difficult for this script to characterize. "
|
|
446
|
+
"If this is intended behavior run the tool with --force. "
|
|
447
|
+
)
|
|
448
|
+
self.url = "https://gitlab.freedesktop.org/drm/amd/-/issues/3089"
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
class DMArNotEnabled(S0i3Failure):
|
|
452
|
+
"""DMAr is not enabled"""
|
|
453
|
+
|
|
454
|
+
def __init__(self):
|
|
455
|
+
super().__init__()
|
|
456
|
+
self.description = "Pre-boot DMA protection disabled"
|
|
457
|
+
self.explanation = (
|
|
458
|
+
"Pre-boot IOMMU DMA protection has been disabled. "
|
|
459
|
+
"When the IOMMU is enabled this platform requires pre-boot DMA protection for suspend to work. "
|
|
460
|
+
)
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
class MissingIommuACPI(S0i3Failure):
|
|
464
|
+
"""IOMMU ACPI table errors"""
|
|
465
|
+
|
|
466
|
+
def __init__(self, device):
|
|
467
|
+
super().__init__()
|
|
468
|
+
self.description = f"Device {device} missing from ACPI tables"
|
|
469
|
+
self.explanation = (
|
|
470
|
+
"The ACPI device {device} is required for suspend to work when the IOMMU is enabled. "
|
|
471
|
+
"Please check your BIOS settings and if configured correctly, report a bug to your system vendor."
|
|
472
|
+
)
|
|
473
|
+
self.url = "https://gitlab.freedesktop.org/drm/amd/-/issues/3738#note_2667140"
|
|
474
|
+
|
|
475
|
+
|
|
476
|
+
class MissingIommuPolicy(S0i3Failure):
|
|
477
|
+
"""ACPI table errors"""
|
|
478
|
+
|
|
479
|
+
def __init__(self, device):
|
|
480
|
+
super().__init__()
|
|
481
|
+
self.description = f"Device {device} does not have IOMMU policy applied"
|
|
482
|
+
self.explanation = (
|
|
483
|
+
f"The ACPI device {device} is present but no IOMMU policy was set for it."
|
|
484
|
+
"This generally happens if the HID or UID don't match the ACPI IVRS table."
|
|
485
|
+
)
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
class IommuPageFault(S0i3Failure):
|
|
489
|
+
"""IOMMU Page fault"""
|
|
490
|
+
|
|
491
|
+
def __init__(self, device):
|
|
492
|
+
super().__init__()
|
|
493
|
+
self.description = f"Page fault reported for {device}"
|
|
494
|
+
self.explanation = (
|
|
495
|
+
f"The IOMMU reports a page fault caused by {device}. This can prevent suspend/resume from functioning properly"
|
|
496
|
+
"The page fault can be the device itself, a problem in the firmware or a problem in the kernel."
|
|
497
|
+
"Report a bug for further triage and investigation."
|
|
498
|
+
)
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
class SMTNotEnabled(S0i3Failure):
|
|
502
|
+
"""SMT is not enabled"""
|
|
503
|
+
|
|
504
|
+
def __init__(self):
|
|
505
|
+
super().__init__()
|
|
506
|
+
self.description = "SMT is not enabled"
|
|
507
|
+
self.explanation = (
|
|
508
|
+
"Disabling SMT prevents cores from going into the correct state."
|
|
509
|
+
)
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
class ASpmWrong(S0i3Failure):
|
|
513
|
+
"""ASPM is overridden"""
|
|
514
|
+
|
|
515
|
+
def __init__(self):
|
|
516
|
+
super().__init__()
|
|
517
|
+
self.description = "ASPM is overridden"
|
|
518
|
+
self.explanation = (
|
|
519
|
+
" Modifying ASPM may prevent PCIe devices from going into the "
|
|
520
|
+
" correct state and lead to system stability issues. "
|
|
521
|
+
)
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
class UnservicedGpio(S0i3Failure):
|
|
525
|
+
"""GPIO is not serviced"""
|
|
526
|
+
|
|
527
|
+
def __init__(self):
|
|
528
|
+
super().__init__()
|
|
529
|
+
self.description = "GPIO interrupt is not serviced"
|
|
530
|
+
self.explanation = (
|
|
531
|
+
"All GPIO controllers interrupts must be serviced to enter "
|
|
532
|
+
"hardware sleep."
|
|
533
|
+
"Make sure that all drivers necessary to service GPIOs are loaded. "
|
|
534
|
+
"The most common cause is that i2c-hid-acpi is not loaded but the "
|
|
535
|
+
"machine contains an I2C touchpad."
|
|
536
|
+
)
|
|
537
|
+
|
|
538
|
+
|
|
539
|
+
class DmiNotSetup(S0i3Failure):
|
|
540
|
+
"""DMI isn't setup"""
|
|
541
|
+
|
|
542
|
+
def __init__(self):
|
|
543
|
+
super().__init__()
|
|
544
|
+
self.description = "DMI data was not scanned"
|
|
545
|
+
self.explanation = (
|
|
546
|
+
"If DMI data hasn't been scanned then quirks that are dependent "
|
|
547
|
+
"upon DMI won't be loaded. "
|
|
548
|
+
"Most notably, this will prevent the rtc-cmos driver from setting. "
|
|
549
|
+
"up properly by default. It may also prevent other drivers from working."
|
|
550
|
+
)
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
class LimitedCores(S0i3Failure):
|
|
554
|
+
"""Number of CPU cores limited"""
|
|
555
|
+
|
|
556
|
+
def __init__(self, actual_cores, max_cores):
|
|
557
|
+
super().__init__()
|
|
558
|
+
self.description = "CPU cores have been limited"
|
|
559
|
+
self.explanation = (
|
|
560
|
+
f"The CPU cores have been limited to {max_cores}, but the system "
|
|
561
|
+
f"actually has {actual_cores}. Limiting the cores will prevent the "
|
|
562
|
+
"the system from going into a hardware sleep state. "
|
|
563
|
+
"This is typically solved by increasing the kernel config CONFIG_NR_CPUS."
|
|
564
|
+
)
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
class RogAllyOldMcu(S0i3Failure):
|
|
568
|
+
"""MCU firwmare is too old"""
|
|
569
|
+
|
|
570
|
+
def __init__(self, vmin, actual):
|
|
571
|
+
super().__init__()
|
|
572
|
+
self.description = "Rog Ally MCU firmware is too old"
|
|
573
|
+
self.explanation = (
|
|
574
|
+
f"The MCU is version {actual}, but needs to be at least {vmin}"
|
|
575
|
+
f"to avoid major issues with interactions with suspend"
|
|
576
|
+
)
|
|
577
|
+
|
|
578
|
+
|
|
579
|
+
class RogAllyMcuPowerSave(S0i3Failure):
|
|
580
|
+
"""MCU powersave is disabled"""
|
|
581
|
+
|
|
582
|
+
def __init__(self):
|
|
583
|
+
super().__init__()
|
|
584
|
+
self.description = "Rog Ally MCU power save is disabled"
|
|
585
|
+
self.explanation = (
|
|
586
|
+
"The MCU powersave feature is disabled which will cause problems "
|
|
587
|
+
"with the controller after suspend/resume."
|
|
588
|
+
)
|