Après avoir ajouté request_mem_region, mon pilote échoue à chaque premier access avec le message «busy».

OK, c‘est vraiment bizarre pour moi. J’ai un pilote de bus CAN simulé, c’est un module de kernel Linux. Ensuite, j’ai une application de test s’exécutant dans l’espace utilisateur qui accède au pilote en ouvrant un descripteur de fichier et en envoyant des messages ioctl() .

Maintenant, le pilote de bus CAN est juste quelque chose que j’ai adopté pour fonctionner sur la plate-forme x86 (il fonctionnait sur notre système Coldfire intégré). Sur le système embarqué, elle devait utiliser request_mem_region() / ioremap() pour rendre la zone d’E / S mémoire accessible. Je n’ai pas besoin de le faire, mais je veux garder le plus de code possible commun.

Voici quelques définitions utiles:

 #define MCF_MBAR 0x10000000 extern unsigned int Base[]; extern unsigned int can_range[]; //This is the CAN registers on coldfire, just unused on my x86 desktop Base[minor] = (MCF_MBAR + 0x1c0000); can_range[minor] = 0x180; 

Puis pendant l’init nous faisions ceci:

 if(NULL == request_mem_region(Base[minor], can_range[minor], "CAN-IO")) { return -EBUSY; } can_base[minor] = ioremap(Base[minor], can_range[minor]); 

Maintenant, si je comprends bien, tout ce que nous faisons ici demande une réservation d’une plage d’adresses mémoire non atsortingbuées et, si nous y arrivons, de les rendre accessibles par nous.

J’ai vérifié les adresses actuellement mappées via cat /proc/iomem :

 00000000-0000ffff : reserved 00010000-0009fbff : System RAM 0009fc00-0009ffff : reserved 000a0000-000bffff : Video RAM area 000c0000-000c8fff : Video ROM 000e2000-000e6fff : Adapter ROM 000f0000-000fffff : reserved 000f0000-000fffff : System ROM 00100000-1ffeffff : System RAM 00200000-0071038b : Kernel code 0071038c-00ad8a7f : Kernel data 00b58000-00c52fff : Kernel bss <-- 101C0000-101C0180 : This is where I'd be mapping memory 1fff0000-1fffffff : ACPI Tables e0000000-e0ffffff : 0000:00:02.0 e0000000-e0bfffff : vesafb f0000000-f001ffff : 0000:00:03.0 f0000000-f001ffff : e1000 f0400000-f07fffff : 0000:00:04.0 f0400000-f07fffff : vboxguest f0800000-f0803fff : 0000:00:04.0 f0804000-f0804fff : 0000:00:06.0 f0804000-f0804fff : ohci_hcd f0806000-f0807fff : 0000:00:0d.0 f0806000-f0807fff : ahci fee00000-fee00fff : Local APIC fffc0000-ffffffff : reserved 

On dirait que rien n’utilise cette mémoire, alors je pense que tout va bien ici. Donc, je charge mon module de kernel, avec succès, je vais exécuter mon programme de test et il échoue, le réexécute et cela fonctionne. Chaque fois que vous l’exécutez après qu’il ait été récemment chargé, il échouera … les 2e, 3e et nième fois, cela fonctionnera:

 mike@linux-4puc:~> ./a.out Starting driver test Error 'Device or resource busy' opening CAN device mike@linux-4puc:~> ./a.out Starting driver test We opened successfully 

Voici une partie de mon programme utilisateur très simple:

 int fd; char* dev = "/dev/can0"; printf("Starting driver test\n"); if ((fd = open(dev, O_RDWR)) < 0) { printf("Error '%s' opening CAN device", strerror(errno)); close(fd); return -1; } 

Des idées sur pourquoi cela se produit? Si je supprime le code request_mem_region() de mon pilote, tout fonctionne, alors je pense que je suis en train de faire quelque chose de stupide … mais pourquoi cela échoue-t-il de cette manière?

Je suis un peu surpris que cela fonctionne pour vous du tout. request_mem_region() reçoit une valeur de 0x101C0000 qui se situe dans la plage d’adresses physiques de la RAM système, 0x00100000 : 0x1ffeffff . Je suppose que le retour d’erreur (initial) est un indicateur du fait que le kernel a déjà installé cette région de mémoire physique dans ses pools de mémoire. Lorsque le pilote détecte une erreur (ou lorsque le module se décharge), tente-t-il d’effectuer le nettoyage approprié et appelle- release_mem_region() -il release_mem_region() , ce qui pourrait permettre à release_mem_region() réussir le prochain tour?

Normalement, vous devez fournir à request_mem_region() une plage d’adresses non utilisée (c’est-à-dire inconnue du kernel), car le pilote est en train de rendre cette plage d’adresses physiques “utilisable” (c’est-à-dire en déclarant une plage d’adresses physiques pour le mappage). à l’espace d’adressage virtuel).

Que se passe-t-il si vous utilisez plutôt quelque chose comme

 #define MCF_MBAR 0x90000000 

en supposant que cet espace d’adressage physique est vraiment inutilisé?

Si votre pilote appelle release_mem_region() après sa première utilisation, le pilote a un bogue. Un pilote ne doit libérer que les ressources qu’il a réellement acquises. Si request_mem_region() renvoyé une erreur, la ressource mémoire n’a jamais été acquise. Par conséquent, il n’y a aucune raison d’appeler release_mem_region() (et le pilote obtiendrait toujours l’erreur d’allocation pendant _init() ). Si vous inspectez des pilotes de périphérique Linux fonctionnant correctement, vous découvrirez probablement des schémas élaborés de sortie d’erreur (à l’aide d’ goto ) permettant de dérouler les ressources allouées dans la routine _init() et de vérifier la validité avant la désallocation dans le code _exit() .