Voici ce que je l'ai utilisé, en bref ...
get_user_pages
à la broche la page d'utilisateur (s) et vous donner un tableau de pointeurs struct page *
.
dma_map_page
sur chaque struct page *
pour obtenir l'adresse DMA (alias "adresse d'E/S") pour la page. Cela crée également un mappage IOMMU (si nécessaire sur votre plate-forme).
Dites maintenant à votre appareil d'exécuter le DMA dans la mémoire en utilisant ces adresses DMA. De toute évidence, ils peuvent être non contigus; La mémoire est seulement garantie contiguë dans les multiples de la taille de la page.
dma_sync_single_for_cpu
pour effectuer les vidages de mémoire cache ou les tampons de tampon de fusion nécessaires. Cet appel garantit que le processeur peut réellement voir le résultat du DMA, puisque sur de nombreux systèmes, la modification de la RAM physique derrière le dos du processeur entraîne des caches périmés.
dma_unmap_page
pour libérer le mappage IOMMU (si nécessaire sur votre plate-forme).
put_page
de désélectionner la (les) page (s) utilisateur (s).
Notez que doit vérifier les erreurs tout le chemin ici, car il y a des ressources limitées partout. get_user_pages
renvoie un nombre négatif pour une erreur pure et simple (-errno), mais il peut renvoyer un nombre positif pour vous indiquer le nombre de pages qu'il a réellement réussi à épingler (la mémoire physique n'est pas illimitée). Si cela est inférieur à ce que vous avez demandé, vous devez toujours parcourir toutes les pages pin pour appeler put_page
sur eux. (Sinon, vous perdez la mémoire du noyau, très mauvais.)
dma_map_page
peut également renvoyer une erreur (-errno), car les mappages IOMMU sont une autre ressource limitée.
dma_unmap_page
et put_page
retour void
, comme d'habitude pour Linux "libérer" les fonctions. (Les routines de gestion des ressources du noyau Linux ne renvoient des erreurs que parce que quelque chose s'est mal passé, pas parce que vous avez foiré un mauvais pointeur ou quelque chose comme ça ... L'hypothèse de base est que vous ne voyez jamais le code noyau.Bien que get_user_pages
vérifie la validité des adresses utilisateur et renvoie une erreur si l'utilisateur vous a donné un mauvais pointeur.)
Vous pouvez également utiliser les fonctions _sg si vous voulez qu'une interface conviviale soit dispersée/rassemblée. Ensuite, vous appelleriez dma_map_sg
au lieu de dma_map_page
, dma_sync_sg_for_cpu
au lieu de dma_sync_single_for_cpu
, etc.
Notez également que bon nombre de ces fonctions peuvent être plus ou moins pas d'habitation sur votre plate-forme, de sorte que vous pouvez souvent obtenir loin d'être bâclée . (En particulier, dma_sync _... et dma_unmap _... ne font rien sur mon système x86_64.) Mais sur ces plateformes, les appels eux-mêmes sont compilés dans rien, donc il n'y a aucune excuse pour être bâclé.
Achetez LDD http://lwn.net/Kernel/LDD3/ et recherchez l'implémentation de mmap() dans un pilote de périphérique. – Dummy00001
J'ai LDD ... pouvez-vous me dire le nom de certains pilotes de périphériques à regarder? –
@ Dummy00001 Qu'en est-il de l'adressage physique/virtuel? –