|
PCIe Driver |
|
|
|
Jul 29 2015, 07:43
|
Профессионал
    
Группа: Свой
Сообщений: 1 404
Регистрация: 11-03-11
Из: Минск, Беларусь
Пользователь №: 63 539

|
Приветствую. Есть плата с Virtex 7, надо забросить данные в ПК по PCIe. Ранее такого не делал и есь трудности. В FPGA собрана система: GPIO, Timer, PCIe Bridge (регистры GPIO и таймера смапированы на адресное пространство BAR0). Разбираюсь в написании модулей ядра Linux (использую Ubuntu 15.04). Пока реализовал управление GPIO при загрузке/выгрузке модуля в Linux. Хочу добавить прерывание. В FPGA линия interrupt от таймера заводится на PCIe-мост, он должен запихнуть его в систему. Для настройки прерывания в драйвере использую: Код irq_handler_t timer_isr(unsigned int irq, void *dev); struct pci_dev *pdev; char irq; ... pci_read_config_byte( pdev, PCI_INTERRUPT_LINE, &irq ); // для моей платы получаю irq = 11 request_irq(irq_num, timer_isr, IRQF_TRIGGER_RISING, "PCIe INT", (void *)pdev); ... Функция pci_read_config_byte() установит irq = 11.Далее настраиваю таймер, чтобы генерировал прерывание и стартую его. В syslog вижу следующее сообщение Цитата Jul 29 10:57:49 user-pc kernel: [ 797.188154] irq 16: nobody cared (try booting with the "irqpoll" option) Jul 29 10:57:49 user-pc kernel: [ 797.188158] CPU: 7 PID: 0 Comm: swapper/7 Tainted: G OE 3.19.0-25-generic #26-Ubuntu Jul 29 10:57:49 user-pc kernel: [ 797.188159] Hardware name: Gigabyte Technology Co., Ltd. To be filled by O.E.M./Z77P-D3, BIOS F7 08/24/2012 Jul 29 10:57:49 user-pc kernel: [ 797.188160] ffff880408dc92a4 ffff88041edc3e28 ffffffff817c4518 0000000000040400 Jul 29 10:57:49 user-pc kernel: [ 797.188162] ffff880408dc9200 ffff88041edc3e58 ffffffff810d0e86 ffff88041edc3e88 Jul 29 10:57:49 user-pc kernel: [ 797.188164] ffff880408dc9200 0000000000000000 0000000000000010 ffff88041edc3e98 Jul 29 10:57:49 user-pc kernel: [ 797.188165] Call Trace: Jul 29 10:57:49 user-pc kernel: [ 797.188166] <IRQ> [<ffffffff817c4518>] dump_stack+0x45/0x57 Jul 29 10:57:49 user-pc kernel: [ 797.188174] [<ffffffff810d0e86>] __report_bad_irq+0x36/0xd0 Jul 29 10:57:49 user-pc kernel: [ 797.188175] [<ffffffff810d1237>] note_interrupt+0x267/0x2b0 Jul 29 10:57:49 user-pc kernel: [ 797.188177] [<ffffffff810ce8c3>] handle_irq_event_percpu+0x133/0x1a0 Jul 29 10:57:49 user-pc kernel: [ 797.188179] [<ffffffff810ce971>] handle_irq_event+0x41/0x70 Jul 29 10:57:49 user-pc kernel: [ 797.188181] [<ffffffff810d1666>] handle_fasteoi_irq+0x86/0x140 Jul 29 10:57:49 user-pc kernel: [ 797.188182] [<ffffffff81017772>] handle_irq+0x22/0x40 Jul 29 10:57:49 user-pc kernel: [ 797.188184] [<ffffffff817ce55f>] do_IRQ+0x4f/0xf0 Jul 29 10:57:49 user-pc kernel: [ 797.188186] [<ffffffff817cc36d>] common_interrupt+0x6d/0x6d Jul 29 10:57:49 user-pc kernel: [ 797.188186] <EOI> [<ffffffff816663b5>] ? cpuidle_enter_state+0x65/0x160 Jul 29 10:57:49 user-pc kernel: [ 797.188190] [<ffffffff816663a1>] ? cpuidle_enter_state+0x51/0x160 Jul 29 10:57:49 user-pc kernel: [ 797.188192] [<ffffffff81666597>] cpuidle_enter+0x17/0x20 Jul 29 10:57:49 user-pc kernel: [ 797.188195] [<ffffffff810b7ce1>] cpu_startup_entry+0x311/0x3b0 Jul 29 10:57:49 user-pc kernel: [ 797.188198] [<ffffffff81049107>] start_secondary+0x197/0x1c0 Jul 29 10:57:49 user-pc kernel: [ 797.188199] handlers: Jul 29 10:57:49 user-pc kernel: [ 797.188202] [<ffffffff815bb130>] usb_hcd_irq Jul 29 10:57:49 user-pc kernel: [ 797.188204] Disabling IRQ #16 Получается PCIe мост при наличии прерывания от таймера выдаёт его на 16 линию. Для просмотра оборудования в системе установлен System Profiler, для моего устройства он показывает IRQ = 16 (рисунок). Если пытаюсь использовать 16 линию прерывания в функции request_irq, она выдаёт ошибку. Код request_irq(16, timer_isr, IRQF_TRIGGER_RISING, "PCIe INT", (void *)pdev); Вопрос, что я делаю не так? Почему в конфигурационной области моего устройства записано 11 (Interrupt Line), а прерывание срабатывает на 16 линии? Код модуля: CODE /* Necessary includes for device drivers */ #include <linux/init.h> //#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> /* printk() */ #include <linux/slab.h> /* kmalloc() */ #include <linux/fs.h> /* everything... */ #include <linux/errno.h> /* error codes */ #include <linux/types.h> /* size_t */ #include <linux/proc_fs.h> #include <linux/fcntl.h> /* O_ACCMODE */ #include <linux/pci.h> #include <linux/pci_regs.h> #include <linux/interrupt.h> //#include <asm/system.h> /* cli(), *_flags */ #include <asm/uaccess.h> /* copy_from/to_user */
#include "hardware.h" #include "timer.h"
MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Andrei Hres"); MODULE_DESCRIPTION("Driver for /dev/virtex7_pcie"); MODULE_SUPPORTED_DEVICE("virtex7_pcie");
#define __DEBUG_MODE #define DRV_NAME "virtex7_pcie"
#define BAR0 0 #define BAR1 1 #define BAR2 2 #define BAR3 3 #define BAR4 4 #define BAR5 5
int virtex7_pcie_init(void); void virtex7_pcie_exit(void); int virtex7_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *ent); void virtex7_pcie_remove(struct pci_dev *pdev);
irq_handler_t timer_isr(unsigned int irq, void *dev); int irq_status; char irq_num;
char *bar0_base; unsigned long *pio_base;
static struct pci_device_id virtex7_pcie_ids[] = { {PCI_DEVICE(0x10EE, 0x7014)}, {0,} };
MODULE_DEVICE_TABLE(pci, virtex7_pcie_ids);
static struct pci_driver virtex7_pcie_driver = { .name = DRV_NAME, .probe = virtex7_pcie_probe, .remove = virtex7_pcie_remove, .id_table = virtex7_pcie_ids, //#ifdef CONFIG_PM // .suspend = pcie_suspend, // .resume = pcie_resume, //#endif /* CONFIG_PM */ };
//static int __init virtex7_pcie_init(void) int virtex7_pcie_init(void) { printk(KERN_ALERT "*****************************************\n"); printk(KERN_ALERT "Inserting PCIe module\n"); return pci_register_driver(&virtex7_pcie_driver); }
//static void __exit virtex7_pcie_exit(void) void virtex7_pcie_exit(void) { printk(KERN_ALERT "Removing PCIe module\n"); pci_unregister_driver(&virtex7_pcie_driver); printk(KERN_ALERT "*****************************************\n"); }
int virtex7_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { int status; int st; unsigned long data; char byte2; unsigned long bar0_start; unsigned long bar0_end; unsigned long *pio_reg;
printk(KERN_ALERT "Entering PCIe probe() function\n");
status = pci_enable_device(pdev);
if(status == 0) { printk(KERN_ALERT "PCIe device is succesfully enabled\n"); printk(KERN_ALERT "vendor: 0x%.4X\n", pdev->vendor); printk(KERN_ALERT "device: 0x%.4X\n", pdev->device);
pci_read_config_dword(pdev, 0, &data); printk(KERN_ALERT "Data from config space: 0x%.8X\n", data); pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &irq_num); printk(KERN_ALERT " PCI_INTERRUPT_LINE=%d\n", irq_num);
//irq_num = 16;
pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &byte2); printk(KERN_ALERT " PCI_INTERRUPT_PIN=%d\n", byte2);
bar0_start = pci_resource_start(pdev, BAR0); bar0_end = pci_resource_end(pdev, BAR0); printk(KERN_ALERT "BAR0 start address: 0x%.8X\n", bar0_start); printk(KERN_ALERT "BAR0 end address: 0x%.8X\n", bar0_end); printk(KERN_ALERT "BAR0 size: %u bytes = %u kB\n", bar0_end-bar0_start, (bar0_end-bar0_start+1)/1024);
//pio_reg = (unsigned long *) (bar0_start + 0x8000); //*pio_reg = 0xFFFFFFFF;
//----------------------------------------------------------------
st = pci_request_region(pdev, BAR0, "virtex7_pcie_bar0"); if(st == 0) { printk(KERN_ALERT "Request region success\n"); bar0_base = pci_iomap(pdev, BAR0, 0); printk(KERN_ALERT "bar0_base: 0x%.16X\n", (unsigned int) bar0_base);
pio_base = (unsigned long *) (bar0_base + 32768); printk(KERN_ALERT "pio_base: 0x%.16X\n", (unsigned int) pio_base);
//*(unsigned long *)(bar0_base + 32768) = 0x1; *pio_base = 0x1;
Timer_Init(bar0_base + TIMER_0_OFFSET_BYTES); Timer_IntClear(bar0_base + TIMER_0_OFFSET_BYTES); data = Timer_DbgRdCSR(bar0_base + TIMER_0_OFFSET_BYTES); printk(KERN_ALERT "Timer CSR: 0x%.8X\n", (unsigned int) data);
// free_irq(irq_num, (void *)pdev); irq_status = request_irq(irq_num, timer_isr, IRQF_TRIGGER_RISING/* | IRQF_SHARED*/, "PCIe INT", (void *)pdev); if(irq_status) printk(KERN_ALERT "request_irq() error\n"); else { printk(KERN_ALERT "request_irq() success\n"); Timer_Start(bar0_base + TIMER_0_OFFSET_BYTES); }
Timer_IntClear(bar0_base + TIMER_0_OFFSET_BYTES); data = Timer_DbgRdCSR(bar0_base + TIMER_0_OFFSET_BYTES); printk(KERN_ALERT "Timer CSR: 0x%.8X\n", (unsigned int) data); }
//pio_base = (unsigned char *) (addr_bar0 + 0x8000); //---------------------------------------------------------------- }
return status; }
void virtex7_pcie_remove(struct pci_dev *pdev) { *pio_base = 0;
printk(KERN_ALERT "Disable PCIe device\n"); pci_disable_device(pdev); pci_release_region(pdev, BAR0);
if(irq_status == 0) { free_irq(irq_num, (void *)pdev); Timer_Stop(bar0_base + TIMER_0_OFFSET_BYTES); printk(KERN_ALERT "Free PCI interrupt line #%d\n", irq_num); } }
module_init(virtex7_pcie_init); module_exit(virtex7_pcie_exit);
irq_handler_t timer_isr(unsigned int irq, void *dev) { static int int_counter = 0;
if(Timer_IntStatus(bar0_base + TIMER_0_OFFSET_BYTES)) { Timer_IntClear(bar0_base + TIMER_0_OFFSET_BYTES); }
printk(KERN_ALERT "Interrupt counter %d\n", int_counter); int_counter++;
return IRQ_NONE; }
Эскизы прикрепленных изображений
|
|
|
|
|
 |
Ответов
|
Aug 6 2015, 11:01
|
Профессионал
    
Группа: Свой
Сообщений: 1 404
Регистрация: 11-03-11
Из: Минск, Беларусь
Пользователь №: 63 539

|
На рисунке Configuration Space для устройства PCIe есть поле Interrupt Line. Оно, как понимаю, доступно только для чтения. Можете пояснить, что это такое и за что оно отвечает? Если повесить обработчик прерывания на 11 линию (записана в поле Interrupt Line), то работать не будет. При загрузке модуля указатель на структуру struct pci_dev *pdev содержит номер линии прерывания pdev->irq отличный от того, что хранится в конфигурационной области PCIe (всегда = 11). Это будет либо 16 (MSI запрещены), либо 31 (разрешены MSI). Если обработчик привязан к этому номеру - работает. Откуда взялся номер 11 в конфигурационной области? Если его пишет система (или BIOS), то почему после переопределения номера линии прерывания он не переписывается на правильный? Драйвер virtex7. MSI запрещены cat /proc/interrupts CODE CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 CPU6 CPU7 0: 17 0 0 0 0 0 0 0 IO-APIC-edge timer 1: 2 0 0 0 0 0 0 0 IO-APIC-edge i8042 8: 1 0 0 0 0 0 0 0 IO-APIC-edge rtc0 9: 0 0 0 0 0 0 0 0 IO-APIC-fasteoi acpi 12: 2 0 0 0 0 1 0 1 IO-APIC-edge i8042 16: 11080 968 13363 494207 41182 4940 73084 4109705 IO-APIC 16-fasteoi ehci_hcd:usb3, virtex7 17: 66 176 1 2 11 897 3 17 IO-APIC 17-fasteoi snd_hda_intel 19: 10129 11616 4327 9923 15263 31670 14741 30747 IO-APIC 19-fasteoi ata_piix, ata_piix 23: 27 0 0 7 1 0 0 0 IO-APIC 23-fasteoi ehci_hcd:usb4 25: 0 0 0 0 0 0 0 0 PCI-MSI-edge xhci_hcd 26: 17 87949 1 470 4 0 0 9 PCI-MSI-edge eth0 27: 28196 0 1 42 2 2 0 1 PCI-MSI-edge eth1 28: 12 0 0 0 3 0 0 0 PCI-MSI-edge mei_me 29: 27 103 1 1 11 313 20 7 PCI-MSI-edge snd_hda_intel 30: 1954797 699670 527638 508968 858144 423732 314299 277036 PCI-MSI-edge nouveau NMI: 68 57 54 49 66 51 38 69 Non-maskable interrupts LOC: 1477693 1742544 1765876 1910964 513009 525984 531958 2214784 Local timer interrupts SPU: 0 0 0 0 0 0 0 0 Spurious interrupts PMI: 68 57 54 49 66 51 38 69 Performance monitoring interrupts IWI: 4371 467 310 533 505 357 275 360 IRQ work interrupts RTR: 6 0 0 0 0 0 0 0 APIC ICR read retries RES: 134654 144649 116848 92117 45669 39876 36313 47002 Rescheduling interrupts CAL: 52294 87270 93843 89098 75381 80948 91265 91551 Function call interrupts TLB: 26135 26093 25448 23842 20976 23850 25294 17155 TLB shootdowns TRM: 0 0 0 0 0 0 0 0 Thermal event interrupts THR: 0 0 0 0 0 0 0 0 Threshold APIC interrupts MCE: 0 0 0 0 0 0 0 0 Machine check exceptions MCP: 50 50 50 50 50 50 50 50 Machine check polls HYP: 0 0 0 0 0 0 0 0 Hypervisor callback interrupts ERR: 0 MIS: 0
MSI разрешены cat /proc/interrupts CODE CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 CPU6 CPU7 0: 17 0 0 0 0 0 0 0 IO-APIC-edge timer 1: 2 0 0 0 0 0 0 0 IO-APIC-edge i8042 8: 1 0 0 0 0 0 0 0 IO-APIC-edge rtc0 9: 0 0 0 0 0 0 0 0 IO-APIC-fasteoi acpi 12: 2 0 0 0 0 1 0 1 IO-APIC-edge i8042 16: 11080 968 13363 535687 41182 4940 73084 4587454 IO-APIC 16-fasteoi ehci_hcd:usb3 17: 66 176 1 2 11 897 3 17 IO-APIC 17-fasteoi snd_hda_intel 19: 10321 11791 4942 10065 16048 32307 16633 31262 IO-APIC 19-fasteoi ata_piix, ata_piix 23: 27 0 0 7 1 0 0 0 IO-APIC 23-fasteoi ehci_hcd:usb4 25: 0 0 0 0 0 0 0 0 PCI-MSI-edge xhci_hcd 26: 17 88916 1 470 4 0 0 9 PCI-MSI-edge eth0 27: 31025 0 1 42 2 2 0 1 PCI-MSI-edge eth1 28: 12 0 0 0 3 0 0 0 PCI-MSI-edge mei_me 29: 27 103 1 1 11 313 20 7 PCI-MSI-edge snd_hda_intel 30: 2145752 747852 565542 547596 947147 459822 339967 308636 PCI-MSI-edge nouveau 31: 10 0 0 0 0 1 0 0 PCI-MSI-edge virtex7 NMI: 74 61 58 53 68 53 40 73 Non-maskable interrupts LOC: 1630591 1926949 1962790 2112890 550816 568671 579103 2443575 Local timer interrupts SPU: 0 0 0 0 0 0 0 0 Spurious interrupts PMI: 74 61 58 53 68 53 40 73 Performance monitoring interrupts IWI: 4389 469 314 604 508 361 279 1490 IRQ work interrupts RTR: 6 0 0 0 0 0 0 0 APIC ICR read retries RES: 140695 148620 119993 95453 48181 41309 37573 50718 Rescheduling interrupts CAL: 54810 89545 96134 90298 77653 83242 93564 92749 Function call interrupts TLB: 27526 27963 26448 26049 22528 24252 25863 18098 TLB shootdowns TRM: 0 0 0 0 0 0 0 0 Thermal event interrupts THR: 0 0 0 0 0 0 0 0 Threshold APIC interrupts MCE: 0 0 0 0 0 0 0 0 Machine check exceptions MCP: 54 54 54 54 54 54 54 54 Machine check polls HYP: 0 0 0 0 0 0 0 0 Hypervisor callback interrupts ERR: 0 MIS: 0
Эскизы прикрепленных изображений
|
|
|
|
|
Aug 8 2015, 15:10
|
Знающий
   
Группа: Участник
Сообщений: 750
Регистрация: 1-11-11
Пользователь №: 68 088

|
Цитата(doom13 @ Aug 6 2015, 15:01)  На рисунке Configuration Space для устройства PCIe есть поле Interrupt Line. Оно, как понимаю, доступно только для чтения. Можете пояснить, что это такое и за что оно отвечает? Насколько я помню, только для чтения поле Interrupt Pin, оно просто определяет, на какую из 4 линий INTA#-INTD# выведена линия прерывания данной платы. Исторически сложилось так, что при конструировании материнских плат линии запросов прерываний от слота к слоту идут со сдвигом, то есть в 1-м слоте PCI INTA подключается к INTA, INTB->INTB, INTC->INTC, INTD->INTD, во 2-м слоте уже INTA->INTB, INTB->INTC, INTC->INTD, INTD->INTA и т. д. Поэтому, если все слоты будут заполнены платами PCI, у которых прерывание выведено на INTA - они равномерно распределятся по всем линиям INTA-INTD. Если какая-то плата окажется с линией INTB - ничего страшного не произойдет, она разделит с другой платой одну линию прерывания. Поэтому конструкторы периферийных плат PCI тоже не мудруствуют лукаво и в 99% случаев используют INTA. Все 4 линии идут в мост, и уже BIOS (или ОС) решает, выделить каждой линии INTA#-INTD# по своему IRQ или всех повесить на одно IRQ. Задача BIOS - изолировать прерывания PCI-устройств от других (ISA, Legacy), которые не могут быть разделены между несколькими устройствами. Interrupt Line регистр - это просто байтовая ячейка памяти, в которую после энумерации энумератор (BIOS или ОС) записывает выделенную для устройства и проложенную до процессора линию IRQ, чтобы драйвер мог разобраться, к чему цеплять обработчик прерывания. Никакого физического смысла, кроме ячейки памяти, поле Interrupt Line не несет. С MSI история примерно та же, только вместо линий INTA#-INTD# используются сообщения с соответствующим номером 1-4 для совместимости, ну и с другими номерами для доп. возможностей.
--------------------
"... часами я мог наблюдать, как люди работают." (М. Горький)
|
|
|
|
Сообщений в этой теме
doom13 PCIe Driver Jul 29 2015, 07:43 doom13 Прерывание стало работать со следующими изменениям... Jul 29 2015, 11:28 doom13 Предположил, что раз система видит устройство как ... Jul 31 2015, 06:47 Tarbal Насколько я понимаю вопрос. PCI имеет механизмы об... Jul 31 2015, 11:45 doom13 Цитата(Tarbal @ Jul 31 2015, 14:45) Наско... Jul 31 2015, 14:37 doom13 Попробовал поменять местами видеокарту и мою плату... Aug 4 2015, 06:40 doom13 Как правильно со стороны ядра выделить память, что... Aug 6 2015, 06:12 doom13 Последний вопрос снят. Посмотрел старую инфу, где
... Aug 6 2015, 07:20 gerber Система не может взять и выделить PCI-устройству л... Aug 6 2015, 09:14  doom13 Цитата(gerber @ Aug 8 2015, 18:10) Interr... Aug 10 2015, 09:43   gerber Цитата(doom13 @ Aug 10 2015, 13:43) Каким... Aug 10 2015, 16:22 Tarbal Цитата(doom13 @ Aug 6 2015, 15:01) Откуда... Aug 17 2015, 13:08 doom13 Хочу ещё спросить по поводу MSI.
Добавил в ядро PC... Aug 6 2015, 13:25 doom13 В драйвере есть операции работы с файлом драйвера ... Aug 13 2015, 11:51 doom13 Посмотрел примеры драйверов, все, оказывается, пол... Aug 13 2015, 13:33 gerber "Нативными" методами работы с драйверами... Aug 13 2015, 21:15 doom13 Ясно, пользуемся open, read, write, close и всё бу... Aug 14 2015, 06:28 doom13 Приветствую!
Возник вопрос, какой максимальный... Sep 30 2015, 11:27 doom13 Если использовать alloc_pages, то вообще выделяет ... Sep 30 2015, 12:33 AVR Цитата(doom13 @ Sep 30 2015, 15:33) Если ... Jul 16 2016, 14:39  dm.pogrebnoy Цитата(AVR @ Jul 16 2016, 17:39) Так это ... Jul 16 2016, 18:00   AVR Цитата(dm.pogrebnoy @ Jul 16 2016, 21:00)... Jul 16 2016, 18:21    dm.pogrebnoy Цитата(AVR @ Jul 16 2016, 21:21) Я может ... Jul 16 2016, 19:15 doom13 Приветствую.
В функции инициализации модуля pcievx... Dec 15 2015, 19:32 Tarbal Я бы поле имени pdev->driver->name напечатал... Dec 16 2015, 02:08  doom13 Цитата(Tarbal @ Dec 16 2015, 05:08) Я бы ... Dec 16 2015, 07:38 doom13 Надо было так:
Кодstatic int pcievx7_probe(str... Dec 16 2015, 11:15
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|