LINUX.ORG.RU

написать драйвер для своего устройства

 ,


6

13

Есть некое устройство (на базе ПЛИС), которое видится в системе через lspci, оно сконфигурировано, назначены адресные пространства и т.д. Осилена книга «PCI Express Technology. Comprehensive Guide to Generations 1.x, 2.x, 3.0», принципы работы PCI Express стали полностью понятны.

Теперь нужно с этим устройством работать. Для этого требуется свой драйвер для ОС Linux. Есть крохи информации в LDD3 (почти бесполезные), есть такой пример http://www.fpga4fun.com/PCI6.html

Подскажите какой-нибудь простейший пример PCI драйвера (самый маленький в ядре), или может есть руководство или книжка на эту тему.

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

Для начала (самый простой вариант) - на устройстве допустим на всем диапазоне запрошенного и выделенного ему адресного пространства лежит повторяющийся одинаковый текст (из пары слов), просто нужно в программе через драйвер этот текст считать с максимальной скоростью (DMA) и вернуться к исполнению программы.

Ответ на: комментарий от ebantrop
struct mypci_device
{
	void __iomem *mmio;
	struct pci_dev *pci;
	struct cdev *char_device;

	wait_queue_head_t wait;
	dma_addr_t dma_device;
	void *dma_driver;
	int dma_finished;
	int debug;
};
	device->dma_driver = dma_alloc_coherent(&device->pci->dev, MYPCI_DMA_BLOCK, &device->dma_device, GFP_DMA);
	if((!device->dma_driver) || (!device->dma_device))
	{
		ret = -ENOMEM;
		dev_err(&device->pci->dev, "mypci: ERROR: dma alloc failed\n");
		goto failed_dma_alloc;
	}
	dev_dbg(&device->pci->dev, "mypci: dma= %08lX\n", (unsigned long) device->dma_driver);

То что dma_device - высылаю в устройство, это адрес для устройства. В драйвере я читаю данные с того что dma_driver.

Таким образом, dw указывает на dma_driver. Мне кажется, это не копия, а то что представляет вторую сторону медали dma_device/dma_driver, возможно потенциально на разных платформах это может быть разные адреса для устройства и хоста, указывающие в одно по сути место.

I-Love-Microsoft ★★★★★
() автор топика
Последнее исправление: I-Love-Microsoft (всего исправлений: 2)
Ответ на: комментарий от I-Love-Microsoft

Добавил задержку 100 мкс (= 0,1 мс) между последним пакетом и MSI - результат прежний. Добавлять задержку еще больше - тогда проще по RS-232 данные получать. Значит данные биты не по причине нехватки времени на запись, тем более сбои возникают в начале блока данных.

I-Love-Microsoft ★★★★★
() автор топика
Ответ на: комментарий от I-Love-Microsoft

Я правильно понимаю из твоей пасты, что у тебя есть пакеты которые просто не доезжают? Последовательность получается типа: доехал, доехал,... не доехал, доехал... То есть пропадает часть пакетов где то в середине? А смысл тогда чего-то ждать?

ebantrop
()
Ответ на: комментарий от ebantrop

Я правильно понимаю из твоей пасты, что у тебя есть пакеты которые просто не доезжают? Последовательность получается типа: доехал, доехал,... не доехал, доехал...

Именно так. Выше я уже проверил это - действительно задержка после последнего пакета не помогает, сбои в начале блоков. Пока не понимаю причину.

I-Love-Microsoft ★★★★★
() автор топика
Ответ на: комментарий от I-Love-Microsoft

То есть получается что TLP либо не уезжал с FPGA, либо сброшен хостом, или уехал совсем не туда. У меня было такое. Что именно происходило я не знаю. На одном хосте все было ок, другой косячил. Вылечил задержкой в один клок на ПЛИСе между пакетами.

ebantrop
()
Ответ на: комментарий от ebantrop

Ого, я попробую задержку между пакетами. У меня она как раз один клок, может больше надо насыпать. Хотя не, я жду флаг готовности корки между пакетами, чтобы буферы просрались. В самом деле, добавлю больше клоков.

I-Love-Microsoft ★★★★★
() автор топика
Последнее исправление: I-Love-Microsoft (всего исправлений: 2)
Ответ на: комментарий от ebantrop

Добавил 10 тактов задержки между пакетами, потерял 25% пропускной способности, но избавился от ошибок! Благодарю за подсказку, это помогло, по крайней мере мне кажется что пока помогает :)

