Programmable Devices
CPLDs, FPGAs, SoC FPGAs, Configuration, and Transceivers
21396 Discussions

How to request multiply MSI interrupts?

Altera_Forum
Honored Contributor II
8,728 Views

Hi !!! 

 

Developing a network device driver on Arria2 GX (Avalon-ST). 

Is it possible to set a vector of 8 MSI interrupts , if the design supports only MSI interrupts, not MSI - X? 

 

From the side of device driver developer - to request 8 separate interrupt handlers, to handle 8 packet queues. 

 

pci_enable_msi_block() returns 1.This means, that it's possible to request only 1 interrupt line. 

 

The capabilities of device: 

 

Capabilities: [78] Power Management version 3 

Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot-,D3cold-) 

Status: D0 PME-Enable- DSel=0 DScale=0 PME- 

Capabilities: [80] Express (v1) Endpoint, MSI 00 

DevCap: MaxPayload 256 bytes, PhantFunc 0, Latency L0s <64ns, L1 <1us 

ExtTag- AttnBtn- AttnInd- PwrInd- RBE+ FLReset- 

DevCtl: Report errors: Correctable- Non-Fatal- Fatal- Unsupported- 

RlxdOrd+ ExtTag- PhantFunc- AuxPwr- NoSnoop+ 

MaxPayload 128 bytes, MaxReadReq 512 bytes 

DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr- TransPend- 

LnkCap: Port# 1, Speed 2.5GT/s, Width x4, ASPM L0s, Latency L0 unlimited, L1 unlimited 

ClockPM- Suprise- LLActRep- BwNot- 

LnkCtl: ASPM Disabled; RCB 64 bytes Disabled- Retrain- CommClk+ 

ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt- 

LnkSta: Speed 2.5GT/s, Width x4, TrErr- Train- SlotClk+ DLActive- BWMgmt- ABWMgmt- 

 

Developing under Linux. 

 

Best Regards,  

Igor
0 Kudos
39 Replies
Altera_Forum
Honored Contributor II
3,024 Views

Here an overview on my module 

 

