MSI interrupt handler on Linux

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

MSI interrupt handler on Linux

11,917 Views
masasi
Contributor II

Hi! I am new to the MSI and I cannot find how to call an interrupt handler function when a MSI transaction is received on my P1012 processor. In my code a new MSI transaction arrives to the RC, the MSIIR register is updated and that causes the MSIR7 register of the PIC to set the interrupt 0 bit. Then, how can I call my interrupt_handler function when the that interrupt arrives? I thought I should use the irq_create_mapping and request_irq Linux functions but I do not know how to link the hwirq with my interrupt. Thanks in advance!

0 Kudos
6 Replies

5,080 Views
wooosaiiii
Contributor III

Hello,

I have this setup:

( iMX6Q Linux RC ) <-----PCIe-----> (iMX6Q Bare-Metal EP)

I am able to enable and generate MSI interrupts from EP to RC.

In Linux driver for EP device I use:

pci_enable_msi(priv->pci_dev);

which allocated "one" MSI vector.

But if I try to use:

ret = pci_enable_msi_range(priv->pci_dev, 1, 32);

I always get return value = 1 which actually means I get only one vector even though I request 32.

Does kernel actually support multiple vectors on iMX6 platform?

If it does how to enable them...? Any examples would be welcome...

Thanks

Primoz

0 Kudos

5,080 Views
yipingwang
NXP TechSupport
NXP TechSupport

Hello masasi,

Please use the function pci_enable_msi to set up the MSI capability for the device.

int pci_enable_msi(struct pci_dev *dev)

A successful call allocates ONE interrupt to the device, regardless of how many MSIs the device supports.  The device is switched from pin-based interrupt mode to MSI mode.  The dev->irq number is changed to a new number which represents the message signaled interrupt; consequently, this function should be called before the driver calls request_irq(), because an MSI is delivered via a vector that is different from the vector of a pin-based interrupt.

Please refer to the document Documentation/PCI/MSI-HOWTO.txt for details, and refer to sample code drivers/net/ethernet/intel/e1000e/netdev.c.

The interrupt number is set at the mpic init, its value is determined by the register "Shared Message Signaled Interrupt Vector/Priority Register (MSIVPRs)".

The msi node is defined here:

Documentation/devicetree/bindings/powerpc/fsl/msi-pic.txt

Related code:

arch/powerpc/sysdev/fsl_msi.c

Please refer to the following example.

interrupts : each one of the interrupts here is one entry per 32 MSIs, and routed to the host interrupt controller. the interrupts should be set as edge sensitive.  If msi-available-ranges is present, only the interrupts that correspond to available ranges shall be present.

The interrupt number "e0, e1, ..." is calculated from the offset address of the register "Shared Message Signaled Interrupt Vector/Priority Register(MSIVPRs)".

msi@41600 {

        compatible = "fsl,mpic-msi";

        reg = <0x41600 0x80>;

        msi-available-ranges = <0 0x100>;

        interrupts = <

                0xe0 0 0 0

                0xe1 0 0 0

                0xe2 0 0 0

                0xe3 0 0 0

                0xe4 0 0 0

                0xe5 0 0 0

                0xe6 0 0 0

                0xe7 0 0 0>;

};


Have a great day,
Yiping

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos

2,083 Views
gauthamkrishnan_r
Contributor II
Do we have to enable MSI capability on the Root Complex side to receive and service the MSI generated by Endpoint?
0 Kudos

5,081 Views
masasi
Contributor II

Thank you for your response!

I have tried to follow your indications and I have succeed on enabling the MSI mode without errors but once I register my interrupt handler by means of the dev->irq the pci_enable_msi function provided, my interrupt handler keeps getting called forever (and I am not sending any MSI interrupt). Maybe I have a problem with my PIC configuration?

As I want to send an MSI interrupt to MSIR7 interrupt 0, I have configured my device tree as follows:

