LINUX.ORG.RU

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

 ,


2

5

Есть некое устройство (на базе Xilinx FPGA) PCI Express Gen2 x4., которое видится в системе через lspci, оно сконфигурировано, назначены адресные пространства. Устройство реализует в себе 4 RS232 порта и энергонезависимою память NVRAM.

Теперь нужно с этим устройством работать. Для этого требуется свой драйвер для ОС Linux в интернете есть примеры. Подскажите работа с RS-портами и память NVRAM можно делать в одном драйвере символьного устройства или лучше разбить на два независимых.

Как оно выглядит, отельные виртуальные функции?

Можно и так, и сяк.

mv ★★★★★
()

Вот ссылка на мою тему: написать драйвер для своего устройства

Спрашивай любые вопросы, я постараюсь помочь. Со своей стороны, я хотел бы тоже задать несколько вопросов по PCI-E ядру в ПЛИС Xilinx. Из моей темы ясно, что PCI-E в Lattice и Altera у меня заработали, а вот в Spartan6-T сейчас ковыряюсь, и там всё трудно, т.к. не отладочная плата, а готовое устройство, которое пытаюсь перепрошить, на которое мало документации.

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

Оффтоп конечно, но можешь мне позадавать вопросов по Xilinx.

По работе пришлось полностью расковырять их корки PCIe, правда для седьмого семейства. Но у них там сам контроллер не сильно поменялся со времен 6 серии.

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

Спасибо, это ценное предложение. Создам отдельную тему и скастую, чтобы тут не загромождать. А от автора темы ждем вопросов :)

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

Какой драйвер для примера взять для работы с MRAM.

Хочу сначала реализовать работу с MRAM (энерго-независимая память).

Вот выдержки из документации

FPGA PCIe - AXI4 bus Memory Map.

Xilinx FPGA implements a bridge between the PCI Express (PCIe) bus and AXI4 bus. This bridge requests 256Mbytes address range in the Host PCIe bus memory space. Offset 0x80000000 is added to the enumerated PCIe Base Address to derive AXI4 bus address. Table below shows implemented peripherals in the Synergy FPGA Memory Map 0x0000.0000 - 0x0FFF.FFFF as seen from the Host PCIe bus.

Synergy mapped Peripherals and RAM.

Memory Region Description Comments 0x0000.0000 – 0x0000.FFFF 32 input Interrupt Controller. 32-bit wide interface. Base address 0x00000000. 0x0010.0000 – 0x001F.FFFF FPGA GMIO. 32-bit wide interface. Custom Gaming Machine parallel and serial I/O. 0x0002.0000 – 0x0002.1FFF UART #0. 32-bit wide interface but only lower 8 bits are used. Xilinx 16550 compatible UART. Base address 0x00020000. 0x0002.2000 – 0x0002.3FFF UART #1. 32-bit wide interface but only lower 8 bits are used. Xilinx 16550 compatible UART. Base address 0x00022000. 0x0002.4000 – 0x0002.5FFF UART #2. 32-bit wide interface but only lower 8 bits are used. Xilinx 16550 compatible UART. Base address 0x00024000. 0x0002.6000 – 0x0002.7FFF UART #3. 32-bit wide interface but only lower 8 bits are used. Xilinx 16550 compatible UART. Base address 0x00026000. 0x0002.8000 – 0x0002.9FFF UART #4. 32-bit wide interface but only lower 8 bits are used. Xilinx 16550 compatible UART. Base address 0x00028000. 0x0002.A000 – 0x0002.BFFF UART #5. 32-bit wide interface but only lower 8 bits are used. Xilinx 16550 compatible UART. Base address 0x0002A000. 0x0400.0000 – 0x043FF.FFFF MRAM Bank #0. NVRAM 4MByte 32-bit wide. Implemented using magneto-resistive random access memory MRAM devices. 0x0440.0000 – 0x047FF.FFFF MRAM Bank #1. NVRAM 4MByte 32-bit wide. Implemented using magneto-resistive random access memory MRAM devices. 0x0480.0000 – 0x04FFF.FFFF MRAM Bank #0 and MRAM Bank #1 compare region. Access to MRAM this region will compare data in Bank#0 to the data in Bank#1 when the same physical address is applied to both banks during compare read cycle.

