Официальный форум СВД Встраиваемые Системы
24 Апрель, 2024, 22:40:46 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.

Войти
 
 
 Сайт СВД ВС  Начало   Помощь Поиск Войти Регистрация  
Страниц: [1]   Вниз
  Печать  
Автор Тема: Драйвер не переходит в обработчик прерывания при генерации MSI прерывания  (Прочитано 2167 раз)
xxxmatrixxx
Интересующийся

Сообщений: 3


« : 13 Февраль, 2018, 11:16:13 »

Всем добрый день!!!

Есть плата с шиной Pci Express, в данной плате реализована работа MSI прерываний

я написал драйвер под Linux, разрешение MSI прерываний осуществляется через функцию pci_msi_anable и все хорошо работало, пока не появилась потребность переписать драйвер под QNX 6.5.0 X86

по документации на pci server(стандартный, что устанавливается вместе с QNX), достаточно просто передать флаг PCI_USE_MSI в функцию pci_attach_device и все само настроится... но вот только не работает...
Код:

const struct sigevent *irq_handler(void *arg, int id)
{
    printf("\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n");
    printf("\nDEV_MIL_DRV_UDx: irq_handler(): begin.\n");
    fflush(stdout);

uint32_t ri, mi, mci, rci;
    DEVICE_MIL *dm;
    int eu = 0;
    dm = (DEVICE_MIL *)arg;

    struct sigevent event;
    int i = 0,err = 0;

    //максируем прерывание
    InterruptMask(dm->irq_num,id);

////////////////////////////////////
!!!code!!!
/////////////////////////////////////

InterruptUnmask(dm->irq_num,id);
    return 0;

}

static __inline__ int pci_detect_card(void)
{ unsigned int minor = 0, devfunc, bus;
int status;
int i;

uint32_t addr_dma_lo, addr_dma_hi;

// создаем поток для драйвера(должны быть root права)
ThreadCtl( _NTO_TCTL_IO, 0 );

printf("\nDEV_MIL_DRV_UDx: try attach to pci-server..");

// подключение к pci серверу
pci_hndl = pci_attach(0);

if (pci_hndl == -1) {
printf("\nDEV_MIL_DRV_UDx: error unable to attach pci");
perror("\npci_attach:");
printf("\nDEV_MIL_DRV_UDx: DEVICE DON'T CREATE");
return - 1;
}

printf("\nDEV_MIL_DRV_UDx: pci_attach good");

plata_cnt = 0;

do{
// проверяем, что слишком много устройств найдено
if(plata_cnt >= MINOR_CNT){
printf("\nDEV_MIL_DRV_UDx: find MAX device(%d) -> exit find device",MINOR_CNT);
return 0;
}
//заполняем структуру для поиска
memset( &device_mil[minor].pci_info, 0, sizeof( device_mil[minor].pci_info ) );
device_mil[minor].pci_info.VendorId = VENDOR_ID;
device_mil[minor].pci_info.DeviceId = DEVICE_ID_UDx;

// начинаем поиск устройства на шине pci
status=pci_find_device(device_mil[minor].pci_info.DeviceId,device_mil[minor].pci_info.VendorId,minor,&bus,&devfunc );
if (status!=PCI_SUCCESS){
device_mil[minor].pci_info.DeviceId = DEVICE_ID_mPCIe;
status=pci_find_device(device_mil[minor].pci_info.DeviceId,device_mil[minor].pci_info.VendorId,minor,&bus,&devfunc );
if (status!=PCI_SUCCESS){
if(minor == 0) // если нет ни одного устройства на шине
{ printf("\nDEV_MIL_DRV_UDx: don't find device");
goto err1;
}
else{
printf("\nDEV_MIL_DRV_UDx: find %d device",plata_cnt);
return 0;
}
}
}

// запоминаем индекс устройства
device_mil[minor].minor = minor;
plata_cnt++; // увеличиваем общее количество устройств

printf("\nDEV_MIL_DRV_UDx: pci_find_device good");
printf("\nDEV_MIL_DRV_UDx: Find device(Vendor_ID = %x, Device_ID = %x, Minor = %d)",device_mil[minor].pci_info.DeviceId,device_mil[minor].pci_info.VendorId, minor);
device_mil[minor].vendor_id = device_mil[minor].pci_info.VendorId;
device_mil[minor].device_id = device_mil[minor].pci_info.DeviceId;

// подключение к pci устройству
device_mil[minor].pci_dev_hndl = pci_attach_device(NULL,( PCI_SHARE | PCI_SEARCH_VENDEV | PCI_INIT_ALL | PCI_INIT_IRQ | PCI_MASTER_ENABLE | PCI_USE_MSI),minor,&device_mil[minor].pci_info);
if(device_mil[minor].pci_dev_hndl == NULL){
printf("\nDEV_MIL_DRV_UDx: error attach device");
perror("\npci_attach_device:");
goto err2;
}

printf("\nDEV_MIL_DRV_UDx: pci_attach_device good");

printf("\nDEV_MIL_DRV_UDx: SUMMARY INFO DEVICE");
printf("\nDEV_MIL_DRV_UDx: Device_ID = 0x%x",device_mil[minor].pci_info.DeviceId);
printf("\nDEV_MIL_DRV_UDx: Vendor_ID = 0x%x",device_mil[minor].pci_info.VendorId);
printf("\nDEV_MIL_DRV_UDx: Bus Number = 0x%x",device_mil[minor].pci_info.BusNumber);
printf("\nDEV_MIL_DRV_UDx: Device Function = 0x%x",device_mil[minor].pci_info.DevFunc);
printf("\nDEV_MIL_DRV_UDx: Device Class = 0x%x",device_mil[minor].pci_info.Class);
printf("\nDEV_MIL_DRV_UDx: Device IRQ = 0x%x(%d)",device_mil[minor].pci_info.Irq,device_mil[minor].pci_info.Irq);
printf("\nDEV_MIL_DRV_UDx: MSI REG = 0x%x",device_mil[minor].pci_info.msi);

device_mil[minor].bars = 0;
for(i =0; i < 6; i++){
printf("\nDEV_MIL_DRV_UDx: BAR%d Address = 0x%x, Size = 0x%x",i,(uint32_t)(device_mil[minor].pci_info.CpuBaseAddress[i]),(uint32_t)(device_mil[minor].pci_info.BaseAddressSize[i]));
// смотрим, что за бар у нас
if ((PCI_IS_MEM(device_mil[minor].pci_info.CpuBaseAddress[i])) && (device_mil[minor].pci_info.CpuBaseAddress[i]!=0x00000000)){
printf("\nDEV_MIL_DRV_UDx: BAR%d is Memory",i);
device_mil[minor].bars++;
}
else if((PCI_IS_IO(device_mil[minor].pci_info.CpuBaseAddress[i])) && (device_mil[minor].pci_info.CpuBaseAddress[i]!=0x00000000)){
printf("\nDEV_MIL_DRV_UDx: BAR%d is I/O",i);
device_mil[minor].bars++;
}
}
// инициализаци bar0
if ((PCI_IS_MEM(device_mil[minor].pci_info.CpuBaseAddress[0])) && (device_mil[minor].pci_info.CpuBaseAddress[0]!=0x00000000)){
printf("\nDEV_MIL_DRV_UDx: BAR0 is Memory");
printf("\nDEV_MIL_DRV_UDx: BAR0 Address = 0x%x, Size = 0x%x",(uint32_t)(device_mil[minor].pci_info.CpuBaseAddress[0]),(uint32_t)(device_mil[minor].pci_info.BaseAddressSize[0]));
// физический адрес
device_mil[minor].base_addr0 = PCI_MEM_ADDR(device_mil[minor].pci_info.CpuBaseAddress[0]);
printf("\nDEV_MIL_DRV_UDx: PCI_MEM_ADDR BAR0 Address = 0x%lx",(unsigned long int)device_mil[minor].base_addr0);
// виртуальный адрес
device_mil[minor].base_addr = mmap_device_memory(NULL, device_mil[minor].pci_info.BaseAddressSize[0], PROT_NOCACHE | PROT_READ | PROT_WRITE, 0, device_mil[minor].base_addr0);
printf("\nDEV_MIL_DRV_UDx: mmap_device_memory base_addr0 = 0x%lx,base_addr = 0x%lx",(unsigned long int)device_mil[minor].base_addr0,(unsigned long int)device_mil[minor].base_addr);
if ( device_mil[minor].base_addr == MAP_FAILED ) {
printf("\nDEV_MIL_DRV_UDx: mmap device memory failed");
    perror( "\nmmap_device_memory for physical address failed" );
    goto err2;
}
}
else {
printf("\nDEV_MIL_DRV_UDx: BAR0 is BAD");
goto err2;
}

printf("\nDEV_MIL_DRV_UDx: allocate BAR0");

// выделяем память под dma
device_mil[minor].addr_dma = mmap(0,SIZE_DMA,(PROT_READ | PROT_WRITE | PROT_NOCACHE), MAP_ANON | MAP_PHYS  ,NOFD,0);
if(device_mil[minor].addr_dma == MAP_FAILED){
printf("\nDEV_MIL_DRV_UDx: dma mmap failed");
perror("\nmmap:");
goto err3;
}

if( mem_offset64(device_mil[minor].addr_dma,NOFD,SIZE_DMA,(off64_t *)&device_mil[minor].addr_dma_1,0) != 0){
printf("\nDEV_MIL_DRV_UDx: don't get physical address");
perror("\nmem_offset:");
goto err4;
}

printf("\nDEV_MIL_DRV_UDx: DMA addr_dma1 = 0x%lx,addr_dma = 0x%lx",(unsigned long int)device_mil[minor].addr_dma_1,(unsigned long int)device_mil[minor].addr_dma);
//memset(device_mil[minor].addr_dma, 0x12, SIZE_DMA);        // clear DMA
addr_dma_lo = (device_mil[minor].addr_dma_1 & 0xffffffff); // low part address DMA
addr_dma_hi = (device_mil[minor].addr_dma_1 >> 32) & 0xffffffff; // hi part address DMA
*(uint32_t*)(device_mil[minor].base_addr + DMA_DATA_BASE) = addr_dma_lo;
*(uint32_t*)(device_mil[minor].base_addr + DMA_DATA_BASE_HI) = addr_dma_hi;
printf("\nDEV_MIL_DRV_UDx: to address = 0x%lx was written 0x%x", (long unsigned int)(device_mil[minor].base_addr + DMA_DATA_BASE),(unsigned int) addr_dma_lo);
printf("\nDEV_MIL_DRV_UDx: to address = 0x%lx was written 0x%x", (long unsigned int)(device_mil[minor].base_addr + DMA_DATA_BASE_HI), (unsigned int)addr_dma_hi);
printf("\nDEV_MIL_DRV_UDx: allocate DMA");

//записываем номер MSI прерывания
device_mil[minor].irq_num = device_mil[minor].pci_info.Irq;
if(device_mil[minor].pci_info.msi) printf("\nDEV_MIL_DRV_UDx: MSI enable, MSI irq is %d",device_mil[minor].irq_num);
else printf("\nDEV_MIL_DRV_UDx: !!! MSI DON'T ENABLE, YOU MUST DON'T USE INTERRUPT FOR WORK WITH MODULE!!!");

//регистрируем обработчик прерывания
device_mil[minor].di.int_id = InterruptAttach(device_mil[minor].irq_num,irq_handler,&device_mil[minor],sizeof(device_mil[minor]),_NTO_INTR_FLAGS_END | _NTO_INTR_FLAGS_TRK_MSK);
if(device_mil[minor].di.int_id == -1)
{ printf("\nDEV_MIL_DRV_UDx: error interrupt attach");
perror("\nInterruptAttach:");
goto err4;
}

// определяем тип и преобразуем его
device_mil[minor].dev_type = ((*(uint32_t*)(device_mil[minor].base_addr + 0x1034)) >> 24) & 0xFF;
printf("\nDEV_MIL_DRV_UDx: DEVICE TYPE = 0x%x", device_mil[minor].dev_type);
switch (device_mil[minor].dev_type){
case 0x03:
device_mil[minor].dev_type = PCIe_1553UD;
break;
case 0x23:
device_mil[minor].dev_type = PCIe_1553UD2;
break;
case 0x43:
device_mil[minor].dev_type = PCIe_1553UD4;
break;
default:
printf("\nDEV_MIL_DRV_UDx: error device type");
goto err5;
break;
}

sprintf((char *)&device_mil[minor].dev_name, "/dev/%s_%d",MIL1553UDx_DRIVER_MASKNAME,minor);
printf("\nDEV_MIL_DRV_UDx: device path with name is %s",device_mil[minor].dev_name);
status = pthread_mutex_init(&device_mil[minor].mutex_dma,NULL);
if(status != EOK)
{ printf("\nDEV_MIL_DRV_UDx: error pthread mutex init %d",status);
perror("\npthread_mutex_init:");
goto err5;
}
printf("\nDEV_MIL_DRV_UDx: DEVICE CREATE GOOD");
fflush(stdout);
minor++;
}while(1);

// подчищаем текущее устройство
err5: for(minor = 0; minor < plata_cnt; minor++) InterruptDetach(device_mil[minor].di.int_id);
err4: for(minor = 0; minor < plata_cnt; minor++) munmap(device_mil[minor].addr_dma, SIZE_DMA);
err3: for(minor = 0; minor < plata_cnt; minor++) munmap_device_memory(device_mil[minor].base_addr, device_mil[minor].pci_info.BaseAddressSize[0]);
err2: for(minor = 0; minor < plata_cnt; minor++) pci_detach_device(device_mil[minor].pci_dev_hndl);
err1: pci_detach(pci_hndl);

printf("\nDEV_MIL_DRV_UDx: DEVICE DON'T CREATE");
return -1;
}