# include <linux/module.h> /* Allg. Modul Informationen */# include <linux/pci.h> /* PCI Funktionen */# include <linux/msi.h># include <linux/interrupt.h># include <asm/io.h> # ifndef CONFIG_PCI# error "This driver needs PCI support to be available"# endif /* Hersteller- und Geraetekennung */# define PCI_VENDOR_ID_LATTICE 0x1204# define PCI_DEVICE_ID_LATTICE_PCI 0xEC30 /* Name/Kennung fuer die PCI-Karte */# define LATTICE_PCI_NAME "LATTICE_pci" /* Register Offsets */# define LATTICE_INTR_REG_ADDR 0x100 ////////////////////////////////# define DMA_BUFFER_SIZE (64 * 1024) size_t dmaBufSize; /**< size in bytes of the allocated kernel buffer */ dma_addr_t dmaPCIBusAddr; /**< PCI bus address to access the DMA buffer - program into board */ void *dmaCPUAddr; /**< CPU (software) address to access the DMA buffer - use in driver */ //////////////////////////////// ////////////////////////////////# define msi_ID 0x01 //uint32_t msi_test; //uint32_t msi_addr, msi_data; uint32_t msi_ctrl, msi_data, msi_address_hi, msi_address_lo, msi_capability; /* Alle geraetespezifischen Variablen werden in einer Struktur */ /* zusammengefasst. */ struct { /* Zeiger auf das Software-Objekt */ struct pci_dev *pci_dev; /* Zeiger auf die virtuelle Basisadresse */ void *virt_addr; /* Physikalische Adresse */ unsigned long phys_addr; /* Adressraum (Umfang) */ unsigned long size; /* Interrupt */ u8 intr_line; } LATTICE_pci_dev; /* Interrupt Handler */ irq_handler_t LATTICE_pci_intr_handler (int irq, void *dev_id, struct pt_regs *regs) { unsigned long intr_flag; /* Lese Interrupt-Flag, um zu pruefen, ob das LATTICE PCI-Board ueberhaupt */ /* Quelle des Interrupts ist. (Moeglicherweise Shared Interrupt!) */ intr_flag = readl (LATTICE_pci_dev.virt_addr + LATTICE_INTR_REG_ADDR) & 1; if (intr_flag) ; /* Kein Interrupt durch das LATTICE PCI-Board */ /* Hier beginnt die eigentliche Interrupt-Bearbeitung... */ { printk ("LATTICE PCI-Board: Interrupt!\n"); return (irq_handler_t) IRQ_HANDLED; } return (irq_handler_t) IRQ_NONE; } /* Aufraeumen, wird bei 'rmmod' aufgerufen */ void cleanup_module(void) { /* Speicherbereich freigeben */ iounmap (LATTICE_pci_dev.virt_addr); release_mem_region (LATTICE_pci_dev.phys_addr, LATTICE_pci_dev.size); free_irq (LATTICE_pci_dev.intr_line, &LATTICE_pci_dev); pci_disable_msi(LATTICE_pci_dev.pci_dev); } /* Modul-Initialisierung, wird bei 'insmod' aufgerufen */ int init_module (void) { int result; //u8 intr_pin; LATTICE_pci_dev.pci_dev = NULL; LATTICE_pci_dev.intr_line = 0; /* Gibt es ueberhaupt PCI Geraete? */ /* (wird eigentlich durch die folgenden Funktionen schon abgedeckt) */ /* if (!pci_present ()) { printk ("LATTICE PCI-Board: no pci-devices found.\n"); result = -ENODEV; goto exit0; }*/ /* Ist das LATTICE Board eingebaut? */ LATTICE_pci_dev.pci_dev = pci_find_device (PCI_VENDOR_ID_LATTICE, PCI_DEVICE_ID_LATTICE_PCI, LATTICE_pci_dev.pci_dev); if (LATTICE_pci_dev.pci_dev == NULL) { printk ("LATTICE PCI-Board: card not present\n"); result = -EIO; goto exit0; } /* Aufwecken des PCI-Geraetes */ if (pci_enable_device (LATTICE_pci_dev.pci_dev)) { printk ("LATTICE PCI-Board: unable to enable card\n"); result = -EIO; goto exit0; } LATTICE_pci_dev.phys_addr = pci_resource_start (LATTICE_pci_dev.pci_dev, 0); LATTICE_pci_dev.size = pci_resource_len (LATTICE_pci_dev.pci_dev, 0); /* Belegen des I/O-Speichers */ if (!request_mem_region (LATTICE_pci_dev.phys_addr, LATTICE_pci_dev.size, LATTICE_PCI_NAME)) { printk ("LATTICE PCI-Board: request_mem_region (0x%lx) failed\n", LATTICE_pci_dev.phys_addr); result = -EBUSY; goto exit0; } LATTICE_pci_dev.virt_addr = ioremap (LATTICE_pci_dev.phys_addr, LATTICE_pci_dev.size); /* Untersuchen, ob die PCI-Karte ueber Interrupt-Funktion verfuegt */ /* (Register "Interrupt Pin" im PCI Configration Header) */ //pci_read_config_byte (LATTICE_pci_dev.pci_dev, PCI_INTERRUPT_PIN, &intr_pin); //if (intr_pin == 0) //{ // printk ("LATTICE PCI-Board: device doesn't support interrupts.\n"); // result = -EIO; //goto exit1; //} /* Lesen der in der Konfigurationsphse zugewiesenen IRQ-Nummer */ /* (Register "Interrupt Line" im PCI Configuration Header */ pci_read_config_byte (LATTICE_pci_dev.pci_dev, PCI_INTERRUPT_LINE, &LATTICE_pci_dev.intr_line); ///////////////////////////////////////////////////////////////////////////////////////////////// msi_data = 0x4100 |msi_ID; msi_address_hi= 0x0; msi_address_lo= 0x03; //================ DMA Common Buffer (Consistent) Allocation ==================== // First see if platform supports 32 bit DMA address cycles (like what won't!) if (pci_set_dma_mask(LATTICE_pci_dev.pci_dev, DMA_32BIT_MASK)) { printk(KERN_WARNING "lattice_pci: init DMA not supported!\n"); //pBrd->hasDMA = FALSE; } else { //pBrd->hasDMA = TRUE; printk(KERN_WARNING "lattice_pci: init DMA supported!\n"); dmaBufSize = DMA_BUFFER_SIZE; dmaCPUAddr = pci_alloc_consistent(LATTICE_pci_dev.pci_dev, dmaBufSize, &dmaPCIBusAddr); if (dmaCPUAddr == NULL) { printk(KERN_WARNING "lattice_pci: init DMA alloc failed! No DMA buffer.\n"); //pBrd->hasDMA = FALSE; } else { printk(KERN_WARNING "lattice_pci: init DMA alloc passed! DMA buffer.\n"); printk(KERN_INFO "lattice_pci: write msi_Data=%0x\n", msi_data); } } /////////////////////////////////////////////////////////////////////////////////////////////////// pci_write_config_dword(LATTICE_pci_dev.pci_dev, 0x73,msi_address_hi); pci_write_config_dword(LATTICE_pci_dev.pci_dev, 0x77,msi_address_lo); pci_write_config_dword(LATTICE_pci_dev.pci_dev, 0x7B,0x4100); //////////////////// pci_read_config_dword(LATTICE_pci_dev.pci_dev, 0x70,&msi_capability); pci_read_config_dword(LATTICE_pci_dev.pci_dev, 0x73,&msi_address_hi); pci_read_config_dword(LATTICE_pci_dev.pci_dev, 0x77,&msi_address_lo); pci_read_config_dword(LATTICE_pci_dev.pci_dev, 0x7B,&msi_data); /////////////////// printk(KERN_INFO "lattice_pci: Config space: MSI Capability =%0x\n", msi_capability); printk(KERN_INFO "lattice_pci: Config space: Adress High =%0x\n", msi_address_hi); printk(KERN_INFO "lattice_pci: Config space: Address Low =%0x\n", msi_address_lo); printk(KERN_INFO "lattice_pci: Config space: Data Register =%0x\n", msi_data); printk(KERN_INFO "lattice_pci: Config space Data =%0x\n", msi_data); //msi_data = 0x4100 |msi_ID; // msiaddr= 0 //u32 msi_data; /* Enable the MSI interrupts */ if(pci_enable_msi(LATTICE_pci_dev.pci_dev)){ printk("LATTICE PCI-Board: unable to enable MSI\n"); result = -1; goto msicleanup; } printk("LATTICE PCI-Board: MSI Enable \n"); /* Interrupt-Handler registrieren */ if (request_irq (LATTICE_pci_dev.intr_line,(irq_handler_t)LATTICE_pci_intr_handler, IRQF_DISABLED, LATTICE_PCI_NAME, &LATTICE_pci_dev)) { printk ("LATTICE PCI-Board: can't get assigned IRQ %d.\n", LATTICE_pci_dev.intr_line); result = -EIO; goto exit1; } /* Benutzer informieren */ printk("LATTICE PCI-Board: pci-card found at address 0x%lx, IRQ %d\n", LATTICE_pci_dev.phys_addr, LATTICE_pci_dev.intr_line); return 0; exit1: iounmap (LATTICE_pci_dev.virt_addr); release_mem_region (LATTICE_pci_dev.phys_addr, LATTICE_pci_dev.size); msicleanup: /* Disable the MSI interrupts */ pci_disable_msi(LATTICE_pci_dev.pci_dev); exit0: return result; }
0 Kudos
Altera_Forum
Honored Contributor II
3,024 Views

