Standby - Suspend to RAM (MNT Reform)

I’ve installed pm-suspend, and running that has an odd problem. While it powers down the screen (it sort of looks like it suspends but power drain is still going on, I need to install that new firmware) but when I suspend it my wireless card is called “wlan0” and works, and when I wake up it’s called “wlp1s0” and doesn’t.

I’m playing with some of the quirks modes in suspend, but I’d really like to know what I’m actually doing rather than picking magic flags out of a hat but that’s going to take some work.

If you run this after coming back up, does it fix the problem?

sudo ifconfig wlp1s0 down
sudo ifconfig wlan0 up

Bringing down wlp1s0 works as you’d expect, but wlan0 doesn’t seem to exist after suspend. “No such device”.

I wondered if I’m missing something here by turning off almost all my console spew, and… wow, almost all of the output of dmesg is “chip reset failed”.

So, that might be the place to start digging.

Maybe you have two different systems trying to manage the wifi card? That would certainly explain the naming problems.

That might well be it - I’ll investigate.

So, I had ConnMan and Network Manager both running on this machine, I’m not sure why. My wireless card now believes that it is called “wlp1s0” all the time, and works correctly on startup. I’ve reverted the change I made to the suspend script at Lysko’s suggestion. I’m still experiencing the whole “wifi loses its mind after suspend” problem, and will continue to dig further.

Amusingly, I’m not seeing any of the wireless failure messages blow up my dmesg output after a suspend in the journald logs. This is fine.

1 Like

Yeah, I remember having this issue as well. I think that may be why I ended up moving from ConnMan to Network Manager.

Some progress. “wlp1s0” comes from systemd renaming it. see systemd.net-naming-scheme and PredictableNetworkInterfaceNames both of which were new to me. “This should solve real problems”, haha. Systemd, why are you always like this.

3 Likes

I’m now testing modified suspend script which I plan to make a suspend target unit (to utilize systemd based suspend).
The script is below, I have tested it successfully during the day, and left overnight - which also woke up ok. It draws suspiciously big power during sleep though - 240mA in active state and 100mA in suspend (so about 2.5W). I’d expect it to be lower.

If I try to poweroff aux (mpcie, by PWR3 command) it does not affect power draw (actually makes it slightly bigger?!) but it also makes system a bit unstable - eg. system lockup when doing lspci.

Either way, there could be some win by suspending nvme perhaps (which could be done via sysfs nodes) but major win should be by clocking down various clocks (eg memory, bus, maybe shutting off some spi/i2c perephery?). Any quick hints?
The modified script:

$ cat standby 
#!/bin/bash

if [ "$EUID" -ne 0 ]
  then echo "reform-standby has to be run as root / using sudo."
  exit
fi

set_wakes() {
	# configure UARTs as wakeup sources
	echo enabled > /sys/devices/platform/soc@0/30800000.bus/30860000.serial/tty/ttymxc0/power/wakeup
	echo enabled > /sys/devices/platform/soc@0/30800000.bus/30890000.serial/tty/ttymxc1/power/wakeup
	echo enabled > /sys/devices/platform/soc@0/30800000.bus/30880000.serial/tty/ttymxc2/power/wakeup
}
radio_off() {
	# remove PCI device
	echo 1 > /sys/class/pci_bus/0000:01/device/remove
	# turn off the power on the mpcie
	#echo -en "\0PWR3" > /dev/hidraw0
	#sleep 1
}
radio_on() {
	# turn on the power on the mpcie
	#echo -en "\0PWR4" > /dev/hidraw0
	#sleep 1
	echo 1 > /sys/class/pci_bus/0000:00/rescan
	sleep 1
}
bklite_off() {
	echo -en "\0LITE0" > /dev/hidraw0
}
bklite_on() {
	echo -en "\0LITE6" > /dev/hidraw0
}

# Countdown for manual run
if [[ -z "$1" ]]; then
	echo Entering standby in 3...
	sleep 1
	echo 2...
	sleep 1
	echo 1...
	sleep 1
fi

# Either manual or suspending
if [[ -z "$1" || $1 = "suspend" ]]; then
	set_wakes
	radio_off
	bklite_off
fi

# Go sleeping for manual run
if [[ -z "$1" ]]; then
	sync
	echo mem >/sys/power/state
	sleep 1
fi

# Either manual or resuming
if [[ -z "$1" || $1 = "resume" ]]; then
	bklite_on
	radio_on
fi
2 Likes

To make this script work with systemd - assuming the script was placed into /usr/local/bin/. First correct systemd-sleep config to prevent deep sleep and hibernation:

# vim /etc/systemd/sleep.conf
[Sleep]
AllowHibernation=no
SuspendState=mem

Normally all lines are commented out there with their defaults. So only these two lines need to be changed. Then create a new service definition:

# vim /etc/systemd/system/reform-sleep.service
[Unit]
Description=Reform suspend helper
Before=sleep.target
StopWhenUnneeded=yes

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/bin/standby suspend
ExecStop=/usr/local/bin/standby resume

[Install]
WantedBy=sleep.target

This will insert the service as a hook for sleep target and will execute Start when entering sleep and Stop when exiting. Now do sudo systemctl daemon-reload and sudo systemctl enable reform-sleep. After that you can try systemctl suspend (note - without sudo, as user) and it should work. To add it to sway keybinds create a config hook (assuming you use system config, not user, but user works similarly):

# vim /etc/sway/config.d/99-suspend.conf
# make sure to add -f to lock otherwise it won't release the idle pipeline till unlocked
exec_always --no-startup-id swayidle -w timeout 600 'swaylock -fei /usr/share/backgrounds/gnome/adwaita-night.png' timeout 300 'swaymsg "output * dpms off"' resume 'swaymsg "output * dpms on"' before-sleep 'swaylock -fei /usr/share/backgrounds/gnome/adwaita-night.png'

bindsym $mod+Shift+Backspace exec systemctl suspend

of course you can use different time, background and key binding.

Update: you also need to unmask sleep and suspend targets to make it all work. For that do

$ sudo systemctl unmask suspend.target
$ sudo systemctl unmask sleep.target

or simply remove corresponding symlinks at /etc/systemd/system pointing to /dev/null and do sudo systemctl daemon-reload.

8 Likes

Just to let everyone here know, but this really seems to be the solution. I reliably have been able to come back from suspend the last 7 times. I highly recommend you give this a go in case you haven’t!

:+1::+1:

Thank you so much @ruff for the detailed instructions, I had no issues following them! Going into suspend from sway using the hotkey defined above, the LPC now reports around 0.100A drawn while the system sleeps. Waking it up again using circle-space worked fine at least once :wink:

I would like to use this mode when closing the lid in the evening (connected to mains) or when transporting the reform when e.g. traveling. In the latter case, what is to be expected when the batteries go low? Will the LPC cut the power before there is a risk of underdepleting the batteries or could I end up with nonchargeable batteries should I ever forget the system in this state?

Glad it works for you too.
There’s no lid switch in reform so you need to manually suspend it. Technically you can add one more timeout to swayidle to enter the sleep after 15min of idle (currently there’re 5min dpms off and 10min lock timers).
LPC controls undervoltage and should turn the power rails off as per this code:

    else if (state == ST_UNDERVOLTED) {
      reset_discharge_bits();
      deep_sleep_seconds(POWERSAVE_SLEEP_SECONDS);

      // TODO: find safe heuristic. here we turn off if half
      // of the cells are undervolted and there's no wall power.
      if (volts < WALLPOWER_DETECT_VOLTAGE && (num_undervolted_critical_cells >= 1 || num_undervolted_cells >= 4)) {
        turn_som_power_off();
      }

      next_state = ST_CHARGE;
      cycles_in_state = 0;
    }

so there won’t be graceful shutdown but at least the undervoltage should be protected.

1 Like

Ruff, so if I understand this correctly, you are saying that when we have the Reform already suspended using the method above, and the system gets to a point where the batteries are too low, the LPC will cut power and protect the cells?

I’m rather saying that LPC protects cells regardless of the SoM sleep state. It is actually oblivious to this fact and will protect them the same way whether the system is active or suspended. And since power sources are not exposed either to upower or sysfs interfaces the graceful shutdown on low power is also not available regardless of the sleep state.

2 Likes

Astonishingly, this appears to work. I will dogfood this over the next few days.

It’s not perfect, it’s a temporary workaround but a good start. Eg. removing wifi card is a quick and dirty solution, and for one today it once did not re-appear.
Whatever I did, however many times I was resetting the bus and controller and… (tbh I didn’t reset power, now that I think about it) it did not reappear on re-scan.
The proper way to handle it would be to enable auto pm and let it suspend. I’m planning to try to pull in purim’s linux-next kernel and rebase your patches onto it. They should have advanced much further into runtime pm.

3 Likes

Just to offer another (potential) workaround that has served me well for about 30 suspend/resume cycles without failures until now: enable the kernel option “no_console_suspend”. I did this mostly for debugging reasons to see more information on the serial console, but it might just be that this keeps a critical component under power which allows the resume to work properly. As the power consumption that I noticed with this option on seemed very close to a suspend without it, this seems like a viable workaround to me.

More data points would be useful, obviously. If you want to give this a shot, you can set this option at runtime by running:

echo N | sudo tee /sys/module/printk/parameters/console_suspend

You will have to run this command after every boot or modify the bootargs environment variable in U-Boot to make it permanent.

5 Likes

FWIW, I recall having used no_console_suspend on a variety of mainstream laptops (mostly Dell and Lenovo) over the past 1-2 decades, where it was necessary to facilitate/improve Linux suspend to RAM (especially crashes/hangs on the resume side).