Вместо первоначальных 175 мегабайт в секунду имею 117 мегабайт без сбоев в данных при работе через user-space программу. Что ж, для начала сойдет.

Цель, поставленная в этой теме достигнута, но топик буду продолжать. Буду пробовать SGDMA теперь.

I-Love-Microsoft ★★★★★
() автор топика
Ответ на: комментарий от ebantrop

Одна PCI-E 1.0 x1 у меня на стороне драйвера дают 175 мегабайт в секунду. Но если добавить достаточные паузы между пакетами и копировать в userspace - получится 115+ мегабайт в секунду. Сколько у тебя?

I-Love-Microsoft ★★★★★
() автор топика
Ответ на: комментарий от I-Love-Microsoft

Для PCIe 1.0 x1 трафик в 175 МБ/с мне кажется очень и очень неплохо с учетом того что у него физический максимум 250. У меня PCEe 2.0 x8, дает ~3100 МБ/с от 4 Гиг физических. Это с payload в 128 байт и одним клоком отдохнуть между пакетами.

ebantrop
()
Ответ на: комментарий от ebantrop

3100 / 8 / 2 = 193 Мбайт/с в секунду, твой линк на 65% эффективнее моего (у мну 117 Мбайт/с? 175 это с потерями и без передачи в userspace). А что если память не будет справляться с такой нагрузкой, положим я вставил четыре карты как у тебя - как ты определишь на стороне ПЛИС что требуется снизить скорость потока?

I-Love-Microsoft ★★★★★
() автор топика
Последнее исправление: I-Love-Microsoft (всего исправлений: 1)
Ответ на: комментарий от I-Love-Microsoft

Почему память не будет справляться, она на CPU вроде как раз 20 быстрее, в GPU и того больше. Честно говоря не знаю что будет если засунуть 4 девайса. Думаю как BIOS на душу положит. У меня сейчас 2 девайса по х8: FPGA и GPU.

Про определить скорость будет видно с хоста, со стороны ПЛИСа просто готовность в нуле будет дольше висеть и все. Интерфейс-то как был жирным так и останется.

ebantrop
()
Ответ на: комментарий от ebantrop

Для тех кто следит за темой :)

Удалось решить проблему ошибок. Всё-таки, в готовых IP Core не бывает «лишних» информационных линий, а документацию следовало мне читать внимательнее...

Так как у меня пакеты (16 + 3) DW = 76 байт, то это значит что на приемной стороне должно быть достаточно «кредитов» приемного буфера, чтобы уместить то что я шлю. Согласно книге «Jackson M., Budruk R., PCI Express Technology. Comprehensive Guide to Generations 1.x, 2.x, 3.0(2012)» кредиты выражаются такими значениями:

Header credits - maximum header size + digest * 4 DWs for completions * 5 DWs for requests Data credits - 4 DWs (aligned 16 bytes)

Я стал проверять что posted data credits у меня больше или равно 5. И всё стало работать.

Меня очень волновала разница, почему у ebantrop получилось 193 мегабайт в секунду, если поделить его скорость на 8 и 2 (x8 -> x1 и 2.0 -> 1.0 = /16)? Теперь, когда снова вернул свои 142 мегабайта в секунду без ошибок, этот результат у меня на системе со старым Pentium D при условии копирования в user-space программу. Без такого копирования, я видел 175 мегабайт в секунду, думаю если уберу копирование в user-space (которое задерживает запрос новых порций данных) то увижу эти цифры снова. Когда я пробовал устройство на более быстром компьютере на работе (процессор i5) - я получил 125 Мбайт/с вместо 114 Мбайт/с. Поэтому, если бы я этот попробовал без копирования в user-space на более быстром компьютере, то увидел бы у себя 190 мегабайт в секунду :)

I-Love-Microsoft ★★★★★
() автор топика
Ответ на: комментарий от I-Love-Microsoft

Хотя, может если брать гораздо больший размер пакетов (64 байта вообще смешно), то такая скорость будет достижима и при копировании в userspace.

I-Love-Microsoft ★★★★★
() автор топика
11 декабря 2016 г.
Ответ на: комментарий от ebantrop

я на эти кредиты и не смотрел

Пару недель назад тестил на еще одном компе, там тоже без ошибок, однако по светодиодам увидел что... там не произошло ни единого retry. Так что, быть может, если не проверять кредиты, устройство на одном компе будет хорошо себя показывать, а на другом неожиданно продемонстрирует свою полную неработоспособность...

P.S. Вспомнил про тему. Сейчас пыжусь с аналогичным проектом на базе Altera Cyclone 4 GX.