First try pci_enable_msi(dev). You don't need any patch, if you want 1 interrupt line.  

Than requst_irq(dev->irq). 

 

 

--- Quote Start ---  

if (request_irq (LATTICE_pci_dev.pci_dev->irq,(irq_handler_t)LATTICE_pci_intr_handler, IRQF_SHARED, LATTICE_PCI_NAME, &LATTICE_pci_dev)) 

--- Quote End ---  

 

 

Try this.
0 Kudos
Altera_Forum
Honored Contributor II
3,024 Views

Hi, 

 

What patch files for my fedora 12 (kernel 2.6.31.5) in order to add the API function pci_enable_msi_block() to allow my driver to request multiple MSI because the main goal of my project is to implemented 8 MSI.
0 Kudos
Altera_Forum
Honored Contributor II
3,024 Views

Hi 

 

The patch in attachment. 

 

Regards,  

Igor
(Virus scan in progress ...)
0 Kudos
Altera_Forum
Honored Contributor II
3,024 Views

Hi, 

 

Thanks for the patch file. but I couldn't executed it and got the following output: 

# patch -p0 -i 0001-Add-support-for-multiple-MSI-on-x86.patch (Stripping trailing CRs from patch.) can't find file to patch at input line 12 Perhaps you used the wrong -p or --strip option? The text leading up to this was: -------------------------- |--- | arch/x86/kernel/apic/io_apic.c | 310 ++++++++++++++++++++++++++++++++++------ | arch/x86/kernel/hpet.c | 2 +- | drivers/pci/htirq.c | 2 +- | include/linux/irq.h | 3 +- | 4 files changed, 271 insertions(+), 46 deletions(-) | |diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c |index fadcd74..5e9decc 100644 |--- a/arch/x86/kernel/apic/io_apic.c |+++ b/arch/x86/kernel/apic/io_apic.c Line 12 @@ -249,11 +249,6 @@ static struct irq_cfg *alloc_irq_and_cfg_at(unsigned int at, int node) -------------------------- File to patch:
0 Kudos
Altera_Forum
Honored Contributor II
3,024 Views

