Jump to content

    
Sign in to follow this  
AVR

Cyclone 4 GX PCI-E - задать несколько векторов MSI

Recommended Posts

У ядер PCI-E Xilinx можно задать число векторов прерываний, например 2 4 8 и т.д., и оно вроде как видится в системе через lspci как параметр Count в строке MSI (на платформе Linux). Это позволяет иметь несколько обработчиков прерываний от 1 устройства.

 

У Altera/Intel при добавлении ядра коллеги не могут найти как включить больше векторов прерываний чем 1. Есть линия app_msi_num которая имеет разрядность 5, значит число векторов может быть до 2^5 = 32. Также известно что в пакете MSI прилетит это в виде некоторого 5-разрядного поля.

 

Но вот с удивлением обнаружили - а на стороне Linux драйвер как должен искать это всё? Пришли к выводу что надо чтобы для начала lspci увидел что у устройства более чем 1 вектор прерывания, чтобы как минимум в драйвере можно было повесить обработчики на IRQ+0 +1 +2 +3 и так далее.

 

Суть проблемы, вопрос: Как включить на Cyclone 4 GX PCI-E ядре больше чем 1 вектор прерывания? Пока коллеги нашли порт CRA в котором надеются найти нужное поле, в котором выставят желаемое значение, а затем уже и я на стороне драйвера смогу повесить туда обработчики прерывания и благодаря app_msi_num мне будет прилетать в разные обработчики.

 

P.S. Документация говорит что может быть до 16 векторов для Cyclone 4 GX.

Share this post


Link to post
Share on other sites
1 hour ago, AVR said:

Но вот с удивлением обнаружили - а на стороне Linux драйвер как должен искать это всё?

Примерно так:
 

static unsigned int nvecs[] = { 1, 2, 4, 8, 16, 32, 1, 1 };

// Setting up interrupt handler
	pdata->nvec = pci_alloc_irq_vectors(pdev,1,
		nvecs[(regval >> 4) & 0x7],
		PCI_IRQ_MSI);
	if(pdata->nvec < 0)
		dev_err(&pdev->dev,"Unable to allocate interrupt vectors");
	else {
		dev_info(&pdev->dev,"MSI Vectors: %d",pdata->nvec);
		for(i = 0; i < pdata->nvec; i++) {
			vn = pci_irq_vector(pdev,i);
			ret = request_irq(vn,pf_isr,IRQF_SHARED,
				pci_name(pdev),pdev);
			if(ret < 0)
				dev_err(&pdev->dev,
						"Unable to register irq %d",vn);
		}
	}

// ISR
irqreturn_t pf_isr(int irq, void *dev_id)
{
	struct pci_dev *pdev = (struct pci_dev *)dev_id;
	struct pf_data *pdata = pci_get_drvdata(pdev);
	int nirq = irq - pdata->pdev->irq;
... 

в nirq при этом - номер MSI-прерывания, которое произошло

Share this post


Link to post
Share on other sites
On 10/23/2021 at 6:49 PM, gosha-z said:

в nirq при этом - номер MSI-прерывания, которое произошло

Благодарю за ответ. Проверили. pci_alloc_irq_vectors выдает -28 (-ENOSPC). If less than min_vecs interrupt vectors are available for dev the function will fail with -ENOSPC.

Capabilities: [50] MSI: Enable- Count=1/1 Maskable- 64bit+

Мне кажется, у нас само устройство не может позволить выделить больше векторов. И это требуется как то настроить, ведь lspci просто декодирует состояние configs space. В нем похоже не настроено число прерываний, ведь это Count должно быть 1/4 1/8 или даже 1/16. Или я ошибаюсь?

        pci_set_master(device->pci);
        dev_info(&device->pci->dev, "master set\n");

        rc = pci_enable_msi(device->pci);
        if(rc < 0)
        {
                dev_err(&device->pci->dev, "MSI failed\n");
                goto failed_msi;
        }

        device->nvec = pci_alloc_irq_vectors(device->pci, 1, 4, PCI_IRQ_MSI);
        if(device->nvec < 0)
        {
                dev_err(&device->pci->dev, "ERROR: IRQ vectors failed %d\n", device->nvec);
                goto failed_irq;
        }
        else
        {
                for(i = 0; i < device->nvec; i++)
                {
                        vn = pci_irq_vector(device->pci, i);
                        rc = request_irq(vn, mypci_isr, IRQF_SHARED, pci_name(device->pci), device->pci);
                        if(rc < 0) dev_err(&device->pci->dev, "ERROR: unable to register irq %d", vn);
                }
        }

 

Share this post


Link to post
Share on other sites
2 hours ago, gosha-z said:

Именно, это должно настраиваться в корке.

Сделали так:

rc = pci_bus_read_config_dword(device->pci->bus, 0, 0x00, &word32);
dev_info(&device->pci->dev, "config 0x00= 0x%08X\n", word32);
rc = pci_bus_read_config_word(device->pci->bus, 0, 0x52, &word16);
dev_info(&device->pci->dev, "config A 0x52= 0x%04X\n", word16);
rc = pci_bus_write_config_word(device->pci->bus, 0, 0x52, 0x00DB);
rc = pci_bus_read_config_word(device->pci->bus, 0, 0x52, &word16);
dev_info(&device->pci->dev, "config B 0x52= 0x%04X\n", word16);

Получили:

config A 0x52= 0x0081
config B 0x52= 0x00D1

Стало Capabilities: [50] MSI: Enable- Count=32/1 Maskable- 64bit+ т.е. Count=32. Однако, MSI Capabilities MSI messages requested гласит "The Qsys design flow supports only 1 MSI". Означает ли это, что у нас нет шансов выставить например чтобы стало Count=32/32 работая через Qsys? Или это можно как то объехать, записывая через порт CRA значение на стороне устройства? А может можно еще где то задать?

 

Если нет то нет, просто тогда не будем использовать эту возможность, придется обойти иначе эту проблему, варианты имеются.

 

Добавлено: Выяснили что у Cyclone 5 есть настройка в Qsys чтобы выставлять сколько угодно векторов. В целевом устройстве будет уже Cyclone 5, поэтому наверное проблема решена. А сейчас временно Cyclone 4, поэтому это ограничение не критично.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this