msi@41600 {

compatible = "fsl,mpic-msi";

reg = <0x00041600 0x00000080>;
msi-available-ranges = <0x00000000 0x00000100>;
interrupts = <<br /> 0xe0 0
0xe1 0
0xe2 0
0xe3 0
0xe4 0
0xe5 0
0xe6 0
0xe7 0>;
};

Then the kernel driver probe function is in charge of enabling MSI mode and register the interrupt handler, no errors appear during the initialization but once I execute the request_irq function, the interrupt handler (pcie_irq) gets called in an infinite loop.
Also, I have not assigned any values to the MSIVPR registers. Do I have to configure them? Can I just configure an arbitrary value for the vector?
static int pm2_pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
{
int rc;
static int probe_count =0;
rc = pci_enable_device(dev);
if(rc){
printk("pci_enable_device() failed\n");
}
pci_set_master(dev);
if(pci_enable_msi(dev)){
printk("Failed to enable MSI\n");
}
else{
/* init wait queues */
init_waitqueue_head(dev->tx_waiters_list);
init_waitqueue_head(dev->rx_waiters_list);

/* register the interrupt handler */
dev->virq = irq_create_mapping(NULL, dev->irq);
if (dev->virq == NO_IRQ)
{
printk(KERN_WARNING "%s: irq_create_mapping failed for irq %x\n",
dev->name, (unsigned int) dev->irq);
}
else
{
rv = request_irq(dev->virq, pcie_irq, 0, dev->name, (void*)dev);
if (rv)
{
printk(KERN_WARNING "%s: Unable to get virtual IRQ %d (returned %d)\n",
dev->name, dev->virq, rv);

}

}

}

return 0;

}

De: yipingwang

Enviado el: jueves, 10 de diciembre de 2015 10:19

Para: Saiz Munoz, Maria

Asunto: Re: - MSI interrupt handler on Linux

<http://jiveon.jivesoftware.com/mpss/c/-AA/PDcDAA/t.1su/wKAPx555RDWmWqxn9DqV9w/h0/eqhG5v9o4WV1pCmWaB03cUjBPgRj-2F3GoJUaXSZ409bQ-3D>

MSI interrupt handler on Linux

reply from Yiping Wang<http://jiveon.jivesoftware.com/mpss/c/-AA/PDcDAA/t.1su/wKAPx555RDWmWqxn9DqV9w/h1/eqhG5v9o4WV1pCmWaB03cUjBPgRj-2F3GoJUaXSZ409bTuunTxDnqsgk6MvTmPNW-2BIbsMPeMV32yFxUPb-2BtQiSPGCG8wrrcaln-2FLLwVRV4WnU-3D> in QorIQ Processors - View the full discussion<http://jiveon.jivesoftware.com/mpss/c/-AA/PDcDAA/t.1su/wKAPx555RDWmWqxn9DqV9w/h2/eqhG5v9o4WV1pCmWaB03cUjBPgRj-2F3GoJUaXSZ409bTgWB1b2z4ZrP8AafTv60SMl5nL9tq2DiKXsdql-2FAAJPZdwvwbRSXLuF66Uu0Pqn2w-3D>

0 Kudos

5,081 Views
scottwood
NXP Employee
NXP Employee

Why do you care which MSI gets used?  Linux allocates this for you.

Do not pass dev->irq to irq_create_mapping().  It is already a virtual IRQ number.

Also, don't use NO_IRQ.  The virtual IRQ number that means there is no IRQ is zero.

0 Kudos

5,081 Views
yipingwang
NXP TechSupport
NXP TechSupport

Hello masasi,

When EP’s MSI Message reaches the RC, such MSI Message is actually a memory write pointing to some particular bit(s) in the MSIIR register, which indirectly caused a write to a pre-defined bit in a selected MSIRn register to be set. This will then trigger the interrupt.


In addition, please refer to the function e1000_test_msi_interrupt in drivers/net/ethernet/intel/e1000e/netdev.c for MSI interrupt handling process.


Have a great day,
Yiping

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos