É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,i915Vé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
##makeRé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-nouveauSuppression 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...)"
;
esacDé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...