Я планирую написать драйвер linux для некоторого оборудования с отображением памяти (он находится в FPGA, поэтому при необходимости я могу настроить этот интерфейс с отображением памяти на обоих концах).
Эта логика FPGA генерирует последовательность дейтаграмм, которые я должен обработать, а затем передать по каналу Ethernet. Нет никаких причин для того, чтобы ни обработка, ни сетевой код находились в ядре, поэтому я спрашиваю о «лучшем» механизме перемещения блоков данных с оборудования в пространство пользователя. Самая большая сложность заключается в том, что обработка пользовательского пространства должна распределяться между несколькими процессами.
Скорость передачи данных не очень высока (до 1 Мбит / с), а интерфейс mmio питается от довольно глубокого FIFO (2 КБ в настоящее время может быть увеличено до 8 КБ), поэтому я думаю, что процесс пользовательского режима с высоким приоритетом может не отставать.
Что мне действительно нужно, так это указатель на существующий драйвер с существующим интерфейсом многоадресного пользовательского пространства (и не усложняющий многое другое). Но план того, что необходимо сделать, был бы разумной заменой.
Пока что я собрал следующие идеи:
AF_NETLINK: поддерживает многоадресную рассылку, заботится о буферизации за меня. Но API нестабилен, мне нужно определить новый идентификатор сокета, который может конфликтовать с другими драйверами в дереве, а интерфейс пользовательского режима довольно специализирован, я не могу использовать стандартные инструменты, такие как
socat
, для тестирования потока данных.Передайте сокет режима дейтаграммы или дескриптор файла FIFO из пользовательского пространства и напишите в него (как?). Есть патч многоадресной рассылки сокета дейтаграммы домена unix, который я мог бы применить.
Предоставьте устройство в символьном режиме одному высокоприоритетному приложению пользовательского режима, которое действует как сервер сокетов дейтаграмм домена unix и копирует дейтаграммы на каждый подключенный узел. Сохраняются ли границы дейтаграммы для устройств с символьным режимом (т.е. если моя функция драйвера
read
возвращает меньше байтов, чем размерfread
буфера,fread
будет возвращать этот блок данных как единицу, или он может фрагментировать и повторно собирать блоки? Помогает ли это, если я используюread (2)
вместоfread (3)
? Есть ли что-нибудь вродеEMSGSIZE
, которое функция чтения драйвера может использовать, чтобы указать, что дейтаграмма была усечена, или это доступно только для сокетов?)Предоставьте устройство символьного режима, которое может быть открыто несколькими приложениями пользовательского режима одновременно, и буферизуйте данные для каждого в ядре.
Я склоняюсь к устройству символьного режима с сервером домена unix, который перенаправляет входящие пакеты. Это избавляет меня от необходимости реализовывать логику буферизации внутри драйвера ядра. Тогда возникает вопрос, как разбудить пользовательский процесс от select
вызова или блокирующего чтения при возникновении прерывания. Кажется, моя функция poll
может читать регистр управления и возвращать POLLIN|POLLRDNORM
, если данные уже доступны, и демаскировать прерывание, если нет. И тогда обработчик прерывания будет использовать wake_up
, чтобы пометить wait_queue
как готовый. read
всегда маскирует прерывание.