LINUX.ORG.RU

проблема с обработкой прерывания


0

0

помогите студенту дописать драйвер :)

дошел до обработки прерываний, нужно по прерыванию запускать пользовательский поток. Че-то написал, но куски кода ниже не работают... :(

///////////////////////////////////////////////////////////////
static void my_wait_irq(int n_dev)
{
u32* LPCI_4C = (u32*) (my_device_table.DeviceInfo[n_dev].MemBase[0]+0x4C);
*LPCI_4C |= 0x49; // разблокировать прерывания на карточке
printk(KERN_ERR "wait for interrupt...\n", n_dev);
interruptible_sleep_on(&my_queue);
}

static void my_int_handler(int irq, void *dev_id, struct pt_regs *regs)
{
u32* LPCI_4C = (u32*)(((my_device_info_t*)dev_id)->MemBase[0]+0x4C);

if(*LPCI_4C & 0x24) {
*LPCI_4C &= ~0x40; // блокируем прерывания на карте
printk(KERN_ERR "interrupt %d seems to be catched!!! :)\n", irq);
wake_up_interruptible(&my_queue);
}
}

static int my_request_irq(int dev_no)
{
char name[sizeof("mydev00") + 1];
int ret, irq;

irq = my_device_table.DeviceInfo[dev_no].IRQ;

sprintf(name, "mydev%d", dev_no);
ret = request_irq(irq, my_int_handler, SA_SHIRQ, name, &my_device_table.DeviceInfo[dev_no]);

if(ret) {
printk(KERN_ERR "%s failed to allocate irq %d\n", name, irq);
};

return ret;
}

static int my_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
.......
switch(cmd) {
.......
case MY_IOCTL_WAIT_IRQ:
my_wait_irq(n_dev);
break;
.......
return -EINVAL;
};

return ret;
}
///////////////////////////////////////////////////////////////

в юзеровской программе я посылаю MY_IOCTL_WAIT_IRQ и, по плану, после того, как упраление вернется, стоит вызов "обработчика". Но управление не возвращается... %(

помогите, плз :)

anonymous

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

> а что говорит cat /proc/interrupts? прерывания вообще приходят?

cat /proc/interrupts: ----------- CPU0 0: 1052698 XT-PIC timer CPU0 0: 1052698 XT-PIC timer 1: 3 XT-PIC keyboard 2: 0 XT-PIC cascade 5: 0 XT-PIC r!@, , , , 8: 1 XT-PIC rtc 11: 50851 XT-PIC eth0 12: 0 XT-PIC PS/2 Mouse 14: 3680 XT-PIC ide0 15: 51 XT-PIC ide1 NMI: 0 ERR: 0 ----------- странно как-то... модуль говорит, что получил именно 5-ое прерывание... может, я что-нить не заполнил?...

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

блин, это был TeX...

> а что говорит cat /proc/interrupts? прерывания вообще приходят?
CPU0
0: 1052698 XT-PIC timer
1: 3 XT-PIC keyboard
2: 0 XT-PIC cascade
5: 0 XT-PIC r!@, , , ,
8: 1 XT-PIC rtc
11: 50851 XT-PIC eth0
12: 0 XT-PIC PS/2 Mouse
14: 3680 XT-PIC ide0
15: 51 XT-PIC ide1
NMI: 0
ERR: 0

мне выдается именно 5-ое прерывание...

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

чему будет равно name после выхода из dev_request_irq? если хотите решить свою проблему приводите весь код. Трудно сказать где вы еще накосячили

anonymous
()

> my_device_table.DeviceInfo[n_dev].MemBase[0]

Как получил ?

