Вопрос

Я планирую написать драйвер Linux для некоторого оборудования, отображаемого в памяти (он находится в FPGA, поэтому я могу настроить этот интерфейс с памятью на обоих концах, если это необходимо).

Эта логика FPGA генерирует последовательность Datagrams, которые я должен обработать, а затем передавать по ссылке Ethernet. Нет никаких причин, чтобы обработка или сетевой код находился в ядре, поэтому я спрашиваю о «лучшем» механизме для перемещения блоков данных от аппаратного обеспечения в пространство пользователя. Самое большое осложнение заключается в том, что обработка пространства пользователя должна быть распределена между несколькими процессами.

Скорость передачи данных не очень высока (до 1 Мбит / с), а интерфейс MMIO кормится довольно глубоким FIFO (в настоящее время 2 КБ может быть увеличен до 8 КБ), поэтому я думаю, что процесс пользовательского режима с высоким приоритетом может не отставать.

Что я действительно хотел бы, так это указатель на существующий драйвер с существующим многоадресным интерфейсом пользовательского пространства (и не сложно с большим количеством). Но описание того, что должно быть сделано, будет разумным заменой.

До сих пор я собрал следующие идеи:

  • AF_NETLINK: поддерживает многоадресную рассылку, заботится о буферизации для меня. Но API нестабилен, я должен определить новый идентификатор сокета, который может противоречить другим драйверам в дереве, а интерфейс пользовательского режима довольно специализирован, я не могу использовать стандартные инструменты, такие как socat Чтобы проверить поток данных.

  • Передайте сокет Datagram-Mode или Descriptor FIFO File из пользовательского пространства и напишите на него (как?). Есть многоадресный патч с ватаграммой Unix-Domain, который я мог бы применить.

  • Поместите устройство с символом для одного приложения пользовательского режима, которое действует как сервер Datagram Datagram Unix-Domain и копирует Datagrams для каждого подключенного узла. Границы Datagram сохранились для устройств с символом (то есть, если мой драйвер read функция возвращает меньше байтов, чем fread размер буфера, будет fread вернуть этот блок данных в качестве единицы, или он может фрагментировать и собрать блоки? Помогает ли это, если я использую read (2) вместо fread (3)? Есть ли что -то похожее на EMSGSIZE что функция чтения драйвера может использовать, чтобы указать, что дейтаграмма была усечена, или это доступно только для сокетов?)

  • Разместите устройство с символом, которое может быть открыто несколькими приложениями пользовательского режима одновременно, и буферизируют данные для каждого внедорожного.

Я склоняюсь к устройству с символом с помощью доменного сервера Unix, который перенаправляет входящие пакеты. Это спасает меня от необходимости реализовать логику буферизации внутри драйвера ядра. Тогда возникает вопрос, как разбудить пользовательский процесс из select Вызовите или блокируйте, прочитав, когда происходит прерывание. Кажется, что мой poll Функция может прочитать регистр управления и вернуть POLLIN|POLLRDNORM Если данные уже доступны, и разоблачить прерывание, если нет. И тогда обработчик прерывания будет использовать wake_up чтобы пометить wait_queue как готов. read всегда замаскировал бы прерывание.

Это было полезно?

Решение

Я думаю, что Char Driver - лучший вариант, потому что вы найдете для него гораздо больше документации, а часть ядра проще. API хорошо известен, и вы найдете больше людей с опытом работы с водителем Char.

Начните с малого, т.е. с рабочей междровующей блокировкой чтение:

  • Если нет доступных данных, спите в очереди
  • иначе вернуть доступные данные в пользовательский пространство.

С подпрограммой прерывания в конечном итоге разбудить очередь, если данные доступны.

Как только он работает, внедрите опрос.

Другие советы

Я думаю, что NetLink - ваш лучший вариант. Кстати, вы можете рассматривать гнездо NetLink в качестве обычного розетки и использовать опрос, Epoll, выберите на нем.

Кроме того, что вы имеете в виду под «API нестабильный»? NetLink часто используется, и у нее довольно приличный API.

Вам просто нужно использовать Generic NetLink для отправки (и, возможно, получения) сообщений. Ваша задача становится еще проще, если существует одностороннее общение, т.е. от ядра -> userpace.

РЕДАКТИРОВАТЬ: Если у вас есть доступ, см. PG. 810 далее (глава 12) книги профессиональной архитектуры ядра Linux от Wrox. Насколько я знаю, у него есть (относительно) хорошее описание того, как вы могли бы использовать NetLink для общения с пользователем.

Единственный недостаток NetLink - скудная документация. В противном случае, на мой взгляд, все в порядке.

С вариантом устройства символов, read(2) от пользовательского пространства в конечном итоге вызовет ваш водитель read() функция (указана в struct file_operations Вы зарегистрировали свое устройство). Таким образом, это зависит от вашей реализации, независимо от того, поддерживаете ли вы границы Datagram и какие ошибки вы хотите вернуть в различных случаях сбоя.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top