I had similar errors. So I patched the kernel, directly modifying the kernel sources. Than recompiling it.

0 Kudos
Altera_Forum
Honored Contributor II
3,024 Views

Please can I get the right revision or originale files which the patch was written for 

Because I got the following errors with my fedora 12 

 

# patch -p1 < 0001-Add-support-for-multiple-MSI-on-x86.patch (Stripping trailing CRs from patch.) patching file arch/x86/kernel/apic/io_apic.c Hunk# 1 FAILED at 249. Hunk# 2 succeeded at 1260 with fuzz 1 (offset 228 lines). Hunk# 3 FAILED at 1373. Hunk# 4 FAILED at 2553. Hunk# 5 FAILED at 3426. Hunk# 6 FAILED at 3436. Hunk# 7 FAILED at 3472. Hunk# 8 FAILED at 3500. Hunk# 9 FAILED at 3510. Hunk# 10 FAILED at 3689. Hunk# 11 FAILED at 3797. Hunk# 12 FAILED at 3805. Hunk# 13 FAILED at 3817. Hunk# 14 FAILED at 3889. Hunk# 15 FAILED at 3967. 14 out of 15 hunks FAILED -- saving rejects to file arch/x86/kernel/apic/io_apic.c.rej (Stripping trailing CRs from patch.) patching file arch/x86/kernel/hpet.c Hunk# 1 FAILED at 499. 1 out of 1 hunk FAILED -- saving rejects to file arch/x86/kernel/hpet.c.rej (Stripping trailing CRs from patch.) patching file drivers/pci/htirq.c Hunk# 1 succeeded at 127 (offset 7 lines). (Stripping trailing CRs from patch.) patching file include/linux/irq.h Hunk# 1 succeeded at 383 with fuzz 1 (offset 61 lines).
0 Kudos
Altera_Forum
Honored Contributor II
3,024 Views

I used this patch with kernel ~ 2.6.30. Maybe newer kernels are not supported.

0 Kudos
Altera_Forum
Honored Contributor II
3,024 Views

Hi,  

 

I finally get patching the patch file manually and recompile sucessfully with fedora 15(kernel 2.6.38.6) and not kernel 2.6.30 

 

So Now could you please give me an overview how the simple driver with the pci_msi_config_block() function should looks like. specially relating to the Interrupt and Interrupt service routine.I just want to do a simple test before moving forward.
0 Kudos
Altera_Forum
Honored Contributor II
3,024 Views

Hi, 

 

I finally get patching the patch file manually and recompile  

sucessfully with fedora 15(kernel 2.6.38.6) and not kernel 2.6.30 

 

So Now could you please give me an overview how the simple driver  

with the pci_msi_config_block() function should looks like. 

specially relating to the Interrupt and Interrupt service routine. 

I just want to do a simple test before moving forward.
0 Kudos
Altera_Forum
Honored Contributor II
3,024 Views

1. pci_enable_msi_block(). Will return irq numbers. 

 

2. request_irq . Pass irq numbers, which returned by pci_enable_msi_block(). 

 

3. Check your interrupts . cat /proc/interrupts. 

 

In your irq handler , printk irq number, which you receive. 

 

Regards,  

Igor
0 Kudos
Altera_Forum
Honored Contributor II
3,024 Views

