Pull to refresh

Готовим Linux на Asus U31SD/P31SD и подобных

Reading time 6 min
Views 16K

После приобретения обновки в виде Asus P31SD и последующей установки на него Linux было очень обидно увидеть всего 6 часов автономной работы вместо желаемых 10-12. На Windows обратно вернуться не удалось (тут даже cywgin не помог), поэтому было решено запастись кофе и занять ближайшие выходные решением этих проблем.

Рассматриваем решение на примере Ubuntu 11.10.

P.S. В теории гайд подходит для всех ноутбуков с Sandybridge и Nvidia Optimus.

Важная, для нас, часть конфигурации ноутбука:
Процессор: Intel Core i3-2310M (Sandybridge)
Видеоадаптер: Nvidia Geforce 520M (Nvidia Optimus)

Итак, сразу после установки Linux мы видим следующие проблемы:
  1. Сумасшедшая яркость.
  2. Повышенное потребление энергии — наша основная цель.
  3. Не работает режим сна — для облегчения жизни заставим его работать

Яркость


Симптом: подсветкой пытаются одновременно управлять хардварный модуль и программный модуль из DE в результате чего случаются скачки в случайном направлении.

Проблемы с яркостью в ноутбуках очень распространены и разнообразны но практически все решаются одним методом: добавлением в параметры загрузки ядра acpi_backlight=vendor, который сигнализирует, что управлением яркостью занимается железо и програмно лезть туда не стоит.

Открываем /etc/default/grub и вписываем параметр в GRUB_CMDLINE_LINUX, получится:
GRUB_CMDLINE_LINUX="acpi_backlight=vendor"

Сохраняем, обновляем конфигурацию grub (sudo update-grub), перезагружаемся и радуемся адекватному поведению подсветки.

Режим сна


Симптом: при отправке ноутбука в сон устройство яростно сопротивляется и, в конечном итоге, зависает.

После недолгих поисков находим виновников: плохо-засыпающие USB-хабы. И рядом находим решение, хук для pm-utils:
/etc/pm/sleep.d/20_custom-asus-u31sd:

#!/bin/sh
 
BUSES="0000:00:1a.0 0000:00:1d.0"
 
case "${1}" in
    hibernate|suspend)
    # Switch USB buses off
    for bus in $BUSES; do
        echo -n $bus | tee /sys/bus/pci/drivers/ehci_hcd/unbind
    done
    ;;
    resume|thaw)
    # Switch USB buses back on
    for bus in $BUSES; do
        echo -n $bus | tee /sys/bus/pci/drivers/ehci_hcd/bind
    done
    ;;
esac

Сохраняем, делаем исполняемым (sudo chmod +x /etc/pm/sleep.d/20_custom-asus-u31sd), проверяем.
Работает? Почти. После выходи из сна яркость дисплея падает до минимума… Поправить оплошность можно в этом же хуке. Достать значение яркости можно где-то из /sys. Большинство драйверов называют параметры банально поэтому просто поищем там backlight:

$ find /sys -name backlight
/sys/devices/platform/asus-nb-wmi/backlight

Нашлось! После изучения внутренностей значение яркости оказалось в /sys/devices/platform/asus-nb-wmi/backlight/asus-nb-wmi/brightness. Допишем в предыдущий хук его сохранение и восстановление:

#!/bin/sh
 
BUSES="0000:00:1a.0 0000:00:1d.0"
 
case "${1}" in
    hibernate|suspend)
    # Switch USB buses off
    for bus in $BUSES; do
        echo -n $bus | tee /sys/bus/pci/drivers/ehci_hcd/unbind
    done
    # Saving brightness to /tmp/br
    cat /sys/devices/platform/asus-nb-wmi/backlight/asus-nb-wmi/brightness > /tmp/br
    ;;
    resume|thaw)
    # Switch USB buses back on
    for bus in $BUSES; do
        echo -n $bus | tee /sys/bus/pci/drivers/ehci_hcd/bind
    done
    # Restoring brightness from /tmp/br
    cat /tmp/br > /sys/devices/platform/asus-nb-wmi/backlight/asus-nb-wmi/brightness
    ;;
esac

Снова проверяем и… работает! Теперь приступим к основному противнику, энергопотреблению.

Повышенное потребление энергии


Сбивать аппетиты Linux будем аж в 3 этапа.

1. Дискретная графика


Ноутбук оборудован двумя видеоадаптерами: интегрированной (Intel) и дискретной (Nvidia). Но не простой Nvidia, а работающей по технологии Nvidia Optimus. Той самой Optimus, поддержки которой в обозримом будущем в Linux не предвидится.

Но слава open-sourc'у мир полон энтузиастов. Борьбой (а иногда и дружбой) с Optimus занимается Bumblebee. Они достигли хорошего прогресса:
  • Bumblebee умеет включать/отключать дискретную карту в зависимости от потребностей
  • Bumblebee умеет заставлять приложения использовать дискретную карту

Естественно проект полон костылей, но это все же лучше чем ничего.
Займемся установкой:

$ sudo add-apt-repository ppa:bumblebee/stable
$ sudo apt-get update
$ sudo apt-get install bumblebee

К сожалению практически на каждом ноутбуке разная ACPI-команда включения/отключения видеокарты (большая таблица собрана здесь), поэтому управление питанием в Bumblebee по умолчанию выключено. Из таблицы выше берем команды и записываем их в /etc/bumblebee/cardoff и /etc/bumblebee/cardon соответственно:
/etc/bumblebee/cardoff:
\_SB.PCI0.PEG0.GFX0.DOFF