I-Love-Microsoft ★★★★★
() автор топика
Ответ на: комментарий от I-Love-Microsoft

Я кредитный сигнал вывел, но подробно посмотреть все никак не соберусь. Пока работает. Правда недавно воткнул в комп с другой материнкой и выяснилось что в в моем реквесте на чтение 4 бита были в нуле, а положено им быть единицами. Старый чипсет все кушал на ура, а в новом они это поправили и надо делать как положено.

ebantrop
()
20 января 2017 г.
Ответ на: комментарий от I-Love-Microsoft

Очень хотелось бы узнать чем дело кончилось. Сейчас занимаюсь похожими вещами и если была б возможность увидеть наглядное пособие (пошаговые комментарии в теме уже есть) рабочего варианта драйвера - (для обучения) было бы здорово. Спасибо :)

confor
()
Ответ на: комментарий от confor

Случайно не chewj*?

Драйвер выложу на днях, если надо, с комментариями. Однако там, даже в таком крайне зачаточном варианте, есть ряд вопросов, которые я пока не стал решать, ибо пытаюсь повторить железо, совместимое с этим недо-драйвером уже на платформе Altera Cyclone 4 GX.

I-Love-Microsoft ★★★★★
() автор топика
Ответ на: комментарий от I-Love-Microsoft

Случайно не chewj*?

Нет, чтобы это не было :)

Драйвер выложу на днях, если надо, с комментариями. Однако там, даже в таком крайне зачаточном варианте, есть ряд вопросов, которые я пока не стал решать, ибо пытаюсь повторить железо, совместимое с этим недо-драйвером уже на платформе Altera Cyclone 4 GX.

Буду ждать, спасибо. Дело не в том, чтобы использовать из коробки, а чтобы научиться. Ибо «достигнутые» мной 3 МБ/с - явно не то на чем стоит останавливаться.

confor
()
Ответ на: комментарий от confor

Вокруг темы образовались три падавана :) как их принято нынче называть, хотя на магистра я пока что не тяну, но тем не менее )))

Вот код драйвера: http://paste.org.ru/?90xru5 Он далек от совершенства, однако дает результаты лучше чем 3 МБ/с ;)

У этого драйвера есть два способа работы: используя старый механизм DMA (через dma_alloc_coherent) и новый (dma_map_single). Старый подразумевает один большой постоянно задействованный буфер, который не всегда можно выделить. Новый механизм - динамический. В данном драйвере используется один буфер пока что (если таковых много, то если не ошибаюсь, это зовется Scatter Gather DMA).

Итак, init_module_mypci - вызывается при загрузке модуля в память и регистрирует в системе драйвер как со стороны шины PCI и со стороны пользователя ввиде character device (простейший интерфейс, позволяющий работать с устройством как с файлом). device_probe - выполняется при наличии устройств с подходящим VENDOR_ID и DEVICE_ID (для каждого экземпляра устройства) и тут же с каждым устройством связывается своя структура struct mypci_device которая хранит данные специфичные для каждого экземпляра устройства - эта структура доступна при каждом событии, будь то во время прерывания, или когда из пространства пользователя осуществляются действия типа открытия файла и чтения-записи. Создание файла устройства делается так: sudo mknod /dev/mypci c 200 0 и тут MYPCI_MAJOR=200 а 0 это говорит о том что это просто первое устройство (их может быть много, 1 будет у второй воткнутой карточки).

Тестовая программа: http://paste.org.ru/?t8bnjo Она позволяет открыть файл, выделяет буфер и осуществляет замер времени заполнения буфера, чтобы приблизительно оценить производительность реализации (не пропускную способность шины как таковую!).

Задачи, которые нужно решить:

1) Сделать динамическое получение major-номера
2) Разобраться с настройкой вывода в debugfs (мне удалось это лишь частично)
3) Разобраться с SG-DMA (работает как dma_map_single но со множеством страниц) - это позволит получить больше данных от устройства (скорость увеличится) прежде чем осуществлять копирование в user space и пробуждать пользовательский процесс
4) Распараллелить процесс получения данных от устройства и копирование в user-space - позволит поднять скорость
5) Хотелось бы реализовать V4L2-интерфейс устройства (как карта захвата видео, например).

Из того что почитать на тему:

1) Jackson M., Budruk R., PCI Express Technology. Comprehensive Guide to Generations 1.x, 2.x, 3.0 - идеальная книга, слабая сторона которой является отсутствие пояснения особенностей работы на стороне хоста, только затронута начальная инициализация

