/x1yg3-suspend-to-ram

Add suspend-to-ram (S3 support to Lenovo X1 Yoga Gen. 3

Lenovo X1 Yoga (3rd Gen) Suspend-to-Ram on Linux

The Lenovo X1 Yoga (3rd Gen) (X1YG3) BIOS does not expose support for Suspend-to-Ram (S3). Instead, it exposes 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. Lenovo has implemented S3 support as an option in a BIOS update to the X1 Carbon (6th Gen) (X1CG6) but has thus far opted not to port the same support to the X1YG3 BIOS.

Fortunately, you can enable S3 support by modifying the firmware's ACPI Differentiated System Description Table (DSDT) that is loaded by your Linux kernel. It would be nice if Lenovo would add support but it has been over a year so I'm not holding out much hope at this point.

These instructions are for Fedora but I hope others can provide pull requests with updated instructions for other distributions.

Prerequisites

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.

Disable SecureBoot

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

Check current ACPI support

dmesg | grep "ACPI: (supports"

This command should return something like ACPI: (supports S0 S4 S5) which as you can see is missing S3 support.

Ensure iasl is installed

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

Check your BIOS version

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

Clone this repository and change directory

git clone https://github.com/zachsmith/x1yg3-suspend-to-ram.git
cd x1yg3-suspend-to-ram

Patch the Differentiated System Description Table (DSDT)

Copy the current DSDT table exposed by the BIOS

sudo cat /sys/firmware/acpi/tables/DSDT > dsdt.dat

Decompile the DSDT

This will produce a dsdt.dsl file:

iasl -d dsdt.dat

Patch the DSL file

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.

Recompile the DSDT

This will produce a dsdt.aml file:

iasl -tc -ve dsdt.dsl

Update initramfs image

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).

Copy updated DSDT table

sudo mkdir /boot/acpi_override
sudo cp dsdt.aml /boot/acpi_override/x1yg3-s3-override.aml

Configure ACPI override for dracut

Create /etc/dracut.conf/acpi.conf and add the following lines:

acpi_override="yes"
acpi_table_dir="/boot/acpi_override"

Rebuild your initramfs image

Update the initramfs image for your current kernel.

cd /boot
sudo dracut --force initramfs-$(uname -r).img

Make sleep default to deep

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.

Edit /etc/default/grub

Append the following to the end of the string defined by GRUB_CMDLINE_LINUX:

mem_sleep_default=deep

Rebuild grub.cfg

sudo grub2-mkconfig -o /boot/efi/EFI/fedora/grub.cfg

Final Steps

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.

Reboot

Confirm S3 support

dmesg | grep "ACPI: (supports"

It should now display ACPI: (supports S0 S3 S4 S5) which includes S3. This means that your patched DSDT loaded.

Confirm deep sleep is default

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 to sleep!

Go ahead and enjoy the convenience of putting your computer to sleep!

Going forward

You should probably repeat these steps after each BIOS update. I'll try and keep the patch updated for new BIOS versions (if needed) or accept pull requests if anybody would like to pitch in. See the Pull Requests guidelines below.

Help

Linux Distributions

If you'd like to adapt these instructions for your distribution, please add changes to the README and submit a pull request.

Pull Requests

Please submit pull requests from a branch with the following naming convention:

<BIOS_VERSION>-<BRIEF-DESCRIPTION> such as 1_30-ubuntu-instructions

Resources

I followed numerous other guides, scripts, and docs to create these instructions. Here are a few that were particularly helpful.