web-dev-qa-db-fra.com

Que fait réellement request_mem_region () et quand est-il nécessaire?

J'étudie l'écriture de pilote Linux intégré et décide de renvoyer quelques GPIO pour m'assurer de bien comprendre le livre (LDD3, chap9.4.1) correctement.

Je suis capable de contrôler les broches GPIO correctes comme prévu (le rendant haut et bas, j'ai sondé avec un multimètre); Cependant, j'ai testé 2 morceaux de code, un avec request_mem_region() et un sans. Je m'attends à ce que l'un sans échoue, mais les deux fonctionnent très bien.

Code avec request_mem_region:

if( request_mem_region( PIN3_CONF_PHYS, MAPPED_SIZE_GPIO_CONF,DEVICE_NAME ) == NULL )
  {
    printk( KERN_ALERT
            "GPIO_140_141_conf_phys error:%s: unable to obtain I/O memory address 0x%08llX\n",
            DEVICE_NAME, PIN3_CONF_PHYS );

    return -EBUSY;
  }

pin3_conf = (u32)ioremap( PIN3_CONF_PHYS, MAPPED_SIZE_GPIO_CONF);
pin4_conf = (u32)ioremap( PIN4_CONF_PHYS, MAPPED_SIZE_GPIO_CONF);
pin5_conf = (u32)ioremap( PIN5_CONF_PHYS, MAPPED_SIZE_GPIO_CONF);
pin6_conf = (u32)ioremap( PIN6_CONF_PHYS, MAPPED_SIZE_GPIO_CONF);
//-----------------------------------------------------------------
if( request_mem_region( GPIO_BANK5_PHYS, MAPPED_SIZE_GPIO_5,DEVICE_NAME ) == NULL )
  {
    printk( KERN_ALERT
            "error:%s: unable to obtain I/O memory address 0x%08llX\n",
            DEVICE_NAME, GPIO_BANK5_PHYS );

    return -EBUSY;
  }

gpio_virt = (u32)ioremap( GPIO_BANK5_PHYS, MAPPED_SIZE_GPIO_5 );

//some iowrite32() functions continue...

Code sans request_mem_region():

pin3_conf = (u32)ioremap( PIN3_CONF_PHYS, MAPPED_SIZE_GPIO_CONF);
pin4_conf = (u32)ioremap( PIN4_CONF_PHYS, MAPPED_SIZE_GPIO_CONF);
pin5_conf = (u32)ioremap( PIN5_CONF_PHYS, MAPPED_SIZE_GPIO_CONF);
pin6_conf = (u32)ioremap( PIN6_CONF_PHYS, MAPPED_SIZE_GPIO_CONF);
gpio_virt = (u32)ioremap( GPIO_BANK5_PHYS, MAPPED_SIZE_GPIO_5 );
//some iowrite32() functions continue...

La seule différence que je peux observer dans les deux cas est le résultat de l'exécution d'un cat /proc/iomem, celui avec request_mem_region() affichera une ligne supplémentaire affichant 49056000-49056097 : GPIO3.

Ma question est pourquoi request_mem_region() est nécessaire puisque je peux toujours communiquer avec l'adresse matérielle avec seulement ioremap()? Alors, quand devons-nous réellement utiliser request_mem_region()?

Merci pour toutes les réponses!

22

request_mem_region indique au noyau que votre pilote utilisera cette plage d'adresses d'E/S, ce qui empêchera les autres pilotes de faire des appels qui se chevauchent vers la même région via request_mem_region. Ce mécanisme ne fait aucun type de mappage, c'est un mécanisme de réservation pur qui repose sur le fait que tous les pilotes de périphérique du noyau doivent être Nice, qu'ils doivent appeler request_mem_region, vérifier la valeur de retour et se comporter correctement en cas d'erreur.

Il est donc tout à fait logique que votre code fonctionne sans request_mem_region, mais simplement qu'il ne respecte pas les règles de codage du noyau.

Cependant, votre code n'est pas conforme au style de codage du noyau. De plus, il existe une infrastructure existante pour gérer les GPIO, nommée gpiolib, que vous devez utiliser au lieu de remapper manuellement vos registres de banque GPIO. Sur quelle plateforme travaillez-vous?

36
Thomas Petazzoni

L'utilisation de request_mem_region () et ioremap () dans les pilotes de périphérique est maintenant obsolète . Vous devriez plutôt utiliser les fonctions "gérées" ci-dessous , Qui simplifient le codage du pilote et la gestion des erreurs:

devm_ioremap()
devm_iounmap()
devm_ioremap_resource(), Takes care of both the request and remapping operations

https://bootlin.com/doc/training/linux-kernel/linux-kernel-slides.pdf diapositive 276

0
jordi oliva