Forum Discussion
Altera_Forum
Honored Contributor
15 years agoHow to request multiply MSI interrupts?
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, Igor39 Replies
- Altera_Forum
Honored Contributor
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; } - Altera_Forum
Honored Contributor
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. - Altera_Forum
Honored Contributor
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. - Altera_Forum
Honored Contributor
- Altera_Forum
Honored Contributor
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: - Altera_Forum
Honored Contributor
I had similar errors. So I patched the kernel, directly modifying the kernel sources. Than recompiling it.
- Altera_Forum
Honored Contributor
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). - Altera_Forum
Honored Contributor
I used this patch with kernel ~ 2.6.30. Maybe newer kernels are not supported.
- Altera_Forum
Honored Contributor
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. - Altera_Forum
Honored Contributor
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.