J'utilise GNU/Linux depuis 1999 et, durant toutes ces années, j'ai contribué à beaucoup de logiciels libres (Owncloud, KDE, GNOME, LineageOS…) et travaillé sur plusieurs projets perso (Lollypop, Mobile Power Saver…). Mais un composant m'a toujours fait peur : le noyau Linux. Dans ce journal, je vais montrer comment j'ai fini malgré moi par mettre le nez dedans, et pourquoi, pour du débogage, il n'est pas forcément nécessaire d'être une brute en programmation.
N'ayant pas fait de longues études (DUT info), je me suis toujours senti trop peu compétent pour espérer ne serait-ce que comprendre le code du noyau, surtout en n'y connaissant rien en électronique…
En 2021, je commence à m'intéresser au noyau Dora pour mon OnePlus 7 Pro. Je me mets à lire les commits de la communauté (Sultan Alsawaf, Danny Lin…) pour optimiser le fonctionnement du téléphone, et effectivement, comparé au noyau d'origine de OnePlus, Dora permet d'obtenir de bien meilleures performances pour une bien meilleure économie d'énergie.
C'est dans ce contexte que je travaille sur un petit module noyau, cpu-min-freq, basé sur cpu_input_boost de Sultan Alsawaf. Le but est de faire passer le CPU en basse consommation quand le téléphone ne fait rien. Rien de bien compliqué : le code de cpu_input_boost est assez simple, et je me rends compte que tant qu'on ne touche pas directement au matériel, j'arrive à comprendre du code noyau.
Je migre ensuite de LineageOS vers Droidian, et je continue à "moder" le noyau avec les commits de la communauté Android, mais sans retoucher moi-même au code du noyau.
Puis, l'année dernière, je ressors mon vieux OnePlus 6 sous postmarketOS. Les appels audio fonctionnent enfin, ou presque : une fois sur deux, le haut-parleur d'écoute (earpiece) ne fonctionne pas pendant les appels. Un peu mieux que trois ans auparavant, mais pas encore satisfaisant.
Comme le bug semble se situer côté noyau, je me décide à regarder de plus près. Je télécharge linux-next, j'applique les patchs linux-sdm845, et là, c'est le drame : l'audio fonctionne encore moins bien. Malgré tout, les logs du noyau me permettent de trouver rapidement le commit à l'origine du problème et de proposer un correctif :
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/?id=8a066a81ee0c1b6cdbd81393536c3b2d19ccef25
Je peux enfin m'attaquer au bug du earpiece — ça va être long : un mois à déboguer le module wcd934x en cause. À force d'ajouter des messages de debug un peu au hasard, je remarque qu'un chemin d'exécution n'est pas emprunté quand je bascule vers le earpiece. À partir de là, je trouve rapidement le problème : un compteur de référence non décrémenté. Je corrige, et tout fonctionne enfin correctement :
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/?id=f8d51e903a6c97d8d298f14d9f8b4fff808670e3
Je suis aux anges : je peux enfin utiliser un téléphone Linux (et non Linux + Android comme avec Droidian) comme téléphone principal. Tout n'est pas parfait, mais vu mon usage, ça fait largement l'affaire.
J'en profite pour continuer sur ma lancée en corrigeant deux traces qui traînaient dans le dmesg pendant le fonctionnement du téléphone :
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/?id=961c900628fef77ad07b4bc4c868e47b9a1269c7
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/?id=3367c5a129f74812806034fa0a106a1c3e4a3890
Il reste encore des bugs, en particulier un crash aléatoire au démarrage, mais je n'arrive pas à en récupérer les logs. Il faudrait que je monte un dispositif électronique connecté directement à la carte mère du téléphone, et là, sans aide, je me sens clairement incompétent.
De mon côté, je travaille depuis trois ans sur un projet, Mobile Power Saver, pour optimiser la consommation de batterie des téléphones sous Linux. Sous Droidian, avec un Redmi Note 9 Pro, j'arrive à deux jours d'autonomie ; mais sous postmarketOS, impossible de dépasser une journée.
J'identifie rapidement que Wireplumber utilise un moniteur libcamera qui laisse un sous-périphérique V4L2 ouvert. Je soupçonne un bug dans Pipewire ou Wireplumber, mais je n'ai pas le temps de lire le code de ces deux projets.
Puis, vendredi, je tombe sur un commentaire qui indique que la commande "rmmod i2c_qcom_cci" divise la consommation de la batterie par deux ! Je file sur le salon Matrix de Pipewire, où l'on m'explique que garder un sous-périphérique V4L2 ouvert ne devrait pas poser problème : pour eux, le bug est côté noyau.
Je commence à examiner /sys/kernel/debug/regulator/regulator_summary et je remarque que des régulateurs liés à la caméra sont bien actifs et consomment de l'énergie. Après de longues recherches, je comprends que le nom du régulateur contient son adresse physique, ce qui me permet de retrouver le nom du driver associé dans /sys/bus/i2c/devices/17-0074/name, à savoir lc898217xc.
Une fois le nom du module en main, je regarde le code : c'est assez clair. À l'ouverture du périphérique, on sort de veille ; à la fermeture, on y retourne. Cela correspond exactement à ce que j'observe : Wireplumber ouvre le sous-périphérique, et la consommation reste donc active même quand la caméra n'est pas utilisée. Je comprends aussi que ce module gère le moteur chargé de la mise au point.
Le code est assez simple à corriger : je déplace la gestion de la mise en veille vers la fonction qui gère la mise au point. En théorie, ça devrait suffire.
- Je redémarre : les régulateurs sont bien éteints.
- Je lance l'application caméra : ils s'allument.
- Je fais une mise au point : ça fonctionne !
https://gitlab.com/gnumdk/linux/-/commit/7d96fbc6437ffb6036795e7cabc460fea03601e3
Sauf qu'au bout d'une seconde, la mise au point revient à sa position initiale ! Après quelques recherches, je comprends le fonctionnement de ce genre de moteur : c'est un "ressort", et la mise au point ne tient que tant que le moteur est alimenté. Si je remets le module en veille au bout d'une seconde, la position revient donc à son état de repos.
J'avais déjà entendu parler d'une méthode pour lier des périphériques entre eux, et je finis par retomber sur cette documentation :
https://www.kernel.org/doc/html/latest/driver-api/device_link.html
Il existe aussi un mécanisme pour lier des périphériques média entre eux via le devicetree du noyau Linux (https://www.kernel.org/doc/html/latest/devicetree/usage-model.html). En ajoutant un nouveau flag, je peux ainsi lier le capteur de la caméra et le moteur de mise au point pour la gestion de la mise en veille : le moteur reste donc actif tant que la caméra l'est aussi.
Je redémarre : ça marche, chouette !
https://gitlab.com/gnumdk/linux/-/commit/1615085aecba5879df789c399b8ccceb10cdd0fe
Je teste le correctif pendant quelques jours, puis je vais envoyer mes deux patchs à la LKML :
- c'est bien old school d'envoyer un patch par e-mail, obligé de relire la doc à chaque fois :)
- même si mon correctif fonctionne, ce n'est pas forcément la bonne façon de faire
Voilà, en attendant les retours des mainteneurs de linux-media. Et pour conclure, si tu identifies un bug dans le noyau Linux, dis-toi que tu peux possiblement le corriger (si tu connais le C par contre).

