Prior to BIOS version 1.34, the Lenovo X1 Yoga (3rd Gen) (X1YG3) BIOS did not expose support for Suspend-to-Ram (S3). Instead, it exposed only Modern Standby (Si03) which is a low-power idle approach to suspend. Unfortunately, Linux does not currently provide good support for Modern Standby which leads to awful power drain when trying to put the X1YG3 to sleep.
Thankfully, Lenovo finally added S3 support in BIOS 1.34 and I can report that it works correctly. The instructions to patch your DSDT to enable S3 can still be found below but as of 1.34 this is no longer necessary. If you're running a prior BIOS version you may still find the instructions helpful.
You may still need to configure deep sleep as the default so review the Make sleep default to deep section. You may also want to review the Potential issues section which provides fixes for some common issues related to sleep but unrelated to the BIOS S3 support.
No new functionality but includes a security fix and resolves a problem with
Thunderbolt docks. S3
support remains the same as in BIOS 1.34
and works as expected. This from the release notes:
[Important updates]
- Update includes a security fix.
[New functions or enhancements] Nothing.
[Problem fixes]
- Fixed an issue where system may enter shutdown after press power button of Thunderbolt 3 Dock Gen2/Thunderbolt 3 Workstation Dock to resume sleep state.
It adds no new functionality or fixes but renames the "Modern Standby" setting
added in BIOS 1.34 to "Sleep State" and changes the values to "Linux" and
"Windows 10". S3
support remains the same as in BIOS 1.34 and
works as expected. This from the release notes:
[Important updates] Nothing.
[New functions or enhancements] Nothing.
[Problem fixes]
- Change Setup item wording from "Modern Standby" to "Sleep State" in ThinkPad Setup - Config - Power. (Note) "Linux" option is optimized for Linux OS, Windows user must select "Windows 10" option.
As with 1.34, I have left Sleep State->Windows 10
(same as Modern Standby->Enabled
) and have proper S3
support in Linux and proper Modern
Standby support retained in Windows 10 (dual-boot).
It adds a new BIOS setting under Config > Power
called "Modern Standby" which
is enabled
by default. This from the release
notes:
- (New) Support Optimized Sleep State for Modern Standby in ThinkPad Setup - Config - Power. (Note) "Enabled" selection is optimized for Windows OS, "Disabled" selection is optimized for Linux OS.
However, my experience has been that there is no need to change this setting to
enable S3 in Linux. Simply leave it set to enabled
, boot into Linux, and
confirm that S3 is supported. You can change the
"Modern Standby" setting to disabled
but it seems to have no bearing S3
support in Linux. Also, I dual-boot and don't want to re-install Windows (see
below) so I leave Modern Standby
enabled
.
If you dual-boot Linux & Windows, you may want to leave the Modern Standby alone as Microsoft claims that you can't enable S3 support with a BIOS setting:
You cannot switch between S3 and Modern Standby by changing a setting in the BIOS. Switching the power model is not supported in Windows without a complete OS re-install.
Some X1YG3 users have claimed that S3 works fine in Windows without a re-install after disabling "Modern Standby" but I haven't tested this myself.
These instructions are for Fedora but hopefully they can at least be a helpful guide for other distributions.
This should go without saying, but if you follow this guide you are responsible for any damage you do to your machine. These instructions worked for me and I have no reason to believe they will cause problems but proceed at your own risk.
If you see SecureBoot disabled
after running the following command, you're all
set. If you don't, you need to disable SecureBoot in the BIOS.
mokutil --sb-state # should display SecureBoot disabled
dmesg | grep "ACPI: (supports"
This command should return something like ACPI: (supports S0 S4 S5)
which as
you can see is missing S3 support.
which iasl
Should return the path to iasl
like /usr/bin/iasl
. If it is not
installed, you can install it with:
sudo dnf install acpica-tools
sudo dmidecode -s bios-version
Should return something like N25ET44W (1.30 )
. These instructions were
written with BIOS version 1.30
.
If dmidecode
is missing, you can install it with:
sudo dnf dmidecode
git clone https://github.com/zachsmith/x1yg3-suspend-to-ram.git
cd x1yg3-suspend-to-ram
sudo cat /sys/firmware/acpi/tables/DSDT > dsdt.dat
This will produce a dsdt.dsl file:
iasl -d dsdt.dat
patch --verbose < x1yg3-s3-override.patch
The output should look something like this:
--------------------------
|--- dsdt.dsl 2019-05-05 21:42:46.137486914 -0700
|+++ dsdt.dsl 2019-05-05 21:45:23.489591442 -0700
--------------------------
patching file dsdt.dsl
Using Plan A...
Hunk #1 succeeded at 21.
Hunk #2 succeeded at 265.
Hunk #3 succeeded at 266.
Hunk #4 succeeded at 27770.
done
If this patch fails to apply, please open an issue and be sure to include your dsdt.dst file and the version of your BIOS.
This will produce a dsdt.aml file:
iasl -tc -ve dsdt.dsl
We are going to utilize dracut
which is used by Fedora (and numerous other
distributions) to build initramfs images. dracut
allows you to provide
overridden ACPI tables to build into an image which is exactly what we need.
This approach will include our updated tables in future initramfs images
generated automatically (by kernel updates) or manually (like we'll do here).
sudo mkdir /boot/acpi_override
sudo cp dsdt.aml /boot/acpi_override/x1yg3-s3-override.aml
Create /etc/dracut.conf.d/acpi.conf
and add the following lines:
acpi_override="yes"
acpi_table_dir="/boot/acpi_override"
Update the initramfs image for your current kernel.
cd /boot
sudo dracut --force initramfs-$(uname -r).img
First, look at your current mem_sleep
values
cat /sys/power/mem_sleep
Which should return [s2idle]
. We want to make sure that deep
(S3) becomes
the default. To do that, we need to pass a parameter to the kernel at boot time
which we can do by editing our grub
configuration. This change will insure that
future kernels will also receive this parameter at boot.
Append the following to the end of the string defined by GRUB_CMDLINE_LINUX
:
mem_sleep_default=deep
sudo grub2-mkconfig -o /boot/efi/EFI/fedora/grub.cfg
At this point you should have patched your DSDT, rebuilt your initramfs
for
your current kernel, and rebuilt your grub
configuration. You should be ready
to reboot your computer to check that everything works.
Note: If you haven't already disabled secure boot, make sure to do it now before your system boots with the overridden DSDT table.
dmesg | grep "ACPI: (supports"
It should now display ACPI: (supports S0 S3 S4 S5)
which includes S3. This
means that your patched DSDT loaded.
cat /sys/power/mem_sleep
This should now display s2idle [deep]
(the []
's indicate default). This means
that your grub
configuration passed the parameter to the kernel at boot.
Go ahead and enjoy the convenience of putting your computer to sleep!
You may still encounter suspend related issues. Here are some I've encountered and fixes where I have them.
- PM: Device 0000:00:14.0 failed to suspend async: error -16
- Touchscreen or stylus unresponsive after resume from suspend
- Ghost/Phantom touch events
- /sys/class/rtc/rtc0/wakealarm: Device or resource busy
- Fan not working
If you see errors like these in your journal
, it may be related to a problem
suspending your XHCI controller:
pci_pm_suspend(): hcd_pci_suspend+0x0/0x30 returns -16
dpm_run_callback(): pci_pm_suspend+0x0/0x120 returns -16
PM: Device 0000:00:14.0 failed to suspend async: error -16
PM: Some devices failed to suspend, or early wake event detected
I found this great
hack
and made a few modifications and improvements in the xhci.sh
script included
in this repo. You can have systemd run this script at pre
and post
suspend
by placing it in the /usr/lib/systemd/system-sleep
directory. I encourage your
to read and understand the script before installing it as it will run with root
privileges. Read more about this in the systemd-suspend man page.
cp xhci.sh /usr/lib/systemd/system-sleep
The Wacom touchscreen is often unresponsive after resuming from sleep.
A user discovered that when waking from s2idle
, the touchscreen worked
correctly and posted this clever solution in a Lenovo forum
post
which makes use of rtcwake
triggered by a systemd
oneshot
service after
suspend.target
. I modified it to also trigger after suspend-then-hibernate.target
and hibernate.target
. This will add a slight delay to the resume so you may
only want to enable this if you like having the touch display working.
sudo cp wake_wacom_hack.service /etc/systemd/system/`
sudo systemctl enable wake_wacom_hack.service
An alternative is to just disable the touchscreen and not worry about it resuming after wake. You may prefer to do this if you are also experiencing ghost/phantom touch issues. See the next section...
Unfortunately, I've experienced a lot of ghost/phantom touch events on my X1YG3 and it
can get pretty irritating. Because I typically don't use the touchscreen, I went
ahead and just disabled it using a custom udev
rule. It's disappointing that there
are issues with the touchscreen since that is one of the key features of the
X1YG3 but I prefer not having phantom touch events to having a touchscreen that
I use very infrequently.
sudo cp 99-x1yg3-touchscreen.rules /etc/udev/rules.d/
sudo udevadm trigger --verbose --type=devices --attr-match=idVendor=056a --attr-match=idProduct=5146
You can always re-enable by editing 99-x1yg3-touchscreen.rules
and setting
ATTR{authorized}="1"
before running the udevadm trigger
command listed
above. Alternatively, I wrote a little
script to
toggle the enable/disable the touchscreen by automating the editing of the rule file
and invoking the trigger but I'm not convinced this is the right approach.
If you plan to disable your touch screen entirely you don't need to use the
wake_wacom_hack.service
described above.
UPDATE: The fix for this issue is available in systemd
243. Check the version of systemd
installed with your distribution: systemctl --version
UPDATE: This issue should be fixed with PR
#12591 and should be in a future
version of systemd
. The PR removes the dependency on rtc wakealarm and uses
CLOCK_BOOTTIME_ALARM
instead thus eliminating the error trying to write to
/sys/class/rtc/rtc0/wakealarm
when a pre-existing alarm is already set.
If you use suspend-then-hibernate
you may encounter a situation where your
system will not properly suspend. This can be caused by an error writing to the
/sys/class/rtc/rtc0/wakealarm
. You'll see something like this in your journal
:
Failed to write '1557511414' to /sys/class/rtc/rtc0/wakealarm: Device or resource busy
systemd-suspend-then-hibernate.service: Main process exited, code=exited, status=1/FAILURE
systemd-suspend-then-hibernate.service: Failed with result 'exit-code'.
Failed to start Suspend; Hibernate if not used for a period of time.
Dependency failed for Suspend; Hibernate if not used for a period of time.
suspend-then-hibernate.target: Job suspend-then-hibernate.target/start failed with result 'dependency'.
Stopped target Sleep.
This happens because there is a value already
present in the wakealarm
and a new value cannot be written until the timer has
triggered or has been reset. In general, I am more concerned with my computer
suspending properly than any other random wakealarm scheduled by the system or
firmware and this has been the most vexing suspend problem I have faced. The
solution I came up with is inspired by the touchscreen fix above; use a systemd
oneshot
service to fire before suspend-then-hibernate
target and reset the
wakealarm
.
sudo cp wakealarm-reset.service /etc/systemd/system/`
sudo systemctl enable wakealarm-reset.service
Of course, this is only relevant if you're making use of
suspend-then-hibernate
which was added in version
239 of
systemd.
I opened an issue with
systemd
to track getting a fix for this
Thinkpads are notoriously problematic when it comes to getting the fans to work.
Thankfully, there is a the thinkfan
package that can be installed and
configured to make sure your computer stays cool.
sudo dnf install lm_sensors thinkfan
Next, detect the sensors and reload kernel modules that are needed after detection:
sudo sensors-detect --auto
systemctl restart systemd-modules-load
You'll need to create a configuration file in /etc/thinkfan.conf
with
information about your sensors. Originally, I did this manually by running
find /sys/devices -type f -name 'temp*_input'
and using the values in /etc/thinkfile.conf
but I realized that the values can
change and kernel modules can be loaded in inconsistent orders. This can
result in thinkfan
crashing or failing to start. I found this
gist with some
great notes and ideas for configuring thinkfan
on an X1 Carbon Gen 5 and
adapted them a bit for my X1YG3. The configurations and modified script I used
are in the thinkfan
directory of this repo. Inside you will find a script that
generates the /etc/thinkfan.conf
file and 3 .conf
files to configure
thinkfan
to adjust how the service is started and restarted. This should work
with an X1YG3 but if you have another Thinkpad you'll probably want to
experiment a bit to make sure this works before installing. WARNING: the
script and service runs as root
so read them and understand it before running
it on your system!
chmod +x thinkfan/thinkfan-config
sudo cp thinkfan/thinkfan-config /usr/local/bin/.
sudo /usr/local/bin/thinkfan-config
cat /etc/thinkfan.conf
This should install the thinkfan-conf
script and generate an
/etc/thinkfan.conf
file for your system.
The thinkfan
rpm should have installed two systemd unit files;
/usr/lib/systemd/system/thinkfan.service
and
/usr/lib/systemd/system/thinkfan-wakeup.service
. You can confirm
and review them with:
systemctl cat thinkfan.service
Next, install the additional thinkfan
service configurations, start the
service, and check that it is running. There are three .conf
files to install:
00-generate-config.conf
will regenerate the/etc/thinkfan.conf
file on service start or restart. This will ensure that you have a config file thatthinkfan
can use even if some of the sensor names have changed or kernel modules have loaded in different orders. It runs thethinkfan-conf
script you just installed.10-restart-on-failure.conf
will restartthinkfan
if it fails to help make sure it is always running.override.conf
provides arguments for thethinkfan
that are called by the service.
sudo mkdir -p /etc/systemd/system/thinkfan.service.d
sudo cp thinkfan/thinkfan.service.d/* /etc/systemd/system/thinkfan.service.d
sudo systemctl enable thinkfan.service
sudo systemctl start thinkfan.service
journalctl status thinkfan.service
Hopefully that will keep thinkfan
running smoothly and help keep your X1YG3 cool!
If you'd like to adapt these instructions for your distribution, please add changes to the README and submit a pull request. Make sure that your changes diverge only where instructions need to be different and insure that other distribution notes stay in place.
Please submit pull requests from a branch with the following naming convention:
<BIOS_VERSION>-<BRIEF-DESCRIPTION>
such as 1_30-ubuntu-instructions
I followed numerous other guides, scripts, and docs to create these instructions. Here are a few that were particularly helpful.
- https://delta-xi.net/blog/#056
- https://github.com/ryankhart/x1carbon2018s3
- https://wiki.archlinux.org/index.php/Lenovo_ThinkPad_X1_Yoga_(Gen_3)
- https://forums.lenovo.com/t5/Other-Linux-Discussions/X1-Yoga-3rd-Gen-S3-Sleep-Linux/td-p/4235264
- https://forums.lenovo.com/t5/Other-Linux-Discussions/Linux-on-the-ThinkPad-X1-Yoga-3rd-Gen/m-p/4242717
- https://uefi.org/acpi/specs
- http://man7.org/linux/man-pages/man5/dracut.conf.5.html
- http://man7.org/linux/man-pages/man8/systemd-sleep.8.html
- https://gist.github.com/ioggstream/8f380d398aef989ac455b93b92d42048#file-system-sleep-xhci-sh
- https://forums.lenovo.com/t5/Other-Linux-Discussions/X1Y3-Touchscreen-not-working-after-resume-on-Linux/td-p/4021200
- https://projectgus.com/2014/09/blacklisting-a-single-usb-device-from-linux/
- https://gist.github.com/abn/de81ba413f860b00c2db3ee4aa83e035