2013-01-31 18 views
6

Chcę przydzielić duży bufor DMA o rozmiarze około 40 MB. Gdy używam dma_alloc_coherent(), że nie powiedzie się i co widzę to:Przydzielanie dużego bufora DMA

------------[ cut here ]------------ 
WARNING: at mm/page_alloc.c:2106 __alloc_pages_nodemask+0x1dc/0x788() 
Modules linked in: 
[<8004799c>] (unwind_backtrace+0x0/0xf8) from [<80078ae4>] (warn_slowpath_common+0x4c/0x64) 
[<80078ae4>] (warn_slowpath_common+0x4c/0x64) from [<80078b18>] (warn_slowpath_null+0x1c/0x24) 
[<80078b18>] (warn_slowpath_null+0x1c/0x24) from [<800dfbd0>] (__alloc_pages_nodemask+0x1dc/0x788) 
[<800dfbd0>] (__alloc_pages_nodemask+0x1dc/0x788) from [<8004a880>] (__dma_alloc+0xa4/0x2fc) 
[<8004a880>] (__dma_alloc+0xa4/0x2fc) from [<8004b0b4>] (dma_alloc_coherent+0x54/0x60) 
[<8004b0b4>] (dma_alloc_coherent+0x54/0x60) from [<803ced70>] (mxc_ipu_ioctl+0x270/0x3ec) 
[<803ced70>] (mxc_ipu_ioctl+0x270/0x3ec) from [<80123b78>] (do_vfs_ioctl+0x80/0x54c) 
[<80123b78>] (do_vfs_ioctl+0x80/0x54c) from [<8012407c>] (sys_ioctl+0x38/0x5c) 
[<8012407c>] (sys_ioctl+0x38/0x5c) from [<80041f80>] (ret_fast_syscall+0x0/0x30) 
---[ end trace 4e0c10ffc7ffc0d8 ]--- 

Próbowałem różnych wartości i wygląda dma_alloc_coherent() nie może przeznaczyć więcej niż 2^25 bajtów (32 MB).

W jaki sposób można przydzielić tak duży bufor DMA?

+0

Duże bufory DMA są drogie. Blok pamięci musi być przyległą pamięcią fizyczną (chyba że istnieje MMU dla I/O, jak w niektórych systemach SPARC) i zablokowany (nie może być stronicowany, aby zrobić miejsce na błędy strony przez zadania o wyższym priorytecie). Typowym obejściem jest użycie więcej niż jednego bufora DMA i wykorzystanie łańcucha DMA (inaczej rozpraszanie/zbieranie). Czy naprawdę masz operację We/Wy, która przesyła 40 MB w jednym bloku, czy to naprawdę nagromadzenie operacji? – sawdust

+0

Używanie oprogramowania, nad którym pracuję, wymaga dużych buforów DMA do przechwytywania wideo i przetwarzania obrazu przez wyspecjalizowany sprzęt. Można tego dokonać za pomocą kilku mniejszych buforów, ale z czasem fragmentacja sprawia, że ​​uwalnianie i ponowne przydzielanie buforów jest problematyczne. Rozmiar i ilość buforów DMA, których potrzebuję, jest poprawiona, więc chcę przydzielić pamięć raz podczas rozruchu i zarządzać żądaniami pamięci w przestrzeni użytkownika. – miluz

+0

@miluz, rozwiązałeś ten problem? w jaki sposób ? – ransh

Odpowiedz

6

Po uruchomieniu systemu dma_alloc_coherent() niekoniecznie jest niezawodny dla dużych przydziałów. Dzieje się tak po prostu dlatego, że strony, które nie są ruchome, szybko wypełniają pamięć fizyczną, przez co rzadkie są duże, sąsiednie zakresy. To był problem przez długi czas.

Dogodnie najnowszy zestaw poprawek może ci pomóc, jest to przydział pamięci, który pojawił się w jądrze 3.5. Jeśli używasz jądra z tym, powinieneś być w stanie przekazać cma=64M na linii poleceń jądra i tyle pamięci zostanie zarezerwowane (tylko ruchome strony będą tam umieszczone). Gdy następnie poprosisz o przydzielenie 40M, powinno to zakończyć się sukcesem. Simples!

Aby uzyskać więcej informacji, zobacz ten artykuł LWN:

https://lwn.net/Articles/486301/

+0

Przydzielanie pamięci w czasie rozruchu jest wystarczająco dobre dla mnie, więc użyłem memblock_alloc_base() i memblock_remove(). Według mojej wiedzy, funkcje te powinny przydzielać i uczynić niewidzialną pamięć jądra i sąsiadują z adresami fizycznymi, dzięki czemu dobrze jest używać DMA. – miluz

+0

Myślę, że to powinno działać, ale jest trochę na uboczu. Będziesz mieć również problemy, jeśli chcesz moduł jądra, który możesz załadować i rozładować. – jleahy