Artisan Numérique

/système/kernel/matos/debian/énergie/intel/nvidia/portable/ Éteindre le GPU mangeur de batteries

J'ai récemment fait l'acquisition pour le boulot d'un Dell Vostro 3300 censé être parfaitement pris en charge par GNU/Linux... Alors oui, c'est vrai, ça s'allume, j'ai même le wifi qui fonctionne, j'arrive à mettre en veille sans maux de crânes, bref, c'est pas si pire. Sauf pour un détail, une autonomie d'1h20, c'est court...

Le fautif, un ingénieur ivre qui a eu l'idée de coller deux cartes écran dans la même bécane, et ce dans le louable principe de pouvoir basculer d'une carte moins rapide mais moins gourmande en énergie (chipset Intel) à une carte plus rapide et plus gourmande (chipset nVidia). Le souci est que le pauvre garçon a juste oublié de mettre dans le BIOS l'option permettant d'éviter que les deux cartes ne tournent en même temps... Et là commence ma quête pour éteindre la carte maudite.

Symptômes

Pour faire simple, je n'en ai rien à braire moi de la carte rapide. N'aimant jouer qu'aux légos avec mon fils et n'ayant jamais bien compris l'intérêt de faire gigoter mes fenêtres lorsque je les déplace, le chipset Intel est largement assez rapide pour mon usage. Ce qui suit ne cherche donc qu'à éteindre le GPU nVidia, définitivement et sans autre forme de procès, de sorte à retrouver une autonomie décente.

Pour commencer, nous pouvons déjà valider le fait que nous avons bien deux cartes écrans :

$$lspci | grep VGA
02.0 VGA compatible controller: Intel Corporation Core Processor Integrated Graphics Controller (rev 18)
01:00.0 VGA compatible controller: nVidia Corporation GT218 [GeForce 310M] (rev a2)

Voilà donc la fautive. Et effectivement, si on regarde les pilotes chargés au démarrage de X, on a bien le pilote "Nouveau" (pilote libre sensé gérer les nVidia) chargé en même temps que le pilote i915 pour celle intégrée au chipset Intel :

$$lsmod | grep nouv
veau               353128  0 
ttm                    40162  1 nouveau
drm_kms_helper         20369  2 nouveau,i915
drm                   142279  5 nouveau,i915,ttm,drm_kms_helper
i2c_algo_bit            4225  2 nouveau,i915
i2c_core               15819  6 nouveau,i915,drm_kms_helper,drm,i2c_i801,i2c_algo_bit
button                  4650  2 nouveau,i915
Vérification des pilotes chargés

Avant de poursuivre, et pour rester fidèle à un esprit vaguement scientifique, il nous faut déterminer le temps de décharge de la batterie. La commande acpi -b m'a servi de base de travail en renvoyant une estimation de temps de décharge total, ainsi que le pourcentage d'énergie restant. Pour valider que le temps annoncé était fiable, j'ai fait un petit script stoquant dans un fichier toutes les minutes le pourcentage restant jusqu'à la dernière goute de jus. Bonne surprise, la valeur annoncée était bien concordante avec le résultat de mon expérience, 1h20. Pathétique.

Extinction des feux

Pour corriger cela, j'ai trouvé deux solutions. La première consiste en un switch niveau kernel (vgaswitchero) qui n'est pas dispo en standard dans le noyau 2.6.32 de la debian squeeze. L'autre est le projet acpi_call qui va, comme son nom l'indique, permettre de lancer des commandes ACPI pour désactiver la carte qui ne sert à rien. J'opte pour la seconde option que ne m'oblige pas à changer de kernel.

acpi call est en réalité un module kernel à compiler soi-même et qui ajoutera une entrée /proc/acpi/call permettant d'injecter la commande ACPI. Pour récupérer le projet, le mieux est d'utiliser GIT (apt-get install git) :

##cd /opt
##git clone http://github.com/mkottman/acpi_call.git
##cd acpi_call
##make
Récupération du projet acpi_call

Nous avons maintenant un module acpi_call.ko prêt à être chargé. Dans le même dossier nous avons une fonction test_off.sh qui va nous permettre de débusquer le bon appel ACPI qui va éteindre la carte. Car bien évidement, cette glute de double carte n'a rien de standard, chaque constructeur fait donc sa propre toutouille :

##insmod acpi_call.ko
##sh ./test_off.sh
Trying \_SB.PCI0.P0P1.VGA._OFF: failed
Trying \_SB.PCI0.P0P2.VGA._OFF: failed
Trying \_SB_.PCI0.OVGA.ATPX: failed
Trying \_SB_.PCI0.OVGA.XTPX: failed
Trying \_SB.PCI0.P0P3.PEGP._OFF: failed
Trying \_SB.PCI0.P0P2.PEGP._OFF: failed
Trying \_SB.PCI0.P0P1.PEGP._OFF: works!
Chargement du module et recherche de la bonne méthode

Ouf, une méthode semble fonctionner :) Il ne nous reste maintenant plus qu'à mettre tout cela en musique dans un petit script.

Mise en place de la solution

Comme le pilote nouveau ne nous sert à rien, autant le supprimer

##aptitude purge libdrm-nouveau1 xserver-xorg-video-nouveau
Suppression du pilote Nouveau

Ensuite nous faisons un petit script qui va éteindre la carte :

#! /bin/bash

# Chargement du module
insmod /opt/acpi_call/acpi_call.ko

# Lancement de la commande ACPI
echo "\_SB.PCI0.P0P1.PEGP._OFF" > /proc/acpi/call

# vérification du résultat
result=$(cat /proc/acpi/call)
case "$result" in
Error*)
echo "Impossible de désactiver cette maudite carte !!"
;;
*)
echo "La satanée carte est désactivé (euh, normalement...)"
;
esac
Désactivation de la carte qui sert à rien

Enfin, nous allons modifier /etc/rc.local pour faire appel à notre script de sorte à ce que la carte soit éteinte à chaque redémarrage.

Résultat des courses

Alors j'en vois déjà certain qui se demandent quel est le nouveau temps de décharge. Et bien croyez le ou pas, mais une fois cette maudite carte éteinte, le portable est simplement passé à 3h40 d'autonomie... Cela valait tout de même le coup de s'enquiquiner un peu...