# Extra !
Posté par Luc-Skywalker . Évalué à 4 (+2/-0).
Je me suis régalé à la lecture de ce journal, merci :)
Pas vraiment programmeur dans l'âme (encore moins en C), j'ai pourtant bien suivi le propos (ceci je pense, parce que, comme tout le monde j'ai été confronté à ce genre de désagréments de bas niveau).
Maintenant je regarde le dernier commit cité dans le journal:
j'ai compris le pb mais pas comment on le résoud en vrai, pourtant c'est écrit la !!!
Ça pourrait faire une dépêche bien rafraichissante pour la rentrée non ?
"Si tous les cons volaient, il ferait nuit" F. Dard
[^] # Re: Extra !
Posté par gnumdk (site web personnel) . Évalué à 2 (+0/-0).
Pour détailler, dans le dts de mon téléphone il y'a ça:
Cela crée un lien entre la caméra et le moteur du focus. J'ai pas cherché midi à quatorze heure, je suis parti du principe que c'est le meilleur endroit pour créer un lien au niveau gestion de l'énergie entre les deux périphériques. Je laisse juste le soin au driver du moteur de dire qu'il veut entre lié via le nouveau flag V4L2_SUBDEV_FL_PM_LINK, en particulier parce que pour l'option dts "flash-leds", cela ne fonctionne pas, on peut avoir la camera active et le flash inactif.
Mais bon, comme je le dis, on va peut-être me dire que taper l'incruste dans cette fonction n'est pas la bonne façon de faire, et qu'il faudrait mieux rajouter une nouvelle option dts genre "link-pm", ça va vouloir dire un patch plus conséquent.
Envoyer un commentaire
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.