MRAM Banks. Synergy four MRAM devices are arranged in two independent 4MByte 32-bit wide banks. BANK #0 address range 0x04000000 – 0x043FFFFFF, BANK #1 address range 0x04400000 – 0x047FFFFFF. Also 16MBytes address range is allocated to Bank #2 only lower 8MBytes are physically present. Upper 8Mbytes region 0x04800000 – 0x04FFFFFFF is used in a MRAM compare operation. Access to the MRAM in this region will compare data in Bank#0 to the data in Bank#1 when the same physical address is applied to both banks during compare read cycle. Compare failure will generate an interrupt #8 and address will be latched in a MRAM Address Fail Register. MRAM Address Failed Register is cleared to zero at the start of the compare operation when interrupt #8 is cleared.¬

Interrupt Controller. Interrupt controller core is located at the base address 0x00000000 and supports 32 inputs. Input assignments are shown below. Bit (0) – Edge. Active Raising. ILA Software Trigger. Bit (1) – Edge. Active Raising. Power supply Power Good. Bit (2) – Edge. Active Raising. Power supply AC Fail. Bit (3) – Level. Active High. GMIO 1ms Timer Interrupt. Bit (4) – Level. Active High. Reserved Interrupt. Bit (5) – Level. Active High. Reserved Interrupt. Bit (6) – Level. Active High. Reserved Interrupt. Bit (7) – Level. Active High. Reserved Interrupt for Link Controller Redundant (LCR) Interrupt. Bit (8) – Edge. Active Raising. MRAM Data Compare Fail. Bit (9) – Level. Active High. Reserved Interrupt. Bit (10) – Level. Active High. Reserved Interrupt. Bit (11) – Level. Active High. Reserved Interrupt. Bit (12) – Level. Active High. Reserved. FPGA_MSP_UCB0SIMO (MSP430 pin #30). Bit (13) – Level. Active High. Reserved. FPGA_MSP_UCB0SOMI (MSP430 pin #31). Bit (14) – Level. Active High. Logging Processor Significant Event Interrupt. (MSP430 P1.2 pin#12). Bit (15) – Level. Active High. Reserved. FPGA_MSP_UCB0SIMO (MSP430 P3.5 pin#27). Bit (16) – Level. Active High. AXI UART0 Interrupt. Bit (17) – Level. Active High. AXI UART1 Interrupt. Bit (18) – Level. Active High. AXI UART2 Interrupt. Bit (19) – Level. Active High. AXI UART3 Interrupt. Bit (20) – Level. Active High. AXI UART4 Interrupt. Bit (21) – Level. Active High. AXI UART5 Interrupt. Bit (22) – Level. Active High. AXI UART6 Interrupt. Bit (23) – Level. Active High. AXI UART7 Interrupt. Bit (24) – Level. Active High. Reserved for AXI UART8 Interrupt. Bit (25) – Level. Active High. AXI UART9 Interrupt. Bit (26) – Level. Active High. Reserved. Bit (27) – Level. Active High. Reserved. Bit (28) – Level. Active High. Reserved. Bit (29) – Level. Active High. Reserved.

Interrupt Controller Registers. Interrupt Controller base address is 0x00000000. Interrupt Controller registers memory map is provided below. Interrupt Status Register (ISR). Read only 32 bit register located at an address 0x00000000 + 0x00. Reading this register returns pending interrupts that are not masked. Interrupt Inputs Register (IIR). Read only 32 bit register located at an address 0x00000000 + (0x04). Reading this register returns all pending interrupts. Masks are by-passed.

MRAM Address Failed Register (MAFR). Read only 32 bit register located at an address 0x00000000 + 0x08. Reading this register returns the first MRAM address where compare operation failed. MRAM Address Failed Register is cleared to zero at the start of the compare operation. MRAM Address Failed Register is valid only when MRAM Data Compare Fail interrupt is pending. Interrupt Masks Register (IMR). Write only 32 bit register located is mapped to an address region 0x00000000 + (0x00 – 0x1F, 0x20). Region (0x00 – 0x1F) is used to write individual bits in IMR. When a write byte access (e.g. unsigned char) is performed in this region, least significant address bits select a bit in a 32-bit word and the data is supplied by the least significant bit (e.g. D0) in a byte. Address (0x20) is used to write all 32 bits of the IMR in a single access. Interrupts are cleared when their corresponding masks are set to ‘0’. After that the required interrupts can be unmasked by setting their corresponding masks to ‘1’.

Interrupt Raising Edge Detect Register (IREDR). Write only 32 bit register located at an address 0x00000000 + (0x24). Bits in this register can be written as a byte or as a 32 bit word.

cyrillwork
() автор топика

Первое что хочу выяснить, ПЛИСовая часть будет сделана с участием Microblaze или без прослоек?

Раз устройство видится, то отображаются ли BARы и какие диапазоны в них доступны?

Удалось ли научиться, для начала, тупо мигать светодиодом через PCI-E через простые обращения к BAR?

Прежде чем поднять advanced тему, нужно сначала разобраться с базовыми деталями.

И да, есть ли заготовка драйвера, которая делает начальные стадии инициализации?

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

Текущее состояние

Написан по найденным образцам драйвер PCIe, проверил запись-чтение по адресам к MRAM (вроде работает), прикрутил шаблонных драйвер символьного устройства (тоже вроде работает). Возник вопрос в функции read в переменной lbuf получаю размер буфера(причем собственного, на стороне драйвера) не могу понять как получить количество байт, которые пользователь хочет прочитать?

cyrillwork
() автор топика
Ответ на: Текущее состояние от cyrillwork

Какая версия ведра? Из моего модуля:

static ssize_t device_read(struct file *f, char *buffer, size_t size, loff_t *offset)
Очевидно, size и есть сколько хочет юзверь. Тогда о какой функции read идет речь? Для ram какой-то другой прототип функций применяется?

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

Текущее состояние

Просто тестовая программа использовала fopen, fread ... потоковое чтение, а там запрашивается больше данных. У меня и драйвер PCI и драйвер символьного устройства в одном файле, попытался развести по разным файлам и через функции creat_chdr_dev и remove_chdr_dev вызывать создание и удаление символьного драйвера, но почему-то основной драйвер не видит их, может с makeом что-то не так?

obj-m = agtbus.o mramdev.o LIBMOD = /lib/modules/4.4.83-1600/build

PWD := $(shell pwd)

all: make -C $(LIBMOD) M=$(PWD) modules

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

Обработка прерываний

Если пример драйвера символьного устройства (желательно RS) построенного на основе прерываний, а то я писал по примеру без прерываний с NVRAM прокатило, но с RS портом помоемому не получится.

cyrillwork
() автор топика
Ответ на: Обработка прерываний от cyrillwork

Вот пожалуйста, ссылка на пост, а там уже ссылка на драйвер и тестовую программу: написать драйвер для своего устройства (комментарий)

Работает по прерываниям, любые вопросы отвечу по коду.

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

Пример uart_diver на pcie шине

На сколько я понимаю, что бы реализовать полноценный драйвер COM-порта нужно использовать uart_driver с прерываниями. Есть ли примеры pcie драйвера, который реализует в себе uart_driver (COM-порт)?

cyrillwork
() автор топика
Ответ на: Пример uart_diver на pcie шине от cyrillwork

Ну в ядре Linux же есть исходники - это же и примеры. Но они как правило, очень сложны. Проще свои драйвера делать. Например у Xilinx есть же Linux-драйвер для uart_lite https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18842359/AXI UART Lite ... правда он не для PCI-E. Но я уверен, пример может быть полезен.

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

Вопрос по памяти

В начале при регистрации драйвера pci память платы мапится ioremap(base_start, base_len), затем регистрирую uart_driver и там в полях структуры uart_port: membase, mapbase нужно указывать адреса памяти c которыми будет работать uart драйвер. Не могу понять толи заново ее мапить, толи использовать те адреса драйвера pci?

cyrillwork
() автор топика
Ответ на: Вопрос по памяти от cyrillwork

Не затруднит кидать код через paste.org.ru? Вот не могу сказать - так это или нет. Нужно читать документацию - подразумевают ли они именно эти дареса. Обычно base address это может быть совсем другой диапазон, такой где периферия лежит по соответствующим оффсетам, а на x86 это кажись те самые https://wiki.osdev.org/I/O_Ports 0x03F8-0x03FF First serial port

Ну а ioremap немножечко не то.

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

Привет.

Увидел твои сообщения про pcie и fgpa. Можно спросить несколько вопросов про раборту с dma?

Вроде простая вещь, но толком не могу найти где описана последовательность шагов чтобы начать dma обмен между хостом и енд-поинтом. Что нужно настроить в плис чтобы она начала слать данные в dma?

Сейчас драйвер в линукс выделяет область dma с помощью pci_alloc_consistent(pdev, DMA_SIZE, &dma_Addr);

Что дальше должен сделать драйвер и что дальше должна сделать плис чтобы она смогла писать в dma?

Спасиб за ответ.

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

Завтра отвечу, если нет - напомни пожалуйста.

P.S. PCI-E на Spartan 6-T я в итоге разобрался и запустил.

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

Чем ты формируешь пакеты на стороне ПЛИС? Microblaze/etc? Или самостоятельно формируешь TLP пакеты?

Из моего примера:

device->dma_driver = dma_alloc_coherent(&device->pci->dev, MYPCI_DMA_BLOCK, &device->dma_device, GFP_DMA);
dma_driver это адрес, по которому драйвер будет видеть область памяти. dma_device это адрес, по которому ПЛИС может писать данные, формируя соответствующие пакеты. Когда буфер заполнен (сама ПЛИС знает сколько записала) - формируется MSI прерывание. Драйвер просыпается и читает из памяти начиная с адреса dma_driver.

Чтобы инициализировать запись, нужно просто каким-то способом передать в ПЛИС адрес dma_device, это будет сигналом «можно записывать». Сам факт записи этого адреса например через MMIO (т.е. через BAR-адрес) может быть таким сигналом к старту.

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

Спасиб за ответ.

TLP формирую самостоятельно.

Основной вопрос видимо такой: Вот есть адрес DMA(dma_Addr) который получил драйвер в результате вызова dma_alloc_coherent или pci_alloc_consistent.

Как правильно этот адрес сообщить в ПЛИС? я думал что логично былоб изменить значение BAR как-то так:

pci_write_config_dword(pdev,PCI_BASE_ADDRESS_1,dma_Addr);
И вроде как он меняется, если после этой команды вызвать:
lspci -xxxx
то будет видно что значение BAR1 перезаписалось.

Но со стороны ПЛИС вроде как нет доступа для чтения BARХ, и поэтому ПЛИС не может узнать адрес dma.

Да, ты верно гришь, можно просто вызвать что-то типа:

drv_priv->hwmem = ioremap(mmio_start, mmio_len);
iowrite32(dma_Addr, drv_priv->hwmem);

тем самым записав по нулевому смещению адрес dma, но мне кажется этот способ каким-то странным.

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

тем самым записав по нулевому смещению адрес dma, но мне кажется этот способ каким-то странным

А какие еще бывают способы, менее странные? Таким способом вроде обычно читают и пишут настроечные регистры устройств PCI, разве нет? Там же читают статусы.

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

Кстати, не обязательно именно по нулевому смещению, можно сделать себе регистровую карту, где 10-й например будет отвечать за адреса DMA от драйвера. И не обязательно стартовать запись когда появится этот адрес, можно и потом, просто пометить себе в каком-то служебном регистре, что получены N начальных адресов страниц памяти, в которые можно данные сувать.

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

А какие еще бывают способы, менее странные? Таким способом вроде обычно читают и пишут настроечные регистры устройств PCI, разве нет? Там же читают статусы.

)) Ну вот у меня и вопрос про это. Как писал выше думал что надо менять значение BAR. Ну лан раз так то пусть будет так. Вроде как-то пашет.

Спасиб за ответ.

оффтоп: ты имеешь какоето отношение к аватарке?

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