Hi, 

 

I finally get it with severals MSIs. 

Just take a look below: 

 

#dmesg pci 0000:04:00.0: irq 47-48 for MSI/MSI-X # cat /proc/interrupts CPU0 0: 49252 IO-APIC-edge timer 1: 2 IO-APIC-edge i8042 ........ 5: 0 IO-APIC-edge parport0 8: 1 IO-APIC-edge rtc0 46: 9454 PCI-MSI-edge eth1 47: 0 PCI-MSI-edge LATTICE_pci  

 

Let's say 47 is my CAN 

and 48 is my UART 

 

Question 1 May I need to request twice as you sa if (request_irq (47,(irq_handler_t) irqreturn_CAN_isr, IRQF_DISABLED, LATTICE_PCI_NAME, &LATTICE_pci_dev)) if (request_irq (48,(irq_handler_t)irqreturn_UART_isr, IRQF_DISABLED, LATTICE_PCI_NAME, &LATTICE_pci_dev)) --------------------Interrupt Handlers--------------------------------- static irqreturn_CAN_isr ( 47, void *dev ) { void testCAN(); printk(KERN_DEBUG " CAN received irq = %d \n", irq); return IRQ_HANDLED; } static irqreturn_UART_isr ( int irq, void *dev ) { void testUART(); printk(KERN_DEBUG " UART received irq = %d \n", irq); return IRQ_HANDLED; }  

 

Is it OK?
0 Kudos
Altera_Forum
Honored Contributor II
3,024 Views

Hi, 

 

I have sucessfully test multiple MSI on my V6 Integrated Block Board and my concern now is: 

 

Do I need an MSI Controller to sychronise all the Interrupts source or it will be handle by the Core automatically. 

 

I would really appreciate any response in order to move forward. 

 

Regards,
0 Kudos
Altera_Forum
Honored Contributor II
3,024 Views

Hi, I need some advice for implementing MSI MaskRegister for my lattice Board which doesn't support MSI -X features(include Mask Register) I have implemented the MSI Interrupt and test it under Linux 1 months ago for my Lattice PCI Express IP Core with Wishbone interface for slaves. But now I am facing a problem to integrated a Mask register to facilitate the driver development. Below is what I have implemented . Could anybody give me a feedback to make sure I am on the rigth way? Notice: Lattice ECP3 just support up to 8 MSI Interrupts. module msi_maskregister( clk_i, rst_i, cyc_i, stb_i, adr_i, we_i, dat_i, dat_o, ack_o, msi ); parameter is = 8; // Number of interrupt sources // // Inputs & outputs // // 8bit WISHBONE bus slave interface input clk_i; // clock input rst_i; // reset (asynchronous active low) input cyc_i; // cycle input stb_i; // strobe (cycle and strobe are the same signal) input [ 2:1] adr_i; // address input we_i; // write enable input [ 7:0] dat_i; // data output output [ 7:0] dat_o; // data input output ack_o; // normal bus termination // Interrupt sources input [is:1] msi; // interrupt request inputs // // Module body // reg [is:1] pol, edgen, mask; // register bank reg [is:1] lirq, dirq; // latched irqs, delayed latched irqs // // latch interrupt inputs always @(posedge clk_i) lirq <=# 1 msi; // // generate delayed latched irqs always @(posedge clk_i) dirq <=# 1 lirq; // // generate actual triggers function trigger; input edgen, pol, lirq, dirq; reg edge_irq, level_irq; begin edge_irq = pol ? (lirq & ~dirq) : (dirq & ~lirq); ///////// Masking level_irq = pol ? lirq : ~lirq; trigger = edgen ? edge_irq : level_irq; end endfunction reg [is:1] irq_event; integer n; always @(posedge clk_i) for(n=1; n<=is; n=n+1) irq_event[n] <=# 1 trigger(edgen[n], pol[n], lirq[n], dirq[n]); // // generate wishbone register bank writes wire wb_acc = cyc_i & stb_i; // WISHBONE access wire wb_wr = wb_acc & we_i; // WISHBONE write access always @(posedge clk_i or negedge rst_i) if (~rst_i) begin pol <=# 1 {{is}{1'b0}}; // clear polarity register edgen <=# 1 {{is}{1'b0}}; // clear edge enable register mask <=# 1 {{is}{1'b1}}; // mask all interrupts end // 0x00: EdgeEnable Register // 0x01: PolarityRegister // 0x02: MaskRegister else if(wb_wr) // wishbone write cycle?? case (adr_i) // synopsys full_case parallel_case 2'b00: edgen <=# 1 dat_i[is-1:0]; // EDGE-ENABLE register 2'b01: pol <=# 1 dat_i[is-1:0]; // POLARITY register 2'b10: mask <=# 1 dat_i[is-1:0]; // MASK register endcase // // generate dat_o reg [7:0] dat_o; always @(posedge clk_i) case (adr_i) // synopsys full_case parallel_case 2'b00: dat_o <=# 1 { {{8-is}{1'b0}}, edgen}; //{ {{8-is}{1'b0}}, edgen} 2'b01: dat_o <=# 1 { {{8-is}{1'b0}}, pol}; 2'b10: dat_o <=# 1 { {{8-is}{1'b0}}, mask}; endcase // // generate ack_o reg ack_o; always @(posedge clk_i) ack_o <=# 1 wb_acc & !ack_o; endmodule

