2013-01-31 22 views
6

Desidero allocare un buffer DMA di grandi dimensioni, con una dimensione di circa 40 MB. Quando uso dma_alloc_coherent(), non riesce e quello che vedo è:Allocazione di un buffer DMA di grandi dimensioni

------------[ 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 ]--- 

Ho provato diversi valori e sembra che dma_alloc_coherent() non può allocare più di 2^25 byte (32 MB).

In che modo è possibile allocare un buffer DMA così grande?

+0

grandi buffer DMA sono costosi. Il blocco di memoria deve essere una memoria fisica contigua (a meno che non vi sia una MMU per I/O come in alcuni sistemi SPARC) e bloccata (non può essere sfogliata per fare spazio per gli errori di pagina da attività con priorità più alta). Soluzione tipica consiste nell'utilizzare più di un buffer DMA e utilizzare il concatenamento DMA (ovvero scatter/gather). Avete davvero un'operazione di I/O che trasferisce 40 MB in un blocco, o si tratta davvero di un accumulo di operazioni? – sawdust

+0

Il caso d'uso del software su cui sto lavorando richiede grandi buffer DMA per l'acquisizione di video e l'elaborazione di immagini da parte di hardware specializzato. Può essere fatto usando diversi buffer più piccoli, ma nel tempo la frammentazione rende problematici i processi di liberazione e riallocazione dei buffer. La dimensione e la quantità dei buffer DMA di cui ho bisogno sono fisse, quindi voglio allocare la memoria una volta all'avvio e gestire le richieste di memoria nello spazio utente. – miluz

+0

@miluz, hai risolto questo problema? Come ? – ransh

risposta

6

Dopo l'avvio del sistema, dma_alloc_coherent() non è necessariamente affidabile per allocazioni di grandi dimensioni. Ciò è dovuto al fatto che le pagine non mobili riempiono rapidamente la memoria fisica rendendo rari ampi intervalli contigui. Questo è stato un problema per molto tempo.

Convenientemente un set di patch recente può essere d'aiuto, questo è l'allocatore di memoria contiguo che è apparso nel kernel 3.5. Se stai usando un kernel con questo, dovresti essere in grado di passare cma=64M sulla riga di comando del kernel e che molta memoria sarà riservata (verranno posizionate solo le pagine mobili). Quando successivamente chiedi la tua allocazione 40M, dovrebbe avere successo in modo affidabile. Semplici!

Per maggiori informazioni consulta questo articolo LWN:

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

+0

L'allocazione della memoria al momento dell'avvio è abbastanza buona per me, quindi ho usato memblock_alloc_base() e memblock_remove(). A mio modo di vedere, queste funzioni dovrebbero allocare e rendere la memoria invisibile al kernel ed è contigua negli indirizzi fisici, rendendola così utile per il DMA. – miluz

+0

Penso che dovrebbe funzionare, ma è un po 'fuori dai sentieri battuti. Avrai anche problemi se vuoi un modulo del kernel che puoi caricare e scaricare. – jleahy