/etc/bumblebee/cardon:
\_SB.PCI0.PEG0.GFX0.DON

Затем в /etc/bumblebee/bumblebee.conf включаем управление питанием:
ENABLE_POWER_MANAGEMENT=Y

и заставляем сервис завершаться (и соответственно выключать дискретную видеокарту) если его никто не использует:
STOP_SERVICE_ON_EXIT=Y

Сохраняем, перезагружаемся, смотрим на потребление энергии — ощутимо уменьшилось.
Прежде чем пойти дальше починим снова ждущий режим: дело в том, что при переходе в сон активный видеодрайвер (nvidia или nouveau) будет пытаться подготовить карту, но карта то у нас выключена. Решим просто и «в лоб»: в выше использованный хук добавим 2 команды:
  • Будем включать карту перед засыпанием.
  • Будем выключать карту после просыпания.

Хук примет следующий вид:

#!/bin/sh
 
BUSES="0000:00:1a.0 0000:00:1d.0"
 
case "${1}" in
    hibernate|suspend)
    # Switch USB buses off
    for bus in $BUSES; do
        echo -n $bus | tee /sys/bus/pci/drivers/ehci_hcd/unbind
    done
    cat /sys/devices/platform/asus-nb-wmi/backlight/asus-nb-wmi/brightness > /tmp/br
    # Switch optimus back on before going to sleep, avoids the "constant on"
    # bug that occurs after 2 suspend/resume cycles (thanks kos888)
    echo `cat /etc/bumblebee/cardon` | tee /proc/acpi/call
    ;;
    resume|thaw)
    # Switch USB buses back on
    for bus in $BUSES; do
        echo -n $bus | tee /sys/bus/pci/drivers/ehci_hcd/bind
    done
    cat /tmp/br > /sys/devices/platform/asus-nb-wmi/backlight/asus-nb-wmi/brightness
    # Switch optimus off before resuming, avoids unneccessary power draw
    echo `cat /etc/bumblebee/cardoff` | tee /proc/acpi/call
    ;;
esac


2. Интегрированная видеокарта


Игравшись с разными версиями ядер я случайно заметил уменьшенное энергопотребление на версиях до 2.6.39 включительно. Бросившись в поиск по этим параметрам я в своей догадке не ошибся.
Проблема была обнаружена: виноват патч принятый в драйвер i915 в 3.0 ядре. Но, к счастью, его можно обойти без последствий.
В уже известный /etc/default/grub дописываем параметр i915.i915_enable_rc6=1. Строка расширится до:

GRUB_CMDLINE_LINUX="acpi_backlight=vendor i915.i915_enable_rc6=1"

Обновляем конфигурацию grub, перезагружаемся и смотрим на показания батареи. Теперь можно жить. А можно уменьшить еще!

3. Дополнительные мелкие твики


Запустив powertop и применив все рекомендованные твики можно выжать еще 0,5-1 Wh, что на данном железе может дополнительно дать до часа автономной работы. Но не играться же каждый раз с powertop? Автоматизируем все это дело через pm-utils. У нас получиться 4 отдельных скрипта:

1. Один из главных твиков, по неизвестным причинам не включенный в стандартную поставку. Меняем режим управления частотой процессора:
/etc/pm/power.d/cpu-governor
#!/bin/bash

cpu_powersave() {
    for i in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do
        echo $1 > $i && echo Done. || echo Failed.
    done

}

case $1 in
    true) cpu_powersave "ondemand" ;;
    false) cpu_powersave "performance" ;;
    *) exit $NA
esac

exit 0

2. Меняем режим управления питанием USB-устройств:
/etc/pm/power.d/usb-autosuspend
#!/usr/bin/env python

from os import listdir, path
from sys import argv

status = argv[1]
USB_PATH = '/sys/bus/usb/devices/'

def powersave(status):
    devices = listdir(USB_PATH)
    devices = filter(lambda x: ':' not in x, devices)

    for device in devices:
        b = listdir(path.join(USB_PATH, device))
        b = filter(lambda x: ':' in x, b)
        is_mouse = False
        for i in b:
            if open(path.join(USB_PATH, device, i, 'bInterfaceProtocol')).read().strip() == '02':
                is_mouse = True
                break

        if not is_mouse:
            open(path.join(USB_PATH, device, 'power/control'), 'w').write(status)

if status == 'true':
    powersave('auto')
elif status == 'false':
    powersave('on')

Скрипт умеет определять мыши и гасить их не будет.

3, 4. Меняем режим управления питанием у остальных устройств:
/etc/pm/power.d/scsi_host-link_power_management
#!/bin/bash

powersave() {
    for i in /sys/class/scsi_host/host?/link_power_management_policy; do
        echo $1 > $i && echo Done. || echo Failed.
    done

}

case $1 in
    true) powersave "min_power" ;;
    false) powersave "max_performance" ;;
    *) exit $NA
esac

exit 0

/etc/pm/power.d/pci-power-control
#!/bin/bash

powersave() {
    for i in /sys/bus/pci/devices/*/power/control; do
        echo $1 > $i && echo Done. || echo Failed.
    done

}

case $1 in
    true) powersave "auto" ;;
    false) powersave "on" ;;
    *) exit $NA
esac

exit 0

Делаем данные файлы исполняемыми и применяем одним махом: sudo pm-powersave true.

Настройка окончена. Официальный пруф:
image
И результаты диаграммой:
Tags:
Hubs:
+47
Comments 59
Comments Comments 59

Articles