> irq = my_device_table.DeviceInfo[dev_no].IRQ;
> et = request_irq(irq,...

Надо делать 
static struct pci_dev *pdev[MAX_MOD];
Инициализируешь её....
................
et = request_irq(pdev[n]->irq,...

Ещё, возможно, прерывание нужно разрешить и для PCI-устройства (регистр в его адресном пространстве), а не только для контроллера (кстати какой? PLX ?)

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

> чему будет равно name после выхода из dev_request_irq?
а я че-то решил, что request_irq копирует себе эту строчку... %)

а код (411 строчек) сюда не влазит... :(
но могу на почту выслать :)

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

>> my_device_table.DeviceInfo[n_dev].MemBase[0] > Как получил ? ------------------ for (reg = 0; reg < 6; reg++) { struct resource *res = dev->resource + reg; unsigned long base, end;

if (!(res->flags & PCI_BASE_ADDRESS_SPACE_IO)) { base = res->start; end = res->end; if (!end) continue; device->MemBase[n] = base; device->MemSize[n] = end - base + 1; device->LinBase[n] = 0; n++; } }

device->NumMemWindows = n; device->IRQ = dev->irq;

pci_enable_device(dev); ------------------ от сюда и вылазит потом "irq = my_device_table.DeviceInfo[dev_no].IRQ"

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

опять с форматированием налажал....

>> my_device_table.DeviceInfo[n_dev].MemBase[0]
> Как получил ?
------------------
	for (reg = 0; reg < 6; reg++) {
		struct resource *res = dev->resource + reg;
		unsigned long base, end;

		if (!(res->flags & PCI_BASE_ADDRESS_SPACE_IO)) {
			base = res->start;
			end = res->end;
			if (!end)
				continue;
			device->MemBase[n] = base;
			device->MemSize[n] = end - base + 1;
			device->LinBase[n] = 0;
			n++;
		}
	}

	device->NumMemWindows = n;
	device->IRQ = dev->irq;

	pci_enable_device(dev);
------------------
от сюда и вылазит потом "irq = my_device_table.DeviceInfo[dev_no].IRQ"

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

> от сюда и вылазит потом "irq = my_device_table.DeviceInfo[dev_no].IRQ"

Не понял, что вылазит... request_irq( должно передаваться dev->irq

> base = res->start;

Получение базового адреса контроллера сделай так:
...= pci_resource_start(dev, 0);

И учти, что смещение регистров относительно base задается в байтах. А у тебя - unsigned long base, можешь промахнуться... :)

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

> Ещё, возможно, прерывание нужно разрешить и для PCI-устройства > (регистр в его адресном пространстве), а не только для контроллера > (кстати какой? PLX ?)

да, PLX9050

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

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

нужно сначала делать pci_enable_device() а потом уже этот цикл.

лучше использовать макросы pci_resource_start()/*_end() вместо того что вы написали

желательно не забыть pci_requset_region()

и ioremap() для памяти у-ва

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

> request_irq( должно передаваться dev->irq

irq = my_device_table.DeviceInfo[dev_no].IRQ = device->IRQ = dev->irq; :)

> pci_resource_start(dev, 0)

а это, разве, не одно и то же, что и dev->resource->start...

с картированием памяти, вроде как, все в относительной норме - тесты проходит на различных машинах... а вот прерывание - ни в какую %(

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

> а вот прерывание - ни в какую %(

А из девайса прерывание точно идет ??? Кто там выставляет ПЛИС, проц ?

> а это, разве, не одно и то же, что и dev->resource->start...

Пользуйся лучше стандартным макросом...
ioremap_nocache сделал ?

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

чтобы быть увереным что если в системе появиться еще одно у-во с пересекающимися ресурсами (например регионами памяти) то оно успешно обломается и ничего нам не испортит

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

чтобы отмапить память у-ва (регистры например) на память ядра.Ведь вы потом к ним обращаетесь

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

> чтобы быть увереным что если в системе появиться еще одно у-во с > пересекающимися ресурсами (например регионами памяти) то оно > успешно обломается и ничего нам не испортит

понятно, спасибо :)

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

> чтобы отмапить память у-ва (регистры например) на память ядра.
> Ведь вы потом к ним обращаетесь

а если не мапить?.. из ядра получается "напрямую", пока маплю только в user-space в .mmap, и пока с тестами памяти и регистров все "ок"...

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

> про pci_resource_start()/*_end() ясно, почему лучше,

Для совместимости. Вдруг что-то изменится... В макросе поменяют, а ты в пролете :)

> сразу вопрос %) зачем ioremap(_nocache)? в user-space я ремаплю remap_page_range`ем...

Тогда не надо...

> u32* LPCI_4C = (u32*) (my_device_table.DeviceInfo[n_dev].MemBase[0]+0x4C); 

my_device_table.DeviceInfo[n_dev].MemBase[0] - тип какой ?
0x4C - точно ли  Interrupt Control/Status Register ? Проверь!!! Просто у меня 9056 - не думаю чтоб сильно отличались...

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

> Для совместимости. Вдруг что-то изменится... В макросе поменяют, а ты в пролете :)
:))

> my_device_table.DeviceInfo[n_dev].MemBase[0] - тип какой ?
unsigned long

> 0x4C - точно ли  Interrupt Control/Status Register ?
да, и в 9052 так же... по-крайней мере, мой драйвер для RTX работает нормально...

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

А 0x4C - это адрес из Data Book'и ??? Ничего не менял ??? :))

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

metawishmaster _этъ_ gmail _ДОТ_ com

спасибо большое, сравню, где у меня фигня... :)

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

> 0x68 INTCSR для PLX надо перечитать прессу %) с другой стороны, почему с 0x4c все работало в RTX?... %(

> Если хошь, могу намылить код драйвера для PLX, скажи куда. metawishmaster _этъ_ gmail _ДОТ_ com

спасибо большое, сравню, где у меня фигня... :)

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

> LPCI_4C = (u32*) (my_device_table.DeviceInfo[n_dev].MemBase[0]+0x4C);

Ты думаешь, что LPCI_4C - это адрес INTCSR со смещением в 0x4C байт относительно базового ???

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

> по идее, LPCI_4C == INTCSR... как я думаю... или, уже, "думал"?.. %)

У тебя - нет! Допустим у тебя INTCSR имеет смещение 0x4C(уточни) БАЙТ! И ты к 32-битному указателю прибавляешь прибавляешь 0x4C(но уже не байт) . Какое в байтах смещение у тебя будет иметь INTCSR ?

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

исправил, но нет, ничего не работает :(
вернее, прерывания не работают. с картированием памяти все как было ок, так и осталось

с другой стороны, под RTX все отлично работало...
тут же прерывания как не приходили, так и не приходят :(

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

может её как-нибудь включить надо по особомму? (2 притопа в один регистр и три прихлопа в другой...)

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

> Что исправил ???
u32* LPCI_4C;
LPCI_4C = (u32*)((BYTE*)((mkopcilnx_device_info_t*)dev_id)->MemBase[0]+0x4C);

я просто не понимаю, что в этой строчке может быть не так... драйверы для 95, NT, RTX работают...

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

Прерывания для PLX разрешаю примерно так:

enum {
  .....
  pciINTCSR   = 0x68,
  .....
}

struct dev {
   ----------
   u32            m_PlxMemory;   // PLX memory range information
   ----------
} device;

//--------------------------------------------------------------------
//
// PLX Memory Acesses
//
u32 ReadPlxMem32 ( void *m_pAddress, u32 offset )
{
    return ioread32 ( ( u32 * ) ( ( u8 * ) m_pAddress + offset ) );
}

//--------------------------------------------------------------------
//
void WritePlxMem32 ( void *m_pAddress, u32 offset, u32 value )
{
    iowrite32 ( value, ( u32 * ) ( ( u8 * ) m_pAddress + offset ) );
}

//--------------------------------------------------------------------
//
device *pdx = xxxx;

//--------------------------------------------------------------------
//
//где-то в проге :) необходимо установить биты PCI Interrupt enable 
//бит 9(название могу не помнить точно) и тип прервания (локальное)
//бит какой-то там...


intcsr = ReadPlxMem32( (void*)pdx->m_PlxMemory, pciINTCSR );
intcsr |= 0x900;
WritePlxMem32( (void*)pdx->m_PlxMemory, pciINTCSR, intcsr );

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

> LPCI_4C = (u32*)((BYTE*)((mkopcilnx_device_info_t*)dev_id)->MemBase[0]+0x4C);
Блин... Сделай так:

LPCI_4C = (u32*)(...MemBase[0]+(0x4C<<2));
либо 
LPCI_4C = (u32*)(((char*)...MemBase[0])+0x4C);

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

>> LPCI_4C = (u32*)((BYTE*)((mkopcilnx_device_info_t*)dev_id)->MemBase[0]+0x4C);
> Блин... Сделай так:

> LPCI_4C = (u32*)(...MemBase[0]+(0x4C<<2));
> либо 
> LPCI_4C = (u32*)(((char*)...MemBase[0])+0x4C);

у меня в заголовке прописано "typedef char BYTE;"
все равно...

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

1) Попробуй прочитать по тем адресам (через память или порты) параметры устройства, которые известны наверняка, скажем DEVICE_ID/VENDOR_ID регистр, чтобы убедиться что правильно отмаппировано устройство.

2) Если у тебя какое-то устройство, то кроме того, что разрешить прервания в регистрах контроллера PLX, их необходимо разрешить еще в регистрах устройства.

3) Попробуй сгенерить прерывание при записи в mailbox-register, например.

Больше помочь не чем... :)

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

> сделал - то жк самое... :(

Попробуй примерно так:

pci_enable_device(dev);
base_f = pci_resource_start(dev, 0);
base_v = (unsigned int*)ioremap_nocache(base_f, SIZE);
.....................
writel(0x900,   base_v +(P9X5X_INTCSR<<2));

Всё это сделай в драйвере.

И второе:

Ты уверен, что у тебя от девайса прерывания идут ??? Кто выставляет ???

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

> из приложения через запись в регистры

Как получил базовый адрес регистров устройства ??? Не контроллера !!!

Ты printk (KERN_ALERT.......) ставишь для отладки??? Уверен что команды ioctl() дходят ??? Номер прерывания (dev->irq) в студию :)

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

> Как получил базовый адрес регистров устройства ???

base = pci_resource_start(dev, 0)...

> Ты printk (KERN_ALERT.......) ставишь для отладки???

printk(KERN_ERR/INFO...) %)

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