Мне нужно предоставить огромный кольцевой буфер (несколько ГБ) для устройства DMA PCIe, управляющего шиной, реализованного в FPGA.
Буферы не должны резервироваться во время загрузки. Следовательно, буфер может быть несмежным.
Устройство поддерживает операцию рассеяния-сбора (SG), но из соображений производительности адреса и длины последовательных непрерывных сегментов буфера хранятся внутри FPGA. Поэтому использование стандартных страниц размером 4 КБ неприемлемо (на каждый 1 ГБ буфера приходится до 262144 сегментов).
Правильное решение должно выделить буфер, состоящий из огромных страниц размером 2 МБ, в пользовательском пространстве (уменьшив максимальное количество сегментов в 512 раз). Виртуальный адрес буфера должен быть передан драйверу ядра через ioctl. Затем следует вычислить адреса и длину сегментов и записать их в ПЛИС.
Теоретически я мог бы использовать get_user_pages для создайте список страниц, а затем вызовите sg_alloc_table_from_pages для получения списка SG, подходящего для программирования механизма прямого доступа к памяти в FPGA. К сожалению, в этом подходе я должен подготовить промежуточный список структур страниц длиной 262144 страниц на 1 ГБ буфера. Этот список хранится в ОЗУ, а не в ПЛИС, поэтому с ним меньше проблем, но в любом случае было бы неплохо его избежать.
На самом деле мне не нужно сохранять сопоставление страниц для ядра, так как огромные страницы защищены от выгрузки и сопоставлены для приложения пользовательского пространства, которое будет обрабатывать полученные данные.
Итак, я ищу функцию sg_alloc_table_from_user_hugepages
, которая могла бы взять такой адрес пользовательского пространства буфера памяти на основе огромных страниц и передать его непосредственно в правильный список разброса, не выполняя ненужного и потребляющего память сопоставления для ядра. Конечно, такая функция должна проверять, действительно ли буфер состоит из огромных страниц.
Я нашел и прочитал следующие сообщения: (A) , (B), но не смог не найти хороший ответ. Есть ли какой-нибудь официальный способ сделать это в текущем ядре Linux?