я изменил загрузчик QNX, чтобы он загружал startup-apic и pci-bios-v2(qnxbasesmp-apic.build)

Код:
#
# The build file for QNX Neutrino booting on a PC
#
[linker="ntox86-ld -T$QNX_TARGET/x86/lib/nto.link %(h!=0, -Ttext 0x%t%)%(d!=0, -Tdata 0x%d%) -o%o %i %[M -L%^i -uinit_%n -lmod_%n%]"]
[virtual=x86,bios +compress] boot = {
# Reserve 64k of video memory to handle multiple video cards
startup-apic -v -s64k

# PATH is the *safe* path for executables (confstr(_CS_PATH...))
# LD_LIBRARY_PATH is the *safe* path for libraries (confstr(_CS_LIBPATH))
#    i.e. This is the path searched for libs in setuid/setgid executables.
PATH=/proc/boot:/bin:/usr/bin:/opt/bin LD_LIBRARY_PATH=/proc/boot:/lib:/usr/lib:/lib/dll:/opt/lib procnto-smp-instr
}

[+script] startup-script = {
# To save memory make everyone use the libc in the boot image!
# For speed (less symbolic lookups) we point to libc.so.3 instead of libc.so
procmgr_symlink ../../proc/boot/libc.so.3 /usr/lib/ldqnx.so.2

# Default user programs to priorty 10, other scheduler (pri=10o)
# Tell "diskboot" this is a hard disk boot (-b1)
# Tell "diskboot" to use DMA on IDE drives (-D1)
# Start 4 text consoles buy passing "-n4" to "devc-con" (-o)
# By adding "-e" linux ext2 filesystem will be mounted as well.
[pri=10o] PATH=/proc/boot diskboot -b1 -D1 -odevc-con,-n4 -odevc-con-hid,-n4
}

# Include the current "libc.so". It will be created as a real file using
# its internal "SONAME", with "libc.so" being a symlink to it. The symlink
# will point to the last "libc.so.*" so if an earlier libc is needed
# (e.g. libc.so.1) add it before the this line.
libc.so
libhiddi.so
libusbdi.so

# Include all the files for the default filesystems
libcam.so
io-blk.so
cam-disk.so
fs-qnx4.so
fs-qnx6.so
fs-dos.so
fs-ext2.so
cam-cdrom.so
fs-cd.so
fs-udf.so
fs-nt.so
fs-mac.so

# USB for console driver
devu-ehci.so
devu-ohci.so
devu-uhci.so
devh-usb.so
devh-ps2ser.so

[data=copy]
seedres
pci-bios=pci-bios-v2
devb-eide
devb-umass
devb-ahci
devb-mvSata
devb-adpu320
devb-aha8
umass-enum
[search=${QNX_TARGET}/etc] umass-enum.cfg
io-usb
io-hid
diskboot
slogger
fesh
devc-con
devc-con-hid

# These files will be unlinked after the system has started
# to release the memory back to the system. They are only
# needed during boot. If needed later on, they will be loaded
# from the boot device.
unlink_list={
/proc/boot/devb-*
}


в драйвере подключаюсь к pci server и инициализирую msi прерывания, затем подключаю обработчик прерывания, но в обработчик прерывания драйвер не заходит(нет сообщений из обработчика), причем я точно знаю, что с модуля tlp пакет msi сообщения уходит, именно на стороне QNX оно игнорируется или блокируется

 
лог pci -vvv после загрузки драйвера
Код:
Class          = Communication (Other)
Vendor ID      = a203h, Unknown
Device ID      = 9472h, Unknown Unknown
PCI index      = 0h
Class Codes    = 078000h
Revision ID    = 3h
Bus number     = 3
Device number  = 0
Function num   = 0
Status Reg     = 10h
Command Reg    = 507h
I/O space access enabled
Memory space access enabled
Bus Master enabled
Special Cycle operations ignored
Memory Write and Invalidate disabled
Palette Snooping disabled
Parity Error Response disabled
Data/Address stepping disabled
SERR# driver enabled
Fast back-to-back transactions to different agents disabled
PCI INTx disabled
Header type    = 0h Single-function
BIST           = 0h Build-in-self-test not supported
Latency Timer  = 0h
Cache Line Size= 8h un-cacheable
BAR - 0 [Mem]  = f7d80000h 64bit length 524288 enabled
Subsystem Vendor ID = a203h
Subsystem ID        = 9472h
Max Lat        = 0ns
Min Gnt        = 0ns
PCI Int Pin    = INT A
Interrupt line = 4
CPU Interrupt  = 104h
Capabilities Pointer = 40h
Capability ID        = 1h - Power Management
Capabilities         = 7e03h - 8h
Capability ID        = 5h - Message Signaled Interrupts
Capabilities         = 81h - fee00000h Enabled
Capability ID        = 10h - PCI Express
Capabilities         = 1h - 288fc0h
Device Dependent Registers:
0x040:  0148 037e 0800 0000   0558 8100 0000 e0fe
0x050:  0000 0000 5200 0000   1000 0100 c08f 2800
0x060:  1028 0b00 11f4 0300   0000 1110 0000 0000
0x070:  0000 0000 0000 0000   0000 0000 0000 0000
...
0x0f0:  0000 0000 0000 0000   0000 0000 0000 0000

лог загрузки драйвера
Код:

DEV_MIL_DRV_UDx: try attach to pci-server..
DEV_MIL_DRV_UDx: pci_attach good
DEV_MIL_DRV_UDx: pci_find_device good
DEV_MIL_DRV_UDx: Find device(Vendor_ID = 9472, Device_ID = a203, Minor = 0)
DEV_MIL_DRV_UDx: pci_attach_device good
DEV_MIL_DRV_UDx: SUMMARY INFO DEVICE
DEV_MIL_DRV_UDx: Device_ID = 0x9472
DEV_MIL_DRV_UDx: Vendor_ID = 0xa203
DEV_MIL_DRV_UDx: Bus Number = 0x3
DEV_MIL_DRV_UDx: Device Function = 0x0
DEV_MIL_DRV_UDx: Device Class = 0x78000
DEV_MIL_DRV_UDx: Device IRQ = 0x104(260)
DEV_MIL_DRV_UDx: MSI REG = 0x1
DEV_MIL_DRV_UDx: BAR0 Address = 0xf7d80004, Size = 0x80000
DEV_MIL_DRV_UDx: BAR0 is Memory
DEV_MIL_DRV_UDx: BAR1 Address = 0x0, Size = 0x0
DEV_MIL_DRV_UDx: BAR2 Address = 0x0, Size = 0x0
DEV_MIL_DRV_UDx: BAR3 Address = 0x0, Size = 0x0
DEV_MIL_DRV_UDx: BAR4 Address = 0x0, Size = 0x0
DEV_MIL_DRV_UDx: BAR5 Address = 0x0, Size = 0x0
DEV_MIL_DRV_UDx: BAR0 is Memory
DEV_MIL_DRV_UDx: BAR0 Address = 0xf7d80004, Size = 0x80000
DEV_MIL_DRV_UDx: PCI_MEM_ADDR BAR0 Address = 0xf7d80000
DEV_MIL_DRV_UDx: mmap_device_memory base_addr0 = 0xf7d80000,base_addr = 0x40100000
DEV_MIL_DRV_UDx: allocate BAR0
DEV_MIL_DRV_UDx: DMA addr_dma1 = 0xbc800000,addr_dma = 0x8400000
DEV_MIL_DRV_UDx: to address = 0x40101000 was written 0xbc800000
DEV_MIL_DRV_UDx: to address = 0x40101004 was written 0x0
DEV_MIL_DRV_UDx: allocate DMA
DEV_MIL_DRV_UDx: MSI enabled, MSI IRQ is 260
DEV_MIL_DRV_UDx: DEVICE TYPE = 0x43
DEV_MIL_DRV_UDx: device path with name is /dev/PCIe_1553UDx_0
DEV_MIL_DRV_UDx: DEVICE CREATE GOOD
DEV_MIL_DRV_UDx: find 1 device
DEV_MIL_DRV_UDx: attach resource manager for device with name /dev/PCIe_1553UDx_0
DEV_MIL_DRV_UDx: resource manager attach, minor = 0
DEV_MIL_DRV_UDx: start pool 1 threads
DEV_MIL_DRV_UDx: io_open
DEV_MIL_DRV_UDx: minor = 0

уважаемые форумчане, был ли у кого опыт включения MSI прерываний под QNX 6.5.0 X86, поделитесь, пожалуйста опытом, 2 недели уже бьюсь, пока результата никакого?Huh?
 
спасибо, жду вашего ответа
Записан
Владимир Махилёв
Сотрудник СВД ВС
Старожил

Сообщений: 704



WWW
« Ответ #1 : 13 Февраль, 2018, 17:45:45 »

Каким-либо специальным образом включать MSI прерывания не требуется. Номер прерывания назначается автоматически при подключении к устройству, исходя из PCI Capabilities и, судя по отладочному выводу, вашему устройству назначено именно MSI прерывание с номером 260 .

Обратите особое внимание на то, что в обработчике прерывания, добавленном с помощью InterruptAttach(), разрешено использовать очень ограниченный набор функций поскольку код будет работать в контексте ядра. В документации к каждой функции есть таблица  в которой указано какие функции можно использовать:
Код:
Safety
Interrupt handler: Yes

Функцию printf() использовать в таком обработчике нельзя и если вы хотите получить отладочный вывод, то вам потребуется в обработчике сохранить нужные значения и вывести из потока драйвера. Например,
Код:
struct sigevent int_event;

const struct sigevent *handler (void *area, int id)
{
    InterruptMask (int_n, id);
    int_counter++;
    return (&int_event);
}

int main( int argc, char **argv )
{
    ...
    int_event.sigev_notify = SIGEV_INTR;
    InterruptAttach( int_n, &handler, NULL, 0, 0);
    ...

    while (1)
    {
        InterruptWait(0, NULL);
        printf (" Got interrupt %lu ( 0x%lX ) #%4ld\n", int_n, int_n, int_counter);
        InterruptUnmask (int_n, id);
    }
    ...
}
« Последнее редактирование: 13 Февраль, 2018, 17:47:26 от Владимир Махилёв » Записан

xxxmatrixxx
Интересующийся

Сообщений: 3


« Ответ #2 : 14 Февраль, 2018, 13:59:04 »

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

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

вот сам обработчик прерывания
Код:

volatile uint32_t int_counter = 0;

const struct sigevent *irq_handler(void *arg, int id)
{
//printf("\nDEV_MIL_DRV_UDx: irq_handler(): begin.\n");

uint32_t ri, mi, mci, rci;
    DEVICE_MIL *dm;
    int eu = 0;
    dm = (DEVICE_MIL *)arg;

    struct sigevent event;
    int i = 0,err = 0;

    //максируем прерывание
    InterruptMask(dm->irq_num,id);
    int_counter++;

    ri = *(uint32_t*)(dm->base_addr + INTERRUPT_REG);
    mi = *(uint32_t*)(dm->base_addr + INTERRUPT_MASK_REG);
    ri &= mi;
    if (ri == 0){
        //демаксируем прерывание
        InterruptUnmask(dm->irq_num,id);
    return 0;
    }
    eu = 0;
    //==============1 Channel=================
    if (ri & INTR_HDAT_1CH) {
dm->di.fl[0] = 1; eu = 1;
    }
    if (ri & INTR_QDAT_1CH) {
dm->di.fl[4] = 1; eu = 1;
    }
    if (ri & INTR_SADDR_1CH) {
rci = *(uint32_t*)(dm->base_addr + HW_STAT_REG2_1CH);
mci = *(uint32_t*)(dm->base_addr + MIL_RT_INT_REG_1CH);
if ((rci & RT_INT_REN) && (mci & RT_INT_REN_MASK )) {
    dm->di.fl[16] = 1; eu = 1;
}
if ((rci & RT_INT_TEN) && (mci & RT_INT_TEN_MASK)) {
    dm->di.fl[20] = 1; eu = 1;
}
    }
    if (ri & INTR_MC_ERR_1CH) {
rci = *(uint32_t*)(dm->base_addr + HW_STAT_REG2_1CH);
mci = *(uint32_t*)(dm->base_addr + MIL_RT_INT_REG_1CH);
if ((rci & RT_INT_ERR) && (mci & RT_INT_ERR_MASK  )) {
    dm->di.fl[12] = 1; eu = 1;
}
if ((rci & RT_INT_MC) && (mci & RT_INT_MC_MASK)) {
    dm->di.fl[8] = 1; eu = 1;
}
    }
    if (ri & INTR_BC_1CH) {
dm->di.fl[24] = 1; eu = 1;
    }
    //==============2 Channel=================
    if (ri & INTR_HDAT_2CH) {
dm->di.fl[1] = 1; eu = 1;
    }
    if (ri & INTR_QDAT_2CH) {
dm->di.fl[5] = 1; eu = 1;
    }
    if (ri & INTR_SADDR_2CH) {
//printf("\nDEV_MIL_DRV_UDx: irq_handler(): INTR_SADDR_2CH.\n");
rci = *(uint32_t*)(dm->base_addr + HW_STAT_REG2_2CH);
//printf("\nDEV_MIL_DRV_UDx: irq_handler(): rci = 0x%x.\n", (unsigned int)rci);
mci = *(uint32_t*)(dm->base_addr + MIL_RT_INT_REG_2CH);
//printf("\nDEV_MIL_DRV_UDx: irq_handler(): mci = 0x%x.\n", (unsigned int)mci);
if ((rci & RT_INT_REN) && (mci & RT_INT_REN_MASK )) {
    //printf("\nDEV_MIL_DRV_UDx: irq_handler(): RT_INT_REN_MASK.\n");
    dm->di.fl[17] = 1; eu = 1;
}
if ((rci & RT_INT_TEN) && (mci & RT_INT_TEN_MASK)) {
    dm->di.fl[21] = 1; eu = 1;
}
    }
    if (ri & INTR_MC_ERR_2CH) {
rci = *(uint32_t*)(dm->base_addr + HW_STAT_REG2_2CH);
mci = *(uint32_t*)(dm->base_addr + MIL_RT_INT_REG_2CH);
if ((rci & RT_INT_ERR) && (mci & RT_INT_ERR_MASK  )) {
    dm->di.fl[13] = 1; eu = 1;
}
if ((rci & RT_INT_MC) && (mci & RT_INT_MC_MASK)) {
    dm->di.fl[9] = 1; eu = 1;
}
    }
    if (ri & INTR_BC_2CH) {
dm->di.fl[25] = 1; eu = 1;
    }
    //==============3 Channel=================
    if (ri & INTR_HDAT_3CH) {
dm->di.fl[2] = 1; eu = 1;
    }
    if (ri & INTR_QDAT_3CH) {
dm->di.fl[6] = 1; eu = 1;
    }
    if (ri & INTR_SADDR_3CH) {
rci = *(uint32_t*)(dm->base_addr + HW_STAT_REG2_3CH);
mci = *(uint32_t*)(dm->base_addr + MIL_RT_INT_REG_3CH);
if ((rci & RT_INT_REN) && (mci & RT_INT_REN_MASK )) {
    dm->di.fl[18] = 1; eu = 1;
}
if ((rci & RT_INT_TEN) && (mci & RT_INT_TEN_MASK)) {
    dm->di.fl[22] = 1; eu = 1;
}
    }
    if (ri & INTR_MC_ERR_3CH) {
rci = *(uint32_t*)(dm->base_addr + HW_STAT_REG2_3CH);
mci = *(uint32_t*)(dm->base_addr + MIL_RT_INT_REG_3CH);
if ((rci & RT_INT_ERR) && (mci & RT_INT_ERR_MASK  )) {
    dm->di.fl[14] = 1; eu = 1;
}
if ((rci & RT_INT_MC) && (mci & RT_INT_MC_MASK)) {
    dm->di.fl[10] = 1; eu = 1;
}
    }
    if (ri & INTR_BC_3CH) {
dm->di.fl[26] = 1; eu = 1;
    }
    //==============4 Channel=================
    if (ri & INTR_HDAT_4CH) {
dm->di.fl[3] = 1; eu = 1;
    }
    if (ri & INTR_QDAT_4CH) {
dm->di.fl[7] = 1; eu = 1;
    }
    if (ri & INTR_SADDR_4CH) {
rci = *(uint32_t*)(dm->base_addr + HW_STAT_REG2_4CH);
mci = *(uint32_t*)(dm->base_addr + MIL_RT_INT_REG_4CH);
if ((rci & RT_INT_REN) && (mci & RT_INT_REN_MASK )) {
    dm->di.fl[19] = 1; eu = 1;
}
if ((rci & RT_INT_TEN) && (mci & RT_INT_TEN_MASK)) {
    dm->di.fl[23] = 1; eu = 1;
}
    }
    if (ri & INTR_MC_ERR_4CH) {
rci = *(uint32_t*)(dm->base_addr + HW_STAT_REG2_4CH);
mci = *(uint32_t*)(dm->base_addr + MIL_RT_INT_REG_4CH);
if ((rci & RT_INT_ERR) && (mci & RT_INT_ERR_MASK  )) {
    dm->di.fl[15] = 1; eu = 1;
}
if ((rci & RT_INT_MC) && (mci & RT_INT_MC_MASK)) {
    dm->di.fl[11] = 1; eu = 1;
}
    }
    if (ri & INTR_BC_4CH) {
dm->di.fl[27] = 1; eu = 1;
    }
    if (eu == 0){
    //демаксируем прерывание
    InterruptUnmask(dm->irq_num,id);
    return 0;
    }

    // передаем сигналы
    for ( i = 0; i < 27; i++)  // check event
if (dm->di.fl[i]) { // ready?
dm->di.fl[i] = 0; // clear event
if (dm->di.proc_pid[i] && dm->di.sig_no[i]) {

// заполняем структуру отправки сигнала
// dm->di.proc_pid[i] выступает за rcvid
SIGEV_SIGNAL_INIT(&event,dm->di.sig_no[i]);

// сначала проверяем
err = MsgVerifyEvent(dm->di.proc_pid[i],&event);
if(err == -1){
//printf("\nDEV_MIL_DRV_UDx: error verify event");
//perror("\nMsgVerifyEvent:");
InterruptUnmask(dm->irq_num,id);
return 0;
}
else{
MsgDeliverEvent(dm->di.proc_pid[i], &event);
//printf("\nDEV_MIL_DRV_UDx:: delivered event,sig_no = %d",(uint32_t)dm->di.sig_no[i]);
}
}
}

    //демаксируем прерывание
    InterruptUnmask(dm->irq_num,id);
    return 0;
}

void*  thread_irq( void*  arg )
{
printf ("\nDEV_MIL_DRV_UDx: Start Thread for count IRQ, irq counter = #%d", int_counter);
      uint32_t cur_int_counter = int_counter;
    while (1)
    {  if(cur_int_counter != int_counter){
        printf ("\nDEV_MIL_DRV_UDx: Got MSI interrupt, irq counter = #%d", int_counter);
        fflush(stdout);
        cur_int_counter = int_counter;
       }
    }
}

int main(int argc, char *argv[]) {
int minor = 0;

// поиск устройства и инициализация
if(pci_detect_card()) return (EXIT_FAILURE);

// запускаем поток на отслеживание прерывания
pthread_create( NULL, NULL, &thread_irq, NULL );

// запуск менеджера ресурсов
if(pci_resource_manager()){
// подчищаем
for(minor = 0; minor < plata_cnt; minor++) pci_remove_card(minor);

pci_detach(pci_hndl);

return (EXIT_FAILURE);
}

// подчищаем
for(minor = 0; minor < plata_cnt; minor++) pci_remove_card(minor);

pci_detach(pci_hndl);

return (EXIT_SUCCESS);
}


в обработчике я все printf убрал, у меня работает менеджер ресурсов, чтобы отслеживать devctl запросы, поэтому решил выделить отдельный поток, который будет проверять значение счетчика прерывания, но поток thread_irq стартует(видно по отладочной печати), но вот когда должно было прийти прерывание в драйвер, я не вижу в отладочной печати сообщения о получении прерывания
Записан
Владимир Махилёв
Сотрудник СВД ВС
Старожил

Сообщений: 704



WWW
« Ответ #3 : 14 Февраль, 2018, 17:38:19 »


Для ожидания прерывания проще всего воспользоваться InterruptWait(), пример кода есть выше и прикрепляю к сообщению простую утилиту. Номер прерывания задаётся через параметр -i
Помимо непосредственно ожидания прерывания необходимо как минимум проинициализировать устройство и включить прерывания с его стороны.

При беглом просмотре обратил внимание, что в коде обработчика может вызываться MsgVerifyEvent() - в обработчике InterruptAttach() это делать нельзя. Также нет необходимости вручную вызывать Mask/Unmask внутри обработчика, пока управление в нём, прерывание будет оставаться замаскированным.

По материалам - рекомендую ознакомиться со следующими статьими:
Обработка прерываний
Writing an Interrupt Handler
InterruptAttach()
И книгой Введение в QNX Neutrino

Записан

xxxmatrixxx
Интересующийся

Сообщений: 3


« Ответ #4 : 15 Февраль, 2018, 14:51:50 »

Огромное спасибо за помощь, наконец, разобрался)))

переписал код через InterruptAttachEvent, все заработало

формально сделал таким образом - в процессе иниицализации создается поток thread_irq, который регистрирует прерывание и ждет его, по приходу посылает сигнал


Код:
void *thread_irq(void *arg)
{ uint32_t ri, mi, mci, rci;
    int eu = 0;
    unsigned int minor = *(unsigned int *)arg;

    struct sigevent int_event; //текущее событие

    struct sigevent event;
    int i = 0,err = 0;

    printf("\nDEV_MIL_DRV_UDx: Start irq_thread(), minor = %d",minor);

//записываем номер MSI прерывания
device_mil[minor].irq_num = device_mil[minor].pci_info.Irq;
if(device_mil[minor].pci_info.msi) printf("\nDEV_MIL_DRV_UDx: MSI enable, MSI irq is %d",device_mil[minor].irq_num);
else printf("\nDEV_MIL_DRV_UDx: !!! MSI DON'T ENABLE, YOU MUST DON'T USE INTERRUPT FOR WORK WITH MODULE!!!");

// создаем поток для драйвера(должны быть root права)
    if(ThreadCtl(_NTO_TCTL_IO, 0) != EOK){
        printf("\nDEV_MIL_DRV_UDx: You must be root!");
        pthread_exit((void*)-1);
    }

//регистрируем обработчик прерывания
int_event.sigev_notify = SIGEV_INTR;
device_mil[minor].di.int_id = InterruptAttachEvent(device_mil[minor].irq_num,&int_event,0);
if(device_mil[minor].di.int_id == -1)
{ printf("\nDEV_MIL_DRV_UDx: error interrupt attach");
perror("\nInterruptAttach:");
pthread_exit((void*)-1);
}

while(1){
//ожидаем прерывания
InterruptWait( 0, NULL);

printf("\nDEV_MIL_DRV_UDx: irq_handler(): begin.\n");
               
                !!!!!code!!!!

        }
}

теперь буду только использовать InterruptAttachEvent)))

еще раз огромное спасибо за помощь!!!)))
Записан
Олег Большаков
Легенда

Сообщений: 3140



« Ответ #5 : 15 Февраль, 2018, 22:36:32 »

теперь буду только использовать InterruptAttachEvent)))

На самом деле, использование именно InterruptAttachEvent() вместо InterruptAttach() хорошая практика. Во-первых, обработка прерывания в потоке проще для разработчика (меньше ограничений на используемые функции). Во-вторых, в этом случае система становится более детерминированной, т.к. управлять приоритетами потоков проще, чем приоритетами прерываний. Но не во всех случаях возможно использовать обработчик прерывания в потоке. Если требуется быстрая реакция на частые события прерывания, а код обработчика маленький (и быстрый), то следует использовать InterruptAttach().
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  

Powered by MySQL Powered by PHP © 2002-2024 СВД Встраиваемые Системы.
При использовании материалов сайта ссылка на forum.kpda.ru обязательна.

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines | © Aiwan. Kolobok smiles | Sitemap
Valid XHTML 1.0! Valid CSS!
Сайт СВД ВС

В последний раз google посещал эту страницу 16 Апрель, 2024, 23:27:14