LINUX.ORG.RU

pci driver


0

0

Пишу драйвер для одного PCI устройства, для ядра 2.4.32. Устройство 
представляет собой отладочную плату TI. Драйвер запрашивает у 
устройства передачу данных по DMA. Для этого он записывает в mailbox 
команду, необходимые данные и вызывает прерывание. Далее устройство 
считывает mailbox и выставляет ответное прерывание, что данные 
прочитаны, и начинает передавать данные через DMA. По окончании 
передачи данных выставляется второе прерывание. Из юзерспейса запрос 
данных от устройства происходит через IOCTL. В программе из 
юзерйспейса я создаю нить pthread и в неё дергую ioctl устройства, 
проблема в том что если я корректно завершаю работу приложения и 
дожидаюсь завершения нити все работает хорошо, но стоит мне убить 
приложение некорректно (через kill) или закрыть терминал, то компьютер
 наглухо виснет. Еще проблема в том что драйвер не работает на SMP 
машинах :) Ниже привожу код ioctl


case IOCTL_GETRAW:
        volatile DM64LCPCI_pciRegs *  pciRegs  = (DM64LCPCI_pciRegs *)
        ((Uint32) regVirt + (DM64LCPCI_PCIREG_BASE - 0x01C00000));
        int i,n,CommandCode;
        SC_GT_ELEMENT *sglmb;
        char *data;
        int *r=((int*)ioctl_param);
        
        DECLARE_WAITQUEUE(wait, current);
        CommandCode = RW_CMD_READ_RAW_FRAME;
        
#ifdef _USE_DEBUG        
        printk("Board: got Xfer CMD %i\n",CommandCode);
#endif        

        // Here we lock our spin
        spin_lock(&sl);
        
        if (!expack[CommandCode])
            init_waitqueue_head(wq+CommandCode);
        
        expack[CommandCode]=RW_CARD_CMD(CommandCode);
        expack[0]=RW_CARD_CMD(CommandCode);

        mb->HostRequest.CommandCode=RW_HOST_CMD(CommandCode);
        mb->HostRequest.Info=1;
        mb->CardRequest[CommandCode].CommandCode=NULL_CMD;
        mb->CardRequest[CommandCode].Info=0;
        mb->CardRequest[0].CommandCode=NULL_CMD;
        
        sglmb = mb->Sc_Gt_Element;
        sglmb->Adress = cpu_to_le32(virt_to_bus(pvksdev->raw_buf));
        sglmb->Length = cpu_to_le32(0x100000);
        
#ifdef _USE_DEBUG        
        printk("Board: phys of xferBuf = 0x%x\n", mb->Sc_Gt_Element[0].Adress);
        printk("Board: len of xferBuf = 0x%x\n", mb->Sc_Gt_Element[0].Length);
        printk("Board: set IRQ%i 4 DSP\n", CommandCode);
#endif        
        pciRegs->PCISTATSET = TRIGGER_DSPINT_MASK;
        sti();
        
        for(i=0;i<0x10000;i++)
        {
            if(expack[0]==0x3AEB1C)
            {
#ifdef _USE_DEBUG                
                printk("Board: SGL%i read after %i waiting",CommandCode,i);
#endif                
                break;
            }
        }
        
        if(expack[0]!=0x3AEB1C)
        {
#ifdef _USE_DEBUG                
            printk("Board: cant get SGL%i read!!!",CommandCode);return -2101;
#endif
        }

#ifdef _USE_DEBUG                
        printk("Board: releasing spinlock%i...",CommandCode);
#endif
        cli();
        spin_unlock(&sl);
            
        if(expack[CommandCode]!=0x3AEB1C)
        {
            set_current_state(TASK_INTERRUPTIBLE);
            add_wait_queue(wq+CommandCode, &wait);
            schedule();
            sti();
            if(signal_pending(current))
            {
#ifdef _USE_DEBUG                
                printk("Board: signal%i pending\n",CommandCode);
#endif
                return -2100;
            }
            else
            {
#ifdef _USE_DEBUG                
                printk("Board: signal%i not pending\n",CommandCode);
#endif
            }
            remove_wait_queue(wq+CommandCode, &wait);
        }
        else
        {
#ifdef _USE_DEBUG                
            printk("Board: Xfer%i ALREADY done: no need wait\n",CommandCode);
#endif
        }
            
        n=mb->CardRequest[CommandCode].Info;
#ifdef _USE_DEBUG                
        printk("Board: Receive %d bytes of raw frame\n", n);
#endif        
        
        if (n > 0 && n < 0x100000)
            copy_to_user(r, (const void*)pvksdev->raw_buf, n);
            
        return n;
       
    }

И еще ниже обработчик прерывания от платы:

static void ISR_handler5 (int irq, void * arg, struct pt_regs * flags)
{
    Uint32 status = HAL_CheckPciInterrupt ()  ;
    volatile DM64LCPCI_pciRegs * pciRegs = (DM64LCPCI_pciRegs *)((Uint32)regVirt+ (DM64LCPCI_PCIREG_BASE - 0x01c00000));
    int i,j,k,l,m,n;
    IO_REQUEST*r=(IO_REQUEST*)&mb->HostRequest;
    
    if (status == 1)
    {
#ifdef _USE_DEBUG                
        printk ("Board: Got DSPIRQ\n") ;
#endif
        r = (IO_REQUEST*)&mb->CardRequest;
        for( i = 0; i < 5; i++)
        {
            if((j=r->CommandCode) != NULL_CMD)
            {
                if(expack[i]==j)
                {
                    expack[i]=0x3AEB1C;
                    if(i)
                    {
#ifdef _USE_DEBUG                
                        printk("Board: WAKE ch%i ioQ.\n",i);
#endif                        
                        wake_up_interruptible(wq+i);}
                    else
                    {
#ifdef _USE_DEBUG                
                        printk("Board: SGL ch%i OK.\n",j&0xFF);
#endif                    
                    }
                }
                else
                {
                    r->CommandCode=NULL_CMD;
                }
                r->CommandCode=NULL_CMD;
            }
        r++;
        }
    HAL_PciClearDspInterrupt () ;
    }
    return;
}

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

> ÎÏ ÓÔÏÉÔ ÍÎÅ ÕÂÉÔØ ÐÒÉÌÏÖÅÎÉÅ ÎÅËÏÒÒÅËÔÎÏ (ÞÅÒÅÚ kill) ÉÌÉ ÚÁËÒÙÔØ ÔÅÒÍÉÎÁÌ,
> ÔÏ ËÏÍÐØÀÔÅÒ ÎÁÇÌÕÈÏ ×ÉÓÎÅÔ

Õ ×ÁÓ ÔÕÔ ×ÏÏÂÝÅ ËÁË-ÔÏ ×ÓÅ ÎÅ ÐÒÁ×ÉÌØÎÏ. ÎÕ ×ÏÔ, ÈÏÔÑ ÂÙ:

		 if(expack[CommandCode]!=0x3AEB1C)
		 {
		     set_current_state(TASK_INTERRUPTIBLE);
		     add_wait_queue(wq+CommandCode, &wait);
		     schedule();
		     sti();

ÜÔÏ ×ÏÔ sti() a) ÎÅ ÎÕÖÅÎ, ×ÏÚ×ÒÁÔ ÉÚ schedule() ×ÓÅÇÄÁ ÐÒÏÉÓÈÏÄÉÔ Ó ÒÁÚÒÅÛÅÎÎÙÍÉ
ÐÒËÒÙ×ÁÎÉÑÍÉ É b) ÅÇÏ ×ÏÏÂÝÅ ÎÉËÏÇÄÁ ÎÅÌØÚÑ ÉÓÐÏÌØÚÏ×ÁÔØ (ÕÓÔÁÒÅÌ), Ó CONFIG_SMP
ÜÔÁ ÆÕÎËÃÉÑ ÎÅ ÏÐÒÅÄÅÌÅÎÁ.

		     if(signal_pending(current))
		     {
	 #ifdef _USE_DEBUG
			 printk("Board: signal%i pending\n",CommandCode);
	 #endif
			 return -2100;

ÔÅ, ÅÓÌÉ ×ÙÈÏÄÉÍ ÐÏ ÓÉÇÎÁÌÕ, ÍÙ ÎÅ ÕÄÁÌÑÅÍ ÜÔÏÔ ÐÒÏÃÅÓÓ (ÔÏÞÎÅÅ, ÁÓÓÏÃÉÉÒÏ×ÁÎÎÙÊ
wait) ÉÚ wait_queue_head_t. ÐÏÎÑÔÎÏ, ÞÔÏ ÓÌÅÄÕÀÝÉÊ wake_up() ÐÒÉ×ÏÄÉÔ Ë ËÒÁÈÕ.

Ñ ×ÏÏÂÝÅ ÎÅ ÍÏÇÕ ÐÏÎÑÔØ ÞÔÏ ÜÔÏÔ ËÏÄ ÄÅÌÁÅÔ. ÅÓÌÉ ÏÖÉÄÁÅÔÓÑ ÓÏÂÙÔÉÅ, ÔÏ ×ÓÅ
ÓÏ×ÓÅÍ ÎÅÐÒÁ×ÉÌØÎÏ. ÐÏÌØÚÕÊÔÅÓØ wait_event_interruptible().

idle ★★★★★
()

я надеюсь вы не для МСВС, а то жалко тех, кто потом это обслуживать будет

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

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

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

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

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

Мне вообще жалко всех кто вынужден иметь дело с МСВС :)))

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