Могу ли я вызвать dma_map_single() на устройстве DeviceB, используя адреса, возвращенные из dma_alloc_coherent на устройстве A?

Я пишу собственный драйвер Linux, которому требуется память DMA между несколькими устройствами PCIE. У меня следующая ситуация:

  1. Я использую dma_alloc_coherent для выделения памяти для DeviceA
  2. Затем я использую DeviceA для заполнения буфера памяти.

Пока все в порядке, но на данный момент я хотел бы DMA памяти для DeviceB, и я не уверен, как правильно это сделать.

Сейчас я вызываю dma_map_single для DeviceB, используя адрес, возвращенный из dma_alloc_coherent, вызванного для DeviceA. Кажется, это нормально работает в x86_64, но кажется, что я нарушаю правила, потому что:

  1. Предполагается, что dma_map_single вызывается с памятью, выделенной из kmalloc (и других). Это проблема вызова с адресом, возвращенным из вызова dma_alloc_coherent другого устройства?

  2. Если с #1 все в порядке, то я все еще не уверен, нужно ли вызывать функции dma_sync_*, которые необходимы для памяти dma_map_single. Поскольку память изначально была выделена из dma_alloc_coherent, это должна быть некэшированная память, поэтому я считаю, что вызовы dma_sync_* не нужны, но я не уверен.

Я беспокоюсь, что мне просто повезло с этой работой, и будущее обновление ядра сломает меня, поскольку неясно, правильно ли я следую правилам API. Мой код в конечном итоге должен будет работать и на ARM, и на PPC, поэтому мне нужно убедиться, что я делаю что-то независимо от платформы, а не обходюсь каким-то хаком с архитектурой x86_64.

Я использую это как ссылку: https://www.kernel.org/doc/html/latest/core-api/dma-api.html


person Vern    schedule 26.07.2021    source источник
comment
Существует совместное использование буфера и синхронизация раздел о [...] совместном использовании буферов для доступа к оборудованию (DMA) между несколькими драйверами устройств и подсистемами, а также для синхронизации асинхронного доступа к оборудованию в Руководство по API для разработчиков драйверов Linux, которое может оказаться полезным.   -  person Pixelchemist    schedule 27.07.2021
comment
Вы правы, использование возвращаемого адреса для dma_map_single() пахнет взломом. Поскольку вы работаете с устройствами PCIe, вы должны иметь возможность использовать передачу DMA p2p.   -  person 0andriy    schedule 27.07.2021


Ответы (1)


  1. dma_alloc_coherent() действует аналогично __get_free_pages(), но в качестве детализации размера, а не страницы, поэтому я не думаю, что здесь проблема.
  2. Сначала вызовите dma_mapping_error() после dma_map_single() для любой проблемы, связанной с платформой. dma_sync_*() помощники используются при потоковой операции прямого доступа к памяти для синхронизации устройства и ЦП. Требуется как минимум dma_sync_single_for_cpu(), поскольку состояние доступа к модифицированным буферам устройства необходимо синхронизировать, прежде чем ЦП его использует.
person tej parkash    schedule 27.07.2021
comment
@tej как вы думаете, почему в этом случае необходимы функции dma_sync_*? Память была выделена с помощью dma_alloc_coherent(), которая по определению является некэшируемой памятью. Функции dma_sync_* предназначены для синхронизации кэшей разных архитектур, поэтому я не думаю, что они окажут какое-либо влияние на некэшированную память. - person Vern; 27.07.2021
comment
Согласно документации Linux для функции dma_alloc_coherent() Непротиворечивая память — это память, для которой запись устройства или процессора может быть немедленно прочитана процессором или устройством, не беспокоясь об эффектах кэширования. (Однако вам может понадобиться убедиться, что буферы записи процессора очищены, прежде чем сообщать устройствам о необходимости чтения этой памяти.) Таким образом, нам нужно использовать dma_sync_*() для некэшированной памяти. - person tej parkash; 28.07.2021
comment
Нельзя ли использовать соответствующий барьер памяти (т. е. wmb() в ядре Linux или встроенный _sync_synchronize() gcc) для очистки буферов записи процессора? Я не указал эту деталь в вопросе, но эта память будет mmap'ирована в пользовательское пространство, где у меня не будет доступа к функциям dma_sync*. Я не хочу, чтобы мой модуль ядра выполнял dma_sync_* дополнительные накладные расходы на IOCTL. - person Vern; 29.07.2021
comment
Спасибо всем за комментарии. Не похоже, что для моей схемы есть какие-то большие красные флажки, но я определенно нахожусь на грани того, как должен был использоваться API. Судя по всему, что я тестировал до сих пор, это работает. Я просто надеюсь, что будущие ядра не сломают его. - person Vern; 29.07.2021