0 Kudos
Altera_Forum
Honored Contributor II
3,024 Views

Hi, I need some advice for implementing MSI MaskRegister for my lattice Board which doesn't support MSI -X features(include Mask Register) I have implemented the MSI Interrupt and test it under Linux 1 months ago for my Lattice PCI Express IP Core with Wishbone interface for slaves. But now I am facing a problem to integrated a Mask register to facilitate the driver development. Below is what I have implemented . Could anybody give me a feedback to make sure I am on the rigth way? Notice: Lattice ECP3 just support up to 8 MSI Interrupts. 

module msi_maskregister( clk_i, rst_i, cyc_i, stb_i, adr_i, we_i, dat_i, dat_o, ack_o, msi ); parameter is = 8; // Number of interrupt sources // // Inputs & outputs // // 8bit WISHBONE bus slave interface input clk_i; // clock input rst_i; // reset (asynchronous active low) input cyc_i; // cycle input stb_i; // strobe (cycle and strobe are the same signal) input adr_i; // address input we_i; // write enable input dat_i; // data output output dat_o; // data input output ack_o; // normal bus termination // Interrupt sources input msi; // interrupt request inputs // // Module body // reg pol, edgen, mask; // register bank reg lirq, dirq; // latched irqs, delayed latched irqs // // latch interrupt inputs always @(posedge clk_i) lirq <=# 1 msi; // // generate delayed latched irqs always @(posedge clk_i) dirq <=# 1 lirq; // // generate actual triggers function trigger; input edgen, pol, lirq, dirq; reg edge_irq, level_irq; begin edge_irq = pol ? (lirq & ~dirq) : (dirq & ~lirq); ///////// Masking level_irq = pol ? lirq : ~lirq; trigger = edgen ? edge_irq : level_irq; end endfunction reg irq_event; integer n; always @(posedge clk_i) for(n=1; n<=is; n=n+1) irq_event <=# 1 trigger(edgen, pol, lirq, dirq); // // generate wishbone register bank writes wire wb_acc = cyc_i & stb_i; // WISHBONE access wire wb_wr = wb_acc & we_i; // WISHBONE write access always @(posedge clk_i or negedge rst_i) if (~rst_i) begin pol <=# 1 {{is}{1'b0}}; // clear polarity register edgen <=# 1 {{is}{1'b0}}; // clear edge enable register mask <=# 1 {{is}{1'b1}}; // mask all interrupts end // 0x00: EdgeEnable Register // 0x01: PolarityRegister // 0x02: MaskRegister else if(wb_wr) // wishbone write cycle?? case (adr_i) // synopsys full_case parallel_case 2'b00: edgen <=# 1 dat_i; // EDGE-ENABLE register 2'b01: pol <=# 1 dat_i; // POLARITY register 2'b10: mask <=# 1 dat_i; // MASK register endcase // // generate dat_o reg dat_o; always @(posedge clk_i) case (adr_i) // synopsys full_case parallel_case 2'b00: dat_o <=# 1 { {{8-is}{1'b0}}, edgen}; //{ {{8-is}{1'b0}}, edgen} 2'b01: dat_o <=# 1 { {{8-is}{1'b0}}, pol}; 2'b10: dat_o <=# 1 { {{8-is}{1'b0}}, mask}; endcase // // generate ack_o reg ack_o; always @(posedge clk_i) ack_o <=# 1 wb_acc & !ack_o; endmodule
0 Kudos
Altera_Forum
Honored Contributor II
3,024 Views

