Библиотека сайта rus-linux.net
Цилюрик О.И. Модули ядра Linux | ||
Назад | Обслуживание периферийных устройств | Вперед |
DMA
Работа PCI устройства может быть предусмотрена как по прямому чтению адресов ввода/вывода, так и (что гораздо чаще) пользуясь механизмом DMA (Direct Memory Access). Передача данных по DMA организуется на аппаратном уровне, и выполняется (например, когда программа запрашивает данные через такую функцию, например, как read()) в таком порядке:
- когда процесс вызывает read(), метод драйвера выделяет буфер DMA (или указывает адрес в ранее выделенном буфере) и выдаёт команду оборудованию передавать свои данные в этот буфер (указывая в этой команде адрес начала передачи и объём передачи); процесс после этого блокируется;
- периферийное устройство аппаратно захватывает шину обмена и записывает данные последовательно в буфер DMA с указанного адреса, после этого вызывает прерывание, когда весь заказанный объём передан;
- обработчик прерывания получает входные данные, подтверждает прерывание и переводит процесс в активное состояние, процесс теперь имеет возможность читать данные.
Установленные в системе каналы обмена по DMA отображаются в файловую систему /proc:
$ cat /proc/dma
2: floppy 4: cascade
Организация обмена по DMA это основной способ взаимодействия со всеми высокопроизводительными устройствами. С другой стороны, обмен по DMA полностью зависим от деталей аппаратной реализации, поэтому в общем виде может быть рассмотрен только достаточно поверхностно. Буфера DMA могут выделяться только в строго определённых областях памяти:
- эта память должна распределяться в физически непрерывной области памяти, выделение посредством vmalloc() неприменимо, память под буфера должна выделяться kmalloc() или __get_free_pages();
- для многих архитектур выделение памяти должно быть специфицировано с флагом GFP_DMA, для x86 это будет выделение ниже адреса MAX_DMA_ADDRESS=16MB;
- память должна выделяться начиная с границы страницы физической памяти, и в объёме целых страниц физической памяти;
Для распределения памяти под буфера DMA предоставляются несколько альтернативных групп API, их реализации полностью архитектурно зависимы, но вызовы создают уровень абстракций:
1. Coherent DMA mapping:
void *dma_alloc_coherent( struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag ); void dma_free_coherent( struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle );
- здесь не требуется распределять предварительно буфер DMA, этот способ применяется для устойчивых распределений многократно (повторно) используемых буферов.
2. Streaming DMA mapping:
dma_addr_t dma_map_single( struct device *dev, void *ptr, size_t size, enum dma_data_direction direction ); void dma_unmap_single( struct device *dev, dma_addr_t dma_handle, size_t size, enum dma_data_direction direction );
- где direction это направление передачи данных: PCI_DMA_TODEVICE, PCI_DMA_FROMDEVICE, PCI_DMA_BIDIRECTIONAL, PCI_DMA_NONE ; этот способ применяется для выделения под однократные операции.
3. DMA pool:
#include <linux/dmapool.h>
struct dma_pool *dma_pool_create( const char *name, struct device *dev,
size_t size, size_t align, size_t allocation );
void dma_pool_destroy( struct dma_pool *pool );
void *dma_pool_alloc( struct dma_pool *pool, gfp_t mem_flags, dma_addr_t *handle );
void dma_pool_free( struct dma_pool *pool, void *vaddr, dma_addr_t handle );
- часто необходимо частое выделение малых областей для DMA обмена, dma_alloc_coherent() допускает минимальное выделение в одну физическую страницу; в этом случае оптимальным становится dma_pool().
4. Старый (перешедший из ядра 2.4) API, PCI-специфический интерфейс — два (две пары вызовов) метода, аналогичных, соответственно п.1 и п.2:
void *pci_alloc_consistent( struct device *dev, size_t size, dma_addr_t *dma_handle ); void pci_free_consistent( struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle ); dma_addr_t pci_map_single( struct device *dev, void *ptr, size_t size, int direction ); void pci_unmap_single( struct device *dev, dma_addr_t dma_handle, size_t size, int direction );
Примеры использования API однотипны и достаточно громоздки. Некоторые примеры использования показаны в архиве dma.tgz, результаты выполнения показаны там же в файле dma.hist.
Предыдущий раздел: | Оглавление | Следующий раздел: |
Отображение памяти | Устройства USB |