Нужна помощь в сопоставлении предварительно зарезервированного ** кешируемого ** буфера DMA на Xilinx / ARM SoC (Zynq 7000)

У меня есть плата на базе Xilinx Zynq 7000 с периферийным устройством в матрице FPGA, которое поддерживает DMA (на шине AXI). Мы разработали схему и запускаем Linux на ядрах ARM. У нас возникают проблемы с производительностью при доступе к буферу DMA из пользовательского пространства после того, как он был заполнен оборудованием.

Резюме:

Мы заранее зарезервировали во время загрузки раздел DRAM для использования в качестве большого буфера DMA. Очевидно, мы используем неправильные API для сопоставления этого буфера, потому что он кажется некэшированным, а скорость доступа ужасна.

Использование его даже в качестве буфера отказов неоправданно медленно из-за ужасной производительности. IIUC, кеши ARM не согласованы с DMA, поэтому я был бы очень признателен за понимание того, как сделать следующее:

  1. Сопоставьте область DRAM с виртуальным адресным пространством ядра, но убедитесь, что она кэшируемая.
  2. Убедитесь, что отображение его в пользовательское пространство также не имеет нежелательного эффекта, даже если для этого требуется, чтобы мы выполняли вызов mmap нашим собственным драйвером.
  3. Явно аннулируйте область физической памяти из иерархии кешей перед выполнением прямого доступа к памяти, чтобы гарантировать согласованность.

Больше информации:

Я пытался тщательно изучить это, прежде чем спрашивать. К сожалению, поскольку это 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.


person Timothy Miller    schedule 19.01.2016    source источник
comment
Какую версию ядра Linux вы используете? Вы пробовали использовать Contiguous Memory Allocator? ...   -  person TheCodeArtist    schedule 19.01.2016
comment
@TheCodeArtist Linux (нет) 3.17.0-xilinx-dirty # 13 SMP PREEMPT Понедельник, 3 августа 12:10:57 MDT 2015 armv7l GNU / Linux Кроме того, я не смотрел на CMA. Если я могу правильно отобразить этот буфер, он не должен требовать CMA, если только невозможно указать буфер DMA из предварительно зарезервированного физического адреса.   -  person Timothy Miller    schedule 19.01.2016
comment
Для получения физического адреса буфера под Linux (это из пользовательского пространства) stackoverflow.com/a/28987409/1163019. Для DMA / некэшированного материала afaik, и, честно говоря, я не помню всех деталей, и мне не удалось выполнить другую задачу, но то, что я вижу из кода, это то, что я пытался dma_alloc_coherent - ›обновить vma-› vm_page_prot как написано - ›dma_mmap_from_coherent - ›remap_pfn_range. Также может помочь эта презентация? events.linuxfoundation.org/sites/events/files/slides/   -  person auselen    schedule 19.01.2016
comment
@auselen Мне не нужен физический адрес. Я знаю это во время загрузки. И я могу отобразить его в пользовательском пространстве с помощью / dev / mem. Однако, если я использую ioremap в ядре, он делает пространство некэшированным, что убивает скорость доступа. dma_alloc_coherent будет динамически выделять только относительно небольшие разделы, тогда как у нас уже есть большой непрерывный предварительно выделенный буфер, в который нам нужно DMA. Проверю презентацию. Спасибо.   -  person Timothy Miller    schedule 19.01.2016
comment
Похоже, что реализация ARM полностью лишена возможности иметь некогерентный буфер DMA.   -  person Timothy Miller    schedule 19.01.2016
comment
В репозиториях исходного кода Android есть множество оптимизированных memcpy или многих других мест.   -  person auselen    schedule 19.01.2016
comment
Моя проблема была противоположной, я пытался отключиться. Я думал, что remap_pfn_range должен помочь с размерами dma. В любом случае остановлюсь сейчас :)   -  person auselen    schedule 19.01.2016
comment
zynq ›процессор cat / proc / cpuinfo: 0 название модели: ARMv7 Processor rev 0 (v7l) Характеристики: половина большого пальца fastmult vfp edsp neon vfpv3 tls vfpd32 Реализация процессора: 0x41 Архитектура процессора: 7 Вариант процессора: 0x3 Часть процессора: 0xc09 Версия процессора: 0 процессор: 1 название модели: ARMv7 Processor rev 0 (v7l) Характеристики: половина большого пальца fastmult vfp edsp neon vfpv3 tls vfpd32 Реализация процессора: 0x41 Архитектура процессора: 7 Вариант процессора: 0x3 Часть процессора: 0xc09 Версия процессора: 0 Оборудование: Xilinx Zynq Platform Ревизия: 0003 Номер: 0000000000000000   -  person Timothy Miller    schedule 20.01.2016
comment
вот и ваша неоновая опора.   -  person auselen    schedule 20.01.2016
comment
Достаточно ли новое ваше ядро, чтобы иметь memremap()? Это, вероятно, наиболее подходящий инструмент для работы - здесь обсуждаются и другие вещи, касающиеся выделения буферов DMA из памяти ядра. ioremap() семантически близок к правильному подходу, т. Е. Отображению некоторой внешней области в адресное пространство ядра, но приведет к отображению ее как памяти устройства, даже не обычного некэшируемого.   -  person Notlikethat    schedule 20.01.2016
comment
@ Notlikethat я думаю, что в моем ядре 3.17 есть memremap. Но, глядя на код, он, вероятно, просто перейдет в ioremap_cache, и я не уверен, что это работает для ARM. Могу попробовать разные комбинации. Одна вещь, которую я также собираюсь попробовать, - это просто извлечь карту памяти из драйвера для буфера DMA и просто отобразить ее в пользовательское пространство с помощью / dev / mem. Однако в моем драйвере есть еще одна потенциальная ошибка, которая подсказывает мне, что состояние по умолчанию по умолчанию не кэшировано.   -  person Timothy Miller    schedule 20.01.2016


Ответы (3)


Пробовали ли вы реализовать собственное символьное устройство с mmap() методом переназначения вашего буфера как кэшируемого (с помощью remap_pfn_range())?

person SergeyT    schedule 26.01.2016

Я считаю, что вам нужен драйвер, реализующий mmap (), если вы хотите, чтобы отображение было кэшировано.

Для этого мы используем два драйвера устройств: portalmem и zynqportal. В проекте Connectal мы называем соединение между программным обеспечением пространства пользователя и логикой FPGA «порталом». Для этих драйверов требуется dma-buf, который является стабильным для нас, начиная с версии ядра Linux 3.8.x.

Драйвер portalmem предоставляет ioctl для выделения блока памяти с подсчетом ссылок. и возвращает дескриптор файла, связанный с этой памятью. Этот драйвер реализует совместное использование dma-buf. Он также реализует mmap (), чтобы приложения пользовательского пространства могли получать доступ к памяти.

Во время выделения приложение может выбрать кэшированное или некэшированное отображение памяти. На x86 отображение всегда кэшируется. Наша реализация mmap () в настоящее время начинается с строки 173 драйвера portalmem. Если отображение не кэшировано, оно изменяет vma-> vm_page_prot с помощью pgprot_writecombine (), разрешая буферизацию записи, но отключая кеширование.

Драйвер portalmem также предоставляет ioctl для аннулирования и, при необходимости, обратной записи строк кэша данных.

Драйвер portalmem ничего не знает о FPGA. Для этого мы используем драйвер zynqportal, который предоставляет ioctl для передачи таблицу трансляции в FPGA, чтобы мы могли использовать логически смежные адреса на FPGA и преобразовывать их в фактические адреса DMA. Схема размещения, используемая portalmem, предназначена для создания компактных таблиц перевода.

Мы используем тот же драйвер portalmem с pcieportal для ПЛИС, подключенных к PCI Express, с никаких изменений в пользовательском программном обеспечении.

person Jamey Hicks    schedule 02.02.2016
comment
На x86 все это просто. Что касается ARM, я изучал, как обеспечить согласованность кеша через протокол AXI, но мне еще предстоит выяснить, как выделить или сопоставить кэшируемый буфер DMA. Некоторые предложения (например, memremap) - это то, что мне нужно будет проверить, когда у меня будет возможность. - person Timothy Miller; 03.02.2016
comment
Для ARM это зависит от того, как AXI подключен к инфраструктуре памяти. Например, на Zynq есть 5 портов AXI, которые можно использовать для программирования для доступа к DRAM процессора. 4 из них не отслеживаются кеш-памятью процессора и поэтому не являются когерентными. Пятый (ACP) отслеживается, поэтому может быть согласован с кешем. Область памяти должна быть отображена кэшируемой в пользовательский процесс. - person Jamey Hicks; 17.02.2016

Zynq имеет неоновые инструкции, а реализация memcpy в ассемблерном коде с использованием неоновых инструкций с использованием выровненных по границе кеша (32 байта) обеспечивает скорость 300 МБ / с или выше.

person Xilinx User    schedule 20.07.2017