Je construis un système d'acquisition de données basé sur l'UltraScale + FPGA équipé d'une CPU arm64. Les données sont transmises à la RAM via DMA. Les tampons DMA dans le pilote sont réservés comme ci-dessous:Linux sur arm64: sendto provoque "Défaut non corrigé: erreur d'alignement (0x96000021)" lors de l'envoi de données à partir du tampon DMA mouillé cohérent
virt_buf[i] = dma_zalloc_coherent(&pdev->dev, BUF_SIZE, &phys_buf[i],GFP_KERNEL);
Dans la fonction mmap du conducteur, la mise en correspondance de l'espace utilisateur se fait de la manière suivante:
#ifdef ARCH_HAS_DMA_MMAP_COHERENT
printk(KERN_INFO "Mapping with dma_map_coherent DMA buffer at phys: %p virt %p\n",phys_buf[off],virt_buf[off]);
res = dma_mmap_coherent(&my_pdev->dev, vma, virt_buf[off], phys_buf[off], vsize);
#else
physical = phys_buf[off];
res=remap_pfn_range(vma,vma->vm_start, physical >> PAGE_SHIFT , vsize, pgprot_noncached(vma->vm_page_prot));
printk(KERN_INFO "Mapping with remap_pfn_range DMA buffer at phys: %p virt %p\n",physical,virt_buf[off]);
#endif
Sur mon UltraScale + remap_pfn_range CPU est utilisé. Dans l'application d'espace utilisateur, les données sont lues à partir du tampon et envoient immédiatement des paquets UDP d'une longueur limitée à MAX_DGRAM (à l'origine égale à 572).
int i = 0;
int bleft = nbytes;
while(i<nbytes) {
int bts = bleft < MAX_DGRAM ? bleft : MAX_DGRAM;
if (sendto(fd,&buf[nbuf][i],bts,0, res2->ai_addr,res2->ai_addrlen)==-1) {
printf("%s",strerror(errno));
exit(1);
}
bleft -= bts;
i+= bts;
}
Tout a fonctionné parfaitement sur le FPGA Zynq 32 bits. Cependant, après l'avoir déplacé vers le FPGA UltraScale 64 bits, j'ai commencé à recevoir des erreurs aléatoires, après quelques centaines de transferts.
[ 852.703491] Unhandled fault: alignment fault (0x96000021) at 0x0000007f82635584
[ 852.710739] Internal error: : 96000021 [#4] SMP
[ 852.715235] Modules linked in: axi4s2dmov(O) ksgpio(O)
[ 852.720358] CPU: 0 PID: 1870 Comm: a4s2dmov_send Tainted: G D O 4.4.0 #3
[ 852.728001] Hardware name: ZynqMP ZCU102 RevB (DT)
[ 852.732769] task: ffffffc0718ac180 ti: ffffffc0718b8000 task.ti: ffffffc0718b8000
[ 852.740248] PC is at __copy_from_user+0x8c/0x180
[ 852.744836] LR is at copy_from_iter+0x70/0x24c
[ 852.749261] pc : [<ffffffc00039210c>] lr : [<ffffffc0003a36a8>] pstate: 80000145
[ 852.756644] sp : ffffffc0718bba40
[ 852.759935] x29: ffffffc0718bba40 x28: ffffffc06a4bae00
[ 852.765228] x27: ffffffc0718ac820 x26: 000000000000000c
[ 852.770523] x25: 0000000000000014 x24: 0000000000000000
[ 852.775818] x23: ffffffc0718bbe08 x22: ffffffc0710eba38
[ 852.781112] x21: ffffffc0718bbde8 x20: 000000000000000c
[ 852.786407] x19: 000000000000000c x18: ffffffc000823020
[ 852.791702] x17: 0000000000000000 x16: 0000000000000000
[ 852.796997] x15: 0000000000000000 x14: 00000000c0a85f32
[ 852.802292] x13: 0000000000000000 x12: 0000000000000032
[ 852.807586] x11: 0000000000000014 x10: 0000000000000014
[ 852.812881] x9 : ffffffc0718bbcf8 x8 : 000000000000000c
[ 852.818176] x7 : ffffffc0718bbdf8 x6 : ffffffc0710eba2c
[ 852.823471] x5 : ffffffc0710eba38 x4 : 0000000000000000
[ 852.828766] x3 : 000000000000000c x2 : 000000000000000c
[ 852.834061] x1 : 0000007f82635584 x0 : ffffffc0710eba2c
[ 852.839355]
[ 852.840833] Process a4s2dmov_send (pid: 1870, stack limit = 0xffffffc0718b8020)
[ 852.848134] Stack: (0xffffffc0718bba40 to 0xffffffc0718bc000)
[ 852.853858] ba40: ffffffc0718bba90 ffffffc0006a1b2c 000000000000000c ffffffc06a9bdb00
[ 852.861676] ba60: 00000000000005dc ffffffc071a0d200 0000000000000000 ffffffc0718bbdf8
[ 852.869488] ba80: 0000000000000014 ffffffc06a959000 ffffffc0718bbad0 ffffffc0006a2358
[...]
[ 853.213212] Call trace:
[ 853.215639] [<ffffffc00039210c>] __copy_from_user+0x8c/0x180
[ 853.221284] [<ffffffc0006a1b2c>] ip_generic_getfrag+0xa4/0xc4
[ 853.227011] [<ffffffc0006a2358>] __ip_append_data.isra.43+0x80c/0xa70
[ 853.233434] [<ffffffc0006a3d50>] ip_make_skb+0xc4/0x148
[ 853.238642] [<ffffffc0006c9d04>] udp_sendmsg+0x280/0x740
[ 853.243937] [<ffffffc0006d38e4>] inet_sendmsg+0x7c/0xbc
[ 853.249145] [<ffffffc000651f5c>] sock_sendmsg+0x18/0x2c
[ 853.254352] [<ffffffc000654b14>] SyS_sendto+0xb0/0xf0
[ 853.259388] [<ffffffc000084470>] el0_svc_naked+0x24/0x28
[ 853.264682] Code: a88120c7 a8c12027 a88120c7 36180062 (f8408423)
[ 853.270791] ---[ end trace 30e1cd8e2ccd56c5 ]---
Segmentation fault
[email protected]_2:~#
La chose étrange est que quand je lis simplement les mots de la mémoire tampon, il ne provoque pas d'erreurs d'alignement.
Il semble que la fonction envoyer utilise incorrectement la __copy_from_user fonction, ce qui provoque un accès mémoire non alignés. La question est: est-ce le bogue du noyau, ou ai-je fait quelque chose de mal? Cependant, en général, l'envoi du bloc de données ne démarrant pas à une limite de 8 octets ne déclenche pas l'erreur d'alignement. Le problème se produit avec une probabilité relativement faible. Je n'ai pas pu isoler les conditions qui ont conduit à l'erreur. J'ai résolu le problème en ajustant le MAX_DGRAM pour qu'il soit un multiple de 8. Cependant, je crains que le problème puisse réapparaître si les données dans le tampon mapped sont soumises à un traitement plus complexe. Certaines personnes ont signalé des problèmes similaires dans l'architecture arm64 liée à la fonction memcpy (par exemple [https://bugs.launchpad.net/linux-linaro/+bug/1271649]]).
Quelle est la méthode correcte pour mapper des tampons DMA cohérents à l'espace utilisateur pour éviter les erreurs d'alignement de la mémoire?
Merci beaucoup! En effet, c'était un problème. J'ai dû ignorer la suppression de ARCH_HAS_DMA_MMAP_COHERENT. Comme j'ai affaire à des SoCs - à la fois avec les FPGA et les pilotes de noyau, je trouve que mes connaissances sont de plus en plus difficiles à mettre à jour ... En fait, je suis assez amusé que le problème ne se soit pas produit. accès à la partie non-alignée du buffer! Je suis passé à dma_mmap_coherent (en rappelant de mettre vma-> vm_pgoff à 0, après qu'il soit utilisé pour définir le numéro du buffer) et tout fonctionne parfaitement. – wzab