Aquí es lo que he utilizado, en resumen ...
get_user_pages
de precisar la página (s) del usuario y le dará una serie de struct page *
punteros.
dma_map_page
en cada struct page *
para obtener la dirección DMA (también conocida como "dirección de E/S") para la página. Esto también crea una asignación de IOMMU (si es necesario en su plataforma).
Ahora indique a su dispositivo que realice el DMA en la memoria usando esas direcciones DMA. Obviamente, pueden ser no contiguos; la memoria solo está garantizada para ser contigua en múltiplos del tamaño de la página.
dma_sync_single_for_cpu
para hacer cualquier descarga de memoria caché necesaria o amortiguador de rebote blitting o lo que sea. Esta llamada garantiza que la CPU realmente puede ver el resultado del DMA, ya que en muchos sistemas, la modificación de la memoria RAM física detrás de la CPU da como resultado memorias caché obsoletas.
dma_unmap_page
para liberar la asignación de IOMMU (si fue necesario en su plataforma).
put_page
para anular las páginas del usuario (s).
Tenga en cuenta que debe comprobar errores hasta el final aquí, porque hay recursos limitados por todas partes. get_user_pages
devuelve un número negativo para un error absoluto (-errno), pero puede devolver un número positivo para decirle cuántas páginas logró anclar (la memoria física no es ilimitada). Si es menor de lo que solicitó, debe recorrer todas las páginas en las que hizo el pin para llamar al put_page
. (De lo contrario se filtra la memoria del núcleo;. Muy mal)
dma_map_page
también puede devolver un error (-errno), debido a las asignaciones IOMMU son otro recurso limitado.
dma_unmap_page
y put_page
return void
, como es habitual para las funciones de "liberación" de Linux. (Las rutinas de administración de recursos del kernel de Linux solo devuelven errores porque algo salió mal, no porque se equivocó y pasó un puntero malo o algo. La suposición básica es que usted está nunca atornillando porque este es el código del kernel.Aunque get_user_pages
sí verifica para garantizar la validez de las direcciones de usuario y devolverá un error si el usuario le entregó un puntero incorrecto)
También puede considerar el uso de las funciones _sg si desea una interfaz amigable para dispersar/reunir. De allí tendría que llamar en lugar de dma_map_sg
dma_map_page
, en lugar de dma_sync_sg_for_cpu
dma_sync_single_for_cpu
, etc.
También tenga en cuenta que muchas de estas funciones pueden ser más o menos no-ops en su plataforma, lo que a menudo puede salirse con ser descuidado . (En particular, dma_sync _... y dma_unmap _... no hacen nada en mi sistema x86_64.) Pero en esas plataformas, las llamadas mismas se compilan en nada, por lo que no hay excusa para ser descuidado.
Compre LDD http://lwn.net/Kernel/LDD3/ y busque la implementación de mmap() en un controlador de dispositivo. – Dummy00001
Tengo LDD ... ¿me puede decir el nombre de algunos controladores de dispositivo para buscar? –
@ Dummy00001 ¿Qué pasa con el direccionamiento físico/virtual? –