2) Linux Device Drivers (книга LDD), есть http://rus-linux.net/MyLDP/BOOKS/drivers/linux-device-drivers-00.html - однако самое нужное по части DMA и связывание с подсистемами, типа I2C/SPI - описано плохо или никак

Что касается аппаратной части - это ПЛИС любого производителя Altera/Lattice/Xilinx или ПЛИС + мостовая микросхема. У устройства должен быть задан PCI-E native режим, доступен один регион памяти (например 4К), поддерживаться режим прерываний MSI, VID/PID как в драйвере. Это отдельная тема, и если есть вопросы - пишите.

charodeus

I-Love-Microsoft ★★★★★
() автор топика
Последнее исправление: I-Love-Microsoft (всего исправлений: 2)
Ответ на: комментарий от ox55ff

как правило, от 400-500 крокодилов

однако просто купил и играешься не выйдет - на момент покупки скиллы проектирования на базе FPGA должны быть уже существенными, иначе всё покажется не очевидной магией, а простые проблемы могут надолго поставить в тупик и не позволят задействовать инструменты отладки

это отладочная плата, хотя сама-то ПЛИСина не дорогая для 1.0 x1, но опять же - развести плату это тоже не совсем просто и легко - скиллы должны быть уже серьезными

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

это как нельзя сразу стать стоматологом, а то клиент помрет от анестетика, а ведь ты всего лишь хотел кариес поковырять :)

I-Love-Microsoft ★★★★★
() автор топика
Последнее исправление: I-Love-Microsoft (всего исправлений: 1)
Ответ на: комментарий от I-Love-Microsoft

Да уж, крокодилы кусачие, по крайней мере для поиграться. Хотя в первой попавшейся ссылки из гугла http://www.mbedded.ninja/electronics/communication-protocols/pci-express-pcie... схема подключения не выглядит сложной. Можно попробовать сделать переходник к обычной плисине, которая уже имеется.

ox55ff ★★★★★
()
Ответ на: комментарий от ox55ff

Можно попробовать сделать переходник к обычной плисине, которая уже имеется

Интерфейс по факту действительно очень прост - резет, клок, и две пары туда-сюда. Переходник - заведомо не рабочий вариант, никаких переходников - только своя плата сразу, с учетом тех ограничений описанных в статье + толщина фольги платы и ширина дорожек там не указана. А питание?

I-Love-Microsoft ★★★★★
() автор топика
Ответ на: комментарий от I-Love-Microsoft

1) Сделать динамическое получение major-номера

А в чем цимес динамического номера? У меня динамический, правда /dev/железка делаю из драйвера с device_create(...). Как по-простому вытащить мажор из драйвера я так и не понял.

ebantrop
()
Ответ на: комментарий от ebantrop

В какой-то системе номер например 200 будет свободен, в какой-то нет. Это явно плохая практика брать фиксированный major. Так же родилась еще идея:

6) создавать файл устройства в /dev динамически через udev или как-то еще, а не через mknod

P.S. А зачем получать major от драйвера? Он есть какой-то уникальный и пусть. Главное чтобы файл устройства был и всё работало, разве не?

I-Love-Microsoft ★★★★★
() автор топика
Последнее исправление: I-Love-Microsoft (всего исправлений: 1)
Ответ на: комментарий от confor

Что-то никто не пишет свои вопросы... Может это совсем не требуется для тех у кого есть опыт, но всё же опишу. Тем более, что тот пример что я выложил, работает лишь с относительно свежими ядрами и поэтому проще взять с kernel.org и собрать.

Первое с чего надо начать это вот что: 1) скачать последнее stable ядро с kernel.org (стрелка - самое видное на странице) 2) собрать это ядро - распаковать в любую папку внутри home, скопировав настройку из arch/x86/configs/i386_defconfig (32 бит ОС) или x86_64_defconfig в корневой каталог ядра под именем .config и выполнив make -j 5 и соберется ядро, где 5 это число потоков 3) sudo make install (или вместо sudo под пользователем root это делать) - ядро установится в систему и после перезагрузки можно будет выбрать это ядро как рабочее в системе 4) собрать драйвер: создать в каталоге с драйвером файл Makefile с

obj-m := mypci.o
внутри и выполнить в текущем каталоге
make -C /home/user/linux-4.8.9 M=$(pwd) modules
где 4.8.9 это путь до каталога с ядром которое скачали 5) получившийся файл .ko можно загрузить при помощи sudo insmod mypci.ko - после этого он появится в выводе команды lsmod

