У меня есть плата на базе Xilinx Zynq 7000 с периферийным устройством в матрице FPGA, которое поддерживает DMA (на шине AXI). Мы разработали схему и запускаем Linux на ядрах ARM. У нас возникают проблемы с производительностью при доступе к буферу DMA из пользовательского пространства после того, как он был заполнен оборудованием.
Резюме:
Мы заранее зарезервировали во время загрузки раздел DRAM для использования в качестве большого буфера DMA. Очевидно, мы используем неправильные API для сопоставления этого буфера, потому что он кажется некэшированным, а скорость доступа ужасна.
Использование его даже в качестве буфера отказов неоправданно медленно из-за ужасной производительности. IIUC, кеши ARM не согласованы с DMA, поэтому я был бы очень признателен за понимание того, как сделать следующее:
- Сопоставьте область DRAM с виртуальным адресным пространством ядра, но убедитесь, что она кэшируемая.
- Убедитесь, что отображение его в пользовательское пространство также не имеет нежелательного эффекта, даже если для этого требуется, чтобы мы выполняли вызов mmap нашим собственным драйвером.
- Явно аннулируйте область физической памяти из иерархии кешей перед выполнением прямого доступа к памяти, чтобы гарантировать согласованность.
Больше информации:
Я пытался тщательно изучить это, прежде чем спрашивать. К сожалению, поскольку это ARM SoC / FPGA, информации об этом очень мало, поэтому я должен спросить напрямую у экспертов.
Поскольку это SoC, многие вещи жестко запрограммированы для u-boot. Например, ядро и виртуальный диск загружаются в определенные места в DRAM перед передачей управления ядру. Мы воспользовались этим, чтобы зарезервировать раздел DRAM размером 64 МБ для буфера DMA (он должен быть таким большим, поэтому мы предварительно зарезервировали его). Не стоит беспокоиться о конфликтах типов памяти или о том, что ядро использует эту память, потому что параметры загрузки сообщают ядру, над какой областью DRAM оно контролирует.
Первоначально мы пытались сопоставить этот диапазон физических адресов с пространством ядра с помощью ioremap, но это, похоже, указывает на то, что область не кэшируется, а скорость доступа ужасна, даже если мы попытаемся использовать memcpy, чтобы сделать ее буфером отказов. Мы используем / dev / mem, чтобы отобразить это также в пользовательском пространстве, и я рассчитал, что memcpy составляет около 70 МБ / сек.
Основываясь на значительном количестве поисков по этой теме, кажется, что, хотя половина людей хотят использовать ioremap таким образом (вероятно, отсюда мы и взяли эту идею), ioremap не должен использоваться для этой цели, и что есть API, относящиеся к DMA, которые следует использовать вместо них. К сожалению, кажется, что выделение буфера DMA полностью динамическое, и я не понял, как это сказать: «вот уже выделенный физический адрес - используйте его».
Я просмотрел один документ, но он слишком ориентирован на x86 и ПК: https://www.kernel.org/doc/Documentation/DMA-API-HOWTO.txt
И этот вопрос также появляется в верхней части моих поисков, но настоящего ответа нет: получить физический адрес буфера в Linux
Если посмотреть на стандартные вызовы, dma_set_mask_and_coherent и семейство не будут принимать заранее определенный адрес и хотят иметь структуру устройства для PCI. У меня такой структуры нет, потому что это ARM SoC без PCI. Я мог бы вручную заполнить такую структуру, но для меня это пахнет злоупотреблением API, а не использованием его по назначению.
Кстати: это кольцевой буфер, в котором мы DMA блоки данных в разные смещения, но мы выравниваем по границам строки кеша, поэтому нет риска ложного разделения.
Спасибо вам огромное за любую помощь, которую вы можете оказать!
ОБНОВЛЕНИЕ: Похоже, что на ARM не существует такой вещи, как кэшируемый буфер DMA, если вы делаете это обычным способом. Возможно, если я не сделаю вызов ioremap, регион не будет помечен как некэшируемый, но тогда мне нужно выяснить, как управлять кешем на ARM, чего я не могу понять. Одна из проблем заключается в том, что memcpy в пользовательском пространстве действительно отстой. Есть ли реализация memcpy, оптимизированная для некэшированной памяти, которую я могу использовать? Может быть, я мог бы написать один. Я должен выяснить, есть ли у этого процессора Neon.
memremap()
? Это, вероятно, наиболее подходящий инструмент для работы - здесь обсуждаются и другие вещи, касающиеся выделения буферов DMA из памяти ядра.ioremap()
семантически близок к правильному подходу, т. Е. Отображению некоторой внешней области в адресное пространство ядра, но приведет к отображению ее как памяти устройства, даже не обычного некэшируемого. - person Notlikethat   schedule 20.01.2016