SO! Возможно, этот вопрос уже задавался, но я не смог найти ничего, что бы соответствовало моим потребностям. Я хочу создать буфер, который можно отобразить в пользовательское пространство (виртуальную непрерывную память), а также создать из него список рассеяния для операций DMA.
Вот как я это представляю:
- Выделить буфер (
vmalloc
)
Найти адрес шины для каждого байта этого буфера, построить следующую таблицу (вставьте новую строку в нее, только если физический адрес больше, чем PAGE_SIZE)
- (
struct scatterlist*
: адрес шины | длина)
Звоните dma_map_sg
, он заполнит dma_address
полей.
- Отправка dma_addresses на устройство вместе с длиной каждого физического буфера.
- Как-то привязать виртуальный буфер к пользовательскому пространству.
Проблемы, которые я вижу при таком подходе:
- Вы не можете указать, сколько частей непрерывной памяти вам нужно, используя
vmalloc
, что может привести к получению большего, чем может принять устройство PCI, хотя мое устройство может принимать только 8192 адреса шины, не более.
- Я не нашел ничего на шаге 2) алгоритма, описанного выше, кроме этого , и он на самом деле не компилируется.
- ioremap используется для отображения физической памяти в ядре, remap_pfn_range - для отображения физической памяти в пространство пользователя с помощью операций MMAP. Они оба ожидают физический адрес в качестве параметра. Как мне сопоставить виртуальный адрес ядра с пользовательским пространством?
По сути, я думаю, что есть кое-что, чего я не понимаю, и я не могу найти небольшой хороший пример того, как сделать это правильно. Интернет полон справочных таблиц, списков рассылки и прочего, но каждый реальный пример - это проект, состоящий из тысяч файлов, которые очень трудно быстро прогнать для новичка. Для подхода, который я пытаюсь реализовать, мне кажется, что я пытаюсь решить проблему X / Y . Есть ли лучший способ сделать это?
РЕДАКТИРОВАТЬ : найдено это . Похоже, я не могу напрямую получить все физические адреса памяти, выделенные с помощью vmalloc. Что я должен использовать вместо этого?
РЕДАКТИРОВАТЬ 2 : Некоторые думают, что я могу вместо этого просто использовать CMA и вообще не беспокоиться о списках разброса - из-за определенных правил проекта я не могу пересобрать ядро, и оно собрано без Поддержка CMA по умолчанию. Мне нужно как-то выделить 3 порции памяти по 4 ГБ для работы моих устройств.
РЕДАКТИРОВАТЬ 3 : Я не знаю, поможет ли это кому-нибудь ... Не буду отвечать на вопросы, хотя бы до тех пор, пока не узнаю, что это работает.
В принципе, то, что у меня есть на данный момент, позволяет мне выделить 12 ГБ памяти без паники ядра (для этого требуется, чтобы ваше устройство поддерживало 64-битные адреса):
dma_set_mask_and_coherent(pdev, DMA_BIT_MASK(64));
dma_pool_create(...);
dma_pool_alloc(...) for as many chunks of memory as you need.
Теперь вопрос стоит, смогу ли я отобразить все эти фрагменты памяти и эффективно прокрутить их.