В принципе ничего нового, но прежде чем работать с примером, нужно его собрать поверх свежего ядра. Если тут отпишутся те, кто интересовались, можем выложить это в какой-то открытый репозиторий, чтобы можно было вместе пилить и тестировать на железе, попутно разбираясь и отвечая на вопросы.

I-Love-Microsoft ★★★★★
() автор топика
Последнее исправление: I-Love-Microsoft (всего исправлений: 1)
Ответ на: комментарий от I-Love-Microsoft

6) создавать файл устройства в /dev динамически через udev или как-то еще, а не через mknod

P.S. А зачем получать major от драйвера? ...

Ну вот для mknod и нужно, udev (или devfs?) я так и не осилил. Многабукаф, а простые примеры завести не получилось и я плюнул. Может кто тут просветит?

ebantrop
()
Ответ на: комментарий от I-Love-Microsoft

cat /proc/devices

Фигасе, а я не знал и поэтому device_create пользую. Спасибо.

ebantrop
()
Ответ на: комментарий от I-Love-Microsoft

В принципе ничего нового, но прежде чем работать с примером, нужно его собрать поверх свежего ядра.

А зачем свежайший свежак нужен? В убунте, по-моему, между ядрами из 12.04 и 14.04 они там что-то поломали, а потом вроде как работает.

Если тут отпишутся те, кто интересовались, можем выложить это в какой-то открытый репозиторий, чтобы можно было вместе пилить и тестировать на железе, попутно разбираясь и отвечая на вопросы.

Ну дык это и железо нужно, и HDL. А оно, за редкими исключениями, сильно зависит от задачи.

ebantrop
()

Удалось воспроизвести полностью аналогичный проект (совместимый с тестовой программой и драйвером) но уже на базе Altera Cyclone IV GX. Кто удумает делать устройство - обращайтесь с вопросами, подскажу в случае проблем.

I-Love-Microsoft ★★★★★
() автор топика
2 февраля 2018 г.
Ответ на: комментарий от gag

Да хорошая статья, респект челу за то что написал такую статью, но можно было попроще. К тому же, нет аппаратной части - а это тоже важно и интересно. Про DMA ни слова. Статья хорошая, но вот такой ряд замечаний.

Может и я когда-то сподоблюсь написать что-нибудь, но с аппаратной частью и DMA.

I-Love-Microsoft ★★★★★
() автор топика
Ответ на: комментарий от gag

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

Получается, я уже знаю как работать с PCI-E на Lattice, Altera и теперь уже на Xilinx будет. Есть что написать.

I-Love-Microsoft ★★★★★
() автор топика
Ответ на: комментарий от gag

у Alterа были готовые дрова для их чипов, которые сидят на PCIe. опенсорцные. проще всего брать за основу их болванку и допиливать под свои нужды.

Iron_Bug ★★★★★
()
Ответ на: комментарий от Iron_Bug

Точно, что-то есть.

И даже в ядре что-то имеется: drivers/pci/host/pcie-altera.c, pcie-altera-msi.c. И для Xilinx тоже: pcie-xilinx.c, pcie-xilinx-nwl.c.

Вчера нашёл платку PicoEVB (250 у.е.) с драйверами от Xilinx.

Ещё бы найти платку за около 100 у.е.

gag ★★★★★
()
Ответ на: комментарий от gag

Ещё бы найти платку за около 100 у.е.

Там себестоимость под сто уёв, не может быть такой дешевой платки. Но вот за 150... Давно мечтал сделать свою отладку. Только как ее продавать. Я слышал про то что наши хотят разродиться «российским алиэкспрессом» для отечественных производителей. Вот поскорее бы они.

I-Love-Microsoft ★★★★★
() автор топика
Ответ на: комментарий от I-Love-Microsoft

Сама ПЛИСка от 40 у.е. Ещё нужны за пару-другую у.е. SPI Flash, чип-генератор нужных напряжений. И по мелочам: разъём I/O наружу (включая JTAG и SPI флэш), резисторы, конденсаторы. И собственно сама плата. 150 - это уже больше психологической границы.

gag ★★★★★
()
Ответ на: комментарий от gag

я просто одно время много работала с Altera. у меня были разные платки на циклонах на работе, с мостами PCI-PCIe. и я писала дрова на PCIe под маздай. но я также платки таскала домой и дома под линём запускала, на самописных дровах. обычно берёшь болванку драйвера от альтеры и допиливаешь под свои нужды. они там основные базовые вещи уже накатали для своих чипов и можно их оптимизировать или менять под свои требования. в общем-то, наиболее простой путь.

Iron_Bug ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.