Did you achive to impelement multiple MSI interrupts using Cyclone IV GX?  

 

I am using IP_COMPILER_FOR_PCI_EXPRESS in Qsys but there is not a feature that enables multiple MSI interrupts. As i read in the manual, it is able to produce only one interrupt and the separation of the interrupts is able by reading the Interrupt Status Register.  

 

So, is it able to be done? If yes, what should I check?  

 

Thanks a lot.
0 Kudos
Altera_Forum
Honored Contributor II
3,024 Views

Hello, 

 

I'm not sure if anyone is still watching this post.  

I'm working on enabling mutiple MSIs for my PCIe card and it has been the most useful information I got so far!! 

When I try to manully apply the patch to my kenel, there's some incompatibility, like functions or variables not declared. 

What is the distribution you use to apply this patch on?  

Any information would be greatly appreciated!! 

 

Best Regards,
0 Kudos
Altera_Forum
Honored Contributor II
3,024 Views

Hi alterahenry, 

 

I am working on X86 PCIe Linux Driver to implement MSI-X Interrupt on Cycleon V FPGA board with reference design taken from Qsys. 

 

I have followed below steps in linux driver to enable MSI-X interrupt. 

 

1) Enabled PCIe Device 

 

2) Executed pci_enable_msix with total number of 4 vectors which is successfully enabled without any fail-case. 

 

3) After that, Disable Legacy Interrupt by setting 0 to 10th bit of PCI_COMMAND Configuration Space Register. 

 

4) Enabled DMA Mask Bit of PCI Cnfiguration (PCI_Command) Register. 

 

5) After that, Request IRQ based on getting vector value of MSIX Entries which allocated successfully without any issue. 

 

6) Than, I have triggered IRQ by writing data into IRQ source which writes some data into TXS Port but not getting interrupt event. 

 

Please find below sample code for more information. 

 

 

status = pci_enable_msix(dev, msix_entries, nr_entries); 

 

pci_read_config_dword(dev, PCI_COMMAND, &temp); 

pci_write_config_dword(dev, PCI_COMMAND, (temp & 0xFFFFFBFF)); /// To Disble Legacy Interrupt (set 0 to 10th bit) 

pci_read_config_dword(dev, PCI_COMMAND, &temp); 

 

/* Enable DMA Mask Bit of PCI Cnfiguration (PCI_Command) Register */ 

if (dma_set_mask(&(dev->dev), DMA_BIT_MASK(32)))  

dev_err(&dev->dev," No suitable DMA available for 32 Bit.\n"); 

else 

printk(KERN_INFO " Set 32 Bit DMA Mask Successfully...\n"); 

 

if (dma_set_mask(&(dev->dev), DMA_BIT_MASK(64)))  

dev_err(&dev->dev," No suitable DMA available.\n"); 

else 

printk(KERN_INFO " Set 64 Bit DMA Mask Successfully...\n");  

 

pci_set_master(dev); 

 

 

dev->irq = msix_entries[0].vector; 

 

 

if (request_irq(dev->irq, sls_sdhc_irq, 0, DRV_NAME, (void*)dev))  

printk(KERN_ERR "Error allocating interrupt.\n"); 

else 

printk(KERN_ERR "Interrupt allocated successfully.\n"); 

 

 

So, All above settings are configured successfully without any issue but I am no getting print from interrupt handler. so, it seems that interrupt is not generated yet. 

 

Please let me know if you have any solution or any idea for this type of issue. 

 

Regards, 

Ritesh Prajapati
0 Kudos
Altera_Forum
Honored Contributor II
3,024 Views

Hi, 

 

Can you please help me to understand how to enable multiple MSI Interrupts? 

In Qsys, if we select Number of MSI messages requested as 4, then will it support 4 different MSI interrupts? 

 

Also please share if anyone have Host software application to enable multiple MSI interrupts. 

Iam using Arria10 FPGA 

 

Regards 

Linus_alt
0 Kudos
Reply