doom13 0 29 июля, 2015 Опубликовано 29 июля, 2015 · Жалоба Приветствую. Есть плата с 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 линии? Код модуля: /* 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; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
doom13 0 29 июля, 2015 Опубликовано 29 июля, 2015 · Жалоба Прерывание стало работать со следующими изменениями: request_irq(pdev->irq, timer_isr, IRQF_SHARED, "PCIe INT", (void *)pdev); // pdev->irq = 16 , ранее использовался неверный флаг IRQF_TRIGGER_RISING и значение pdev->irq = 16. Остался вопрос по номеру линии прерывания. В конфигурационной области PCIe моего устройства записано 11 (Interrupt Line), а прерывание срабатывает для линии №16. Нашёл, что при старте системы плате назначена линия прерывания №11, через некоторое время линию прерывания №11 занимает другое устройство (SMBus Controller). Плате назначается линия прерывания №16, которую она делит с USB Controller-ом, но номер линии прерывания (Interrupt Line) в конфигурационной области PCIe не меняется (может и меняется но функция pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &irq )устанавливает переменную irq = 11)? В struct pci_dev *pdev значение pdev->irq = 16, а если использовать pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &irq) получим irq = 11??? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
doom13 0 31 июля, 2015 Опубликовано 31 июля, 2015 · Жалоба Предположил, что раз система видит устройство как PCI Mouse Controller, то она и вешает его на туже линию прерывания, что и USB Controller. Поменял настройки для PCIe Bridge (теперь класс устройства стал Base system peripherals), но результат одинаков (при старте системы повесило на 11 линию прерывания, после запуска модуля перекинуло на 16). Как сделать так, чтоб моему устройству назначалась отдельная линия прерывания (в системе есть много свободных)? Для мультимедиа-девайс всё аналогично. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Tarbal 4 31 июля, 2015 Опубликовано 31 июля, 2015 · Жалоба Насколько я понимаю вопрос. PCI имеет механизмы обработки прерываний даже если несколько устройств пользуется одним и тем же проводом для вызова прерывания. Много устройств прекрасно ладят используя общий провод для вызова прерываний. Далее пойдут общие соображения и я не поручусь, что они точны, поскольку с PCI мало работал. Прерывание физически присоединено к проводу и задется при изготовлении устройства. Можно изготовить устройство так, что есть возможность выбора. Надо найти документацию на устройство и узнать если есть такая возможность. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
doom13 0 31 июля, 2015 Опубликовано 31 июля, 2015 · Жалоба Насколько я понимаю вопрос. PCI имеет механизмы обработки прерываний даже если несколько устройств пользуется одним и тем же проводом для вызова прерывания. Много устройств прекрасно ладят используя общий провод для вызова прерываний. Да, так и есть - моё PCIe устройство делит Interrupt Line #16 c USB контроллером (при определении обработчика прерывания используется флаг IRQF_SHARED). Но в системе куча свободных линий и хотелось бы повесить его на отдельную. Далее пойдут общие соображения и я не поручусь, что они точны, поскольку с PCI мало работал. Прерывание физически присоединено к проводу и задется при изготовлении устройства. Можно изготовить устройство так, что есть возможность выбора. Надо найти документацию на устройство и узнать если есть такая возможность. А как тогда объяснить что при старте система назначает моему устройству Interrupt Line #11, а потом (загружаю свой модуль в ядро) перебрасывает его на Interrupt Line #16? Как я пока понял прерывания для PCIe работают на уровне Transaction Layer, т.е. устройство PCIe передаёт сигнал прерывания посредством сообщений. Не совсем понимаю разницу между Legacy Interrupt, MSI Interrupt и MSI-X Interrupt, но вроде как речь везде идёт о транзакциях. Посмотрю, что там может быть ещё железного. Спасибо. Раньше драйвер немного неправильно конфигурировал таймер - прерывание срабатывало очень часто. Мышь, клава и всё остальное, что висело на USB контроллере с Interrupt Line #16, жутко тормозили. Счас подправил функции настройки таймера и он отлично делит 16 линию прерывания с USB контроллером. Вопрос, как происходит назначение устройству линии прерывания, остаётся актуальным. Буду благодарен, если кто подскажет. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
doom13 0 4 августа, 2015 Опубликовано 4 августа, 2015 · Жалоба Попробовал поменять местами видеокарту и мою плату с Virtex 7, номера линий прерываний назначаемые устройствам сохранились (у видеокарты было и осталось Interrupt Line 30, для моей платы - 16)??? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
doom13 0 6 августа, 2015 Опубликовано 6 августа, 2015 · Жалоба Как правильно со стороны ядра выделить память, чтобы моё устройство могло писать в неё? Пока сделал так: pc_buffer = kmalloc(pc_buffer_size, GFP_KERNEL); // выделяю буфер pc_buffer_phys = virt_to_phys(pc_buffer); // получаю физический адрес выделенной памяти Полученный физический адрес памяти (32 бита) записываю в регистр PCIe моста в Virtex 7 (старшие 32 бита записываю 0 т.к. возвращаемый адрес 32 бита). Пытаюсь из Xilinx SDK получить доступ к выделенному адресному пространству (через мост). Иногда всё проходит нормально, вижу память выделенную драйвером Linux (предварительно установил все байты буфера в определённое значение). Могу изменить из Xilinx SDK данные в выделенном буфере (в прерывании драйвер мониторит содержимое участка памяти буфера, и могу видеть, что данные меняются). Иногда всё работает как-то криво, либо вообще не могу видеть буфер памяти со стороны FPGA, либо оно подключилось к какому-то другому участку памяти (через мост пишу/читаю данные, т.е. какую-то память он видит, но даннае в буфере драйвера не меняются). Правильно ли я определяю физический адрес выделенной памяти? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
doom13 0 6 августа, 2015 Опубликовано 6 августа, 2015 · Жалоба Последний вопрос снят. Посмотрел старую инфу, где unsigned long virt_to_phys( volatile void *address ); В новых исходниках #ifdef CONFIG_PHYS_ADDR_T_64BIT typedef u64 phys_addr_t; #else typedef u32 phys_addr_t; #endif static inline phys_addr_t virt_to_phys(volatile void *address) { return __pa(address); } , как итог загонял в мост неверный адрес. Вопрос про прерывания остаётся актуальным, пока так и не понял, как система раздаёт линии прерываний. Добавил только разрешение MSI и система при загрузке модуля стала выделять отдельную линию для моего устройства. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
gerber 7 6 августа, 2015 Опубликовано 6 августа, 2015 · Жалоба Система не может взять и выделить PCI-устройству любую линию прерывания, какую посчитает нужным, так как эта линия может схемотехнически тупо не проложена до процессора и аппаратных средств довести эту линию от PCI-устройства до процессора у данной модели материнской платы нет. Как разложены линии прерывания по плате знает только разработчик платы и сообщает эту информацию разработчику BIOS, который в свою очередь строит в BIOS таблицы роутинга для всех слотов PCI. В процессе старта и энумерации всех подключенных PCI-устройств BIOS раздаёт прерывания и прокладывает их до процессора известным ему аппаратным способом, после чего номер выделенного прерывания записывается в соответствующий конфиг-регистр. Этот регистр просто ячейка памяти для драйвера, который будет работать с устройством, то бишь произвольная перезапись номера прерывания не меняет выделенной линии и просто ведет к сбою логики работы драйвера. Операционная система может оставить роутинг PCI-прерываний, как его создал BIOS при загрузке, а может и перестроить по-своему, но опираясь на таблицы роутинга, размещённые в BIOS-e. По практике, поскольку PCI-прерывания работают по уровню и легко разделяются между устройствами, разработчики плат выделяют на PCI 2-3 линии IRQ и всё. Поэтому на уровне физики номер прерывания тот, который записан в регистре устройства и брать для подключения обработчика нужно именно его. Всё остальное, что показывает система - это виртуальные вектора, созданные самой системой в процессе старта драйверов, чтобы как-то разобраться в кипе устройств и отправить пришедшее прерывание IRQ 11 на нужный из 5 подключенных обработчиков. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
doom13 0 6 августа, 2015 Опубликовано 6 августа, 2015 · Жалоба На рисунке 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 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 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 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
doom13 0 6 августа, 2015 Опубликовано 6 августа, 2015 · Жалоба Хочу ещё спросить по поводу MSI. Добавил в ядро PCIe поддержку 4 векторов MSI. Функция pci_msi_vec_count(pdev) возвращает значение 4, т.е. всё правильно. А вот функция pci_enable_msi_range(pdev, 1, 4) возвращает 1. Что это означает, что система может выделить только одну линию под данное устройство? А как тогда должен работать драйвер, должен предполагать возможность обеих ситуаций? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
gerber 7 8 августа, 2015 Опубликовано 8 августа, 2015 · Жалоба На рисунке 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 0 10 августа, 2015 Опубликовано 10 августа, 2015 · Жалоба Interrupt Line регистр - это просто байтовая ячейка памяти, в которую после энумерации энумератор (BIOS или ОС) записывает выделенную для устройства и проложенную до процессора линию IRQ, чтобы драйвер мог разобраться, к чему цеплять обработчик прерывания. Никакого физического смысла, кроме ячейки памяти, поле Interrupt Line не несет. Каким тогда образом, если в Interrupt Line записано 11 (при выполнении функции pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &irq_num) получаю irq_num = 11), прерывание работает на линии № 16 (если MSI запрещены), либо № 31 (если MSI разрешены)? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
gerber 7 10 августа, 2015 Опубликовано 10 августа, 2015 · Жалоба Каким тогда образом, если в Interrupt Line записано 11 (при выполнении функции pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &irq_num) получаю irq_num = 11), прерывание работает на линии № 16 (если MSI запрещены), либо № 31 (если MSI разрешены)? Возможно, это "происки" операционной системы, то есть номера 16 и 31 являются виртуальными номерами прерываний. Так как на одном физическом номере IRQ может висеть несколько PCI-устройств - ОС должна как-то различать, какой драйвер к какому устройству подключается. Для этого ОС "придумывает" свои номера устройствам, а сама "втихаря" подвешивает свой обработчик на IRQ 11. Как только произойдёт IRQ 11 - система передает управление всем подключенным обработчикам (возможно, с приоритетом), пока кто-то из обработчиков не сообщит, что, мол, да, это моё устройство сгенерировало прерывание, и я его обработал. Так система поймет, какое именно устройство сгенерировало прерывание IRQ 11. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
doom13 0 13 августа, 2015 Опубликовано 13 августа, 2015 · Жалоба В драйвере есть операции работы с файлом драйвера (virtex7board_ioctl добавил недавно): static const struct file_operations virtex7board_fops= { .owner = THIS_MODULE, .open = virtex7board_open, .release = virtex7board_release, .read = virtex7board_read, .write = virtex7board_write, .unlocked_ioctl = virtex7board_ioctl, }; Для работы с файлом драйвера из user space использовал fopen, fwrite, fread, fclose и всё было гуд. Теперь добавил в модуль драйвера поддержку ioctl. Тут появились какие-то ошибки. Функция fread как-то неправильно работает, она вызывает virtex7board_ioctl и virtex7board_read и передаёт неправильный размер данных для чтения в virtex7board_read (4096 байт вместо 16). Попробовал использовать open, read, write, close - тут всё нормально. ??? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться