From c095f06560a0efacc7a34ea4e7f1e69c1faab0cf Mon Sep 17 00:00:00 2001 From: "Suren A. Chilingaryan" Date: Mon, 11 Jul 2011 01:37:54 +0200 Subject: IRQ support in NWL DMA engine --- driver/common.h | 2 +- driver/config.h | 2 +- driver/int.c | 71 +++++++++++++----------------------------------------- driver/ioctl.c | 26 +++++++++++++++----- driver/pciDriver.h | 9 +++++-- 5 files changed, 46 insertions(+), 64 deletions(-) (limited to 'driver') diff --git a/driver/common.h b/driver/common.h index 6036b0c..3bc27d8 100644 --- a/driver/common.h +++ b/driver/common.h @@ -60,7 +60,7 @@ typedef struct { struct list_head umem_list; /* List of 'umem_list_entry's associated with this device */ atomic_t umem_count; /* id for next umem entry */ - + int msi_mode; } pcidriver_privdata_t; diff --git a/driver/config.h b/driver/config.h index a2b6946..c217afd 100644 --- a/driver/config.h +++ b/driver/config.h @@ -3,7 +3,7 @@ /*******************************/ /* Debug messages */ -#define DEBUG +//#define DEBUG /* Enable/disable IRQ handling */ #define ENABLE_IRQ diff --git a/driver/int.c b/driver/int.c index 285aa0e..5dbcb7f 100644 --- a/driver/int.c +++ b/driver/int.c @@ -162,6 +162,10 @@ int pcidriver_probe_irq(pcidriver_privdata_t *privdata) return 0; } + /* Enable interrupts using MSI mode */ + if (!pci_enable_msi(privdata->pdev)) + privdata->msi_mode = 1; + /* register interrupt handler */ if ((err = request_irq(privdata->pdev->irq, pcidriver_irq_handler, MODNAME, privdata)) != 0) { mod_info("Error registering the interrupt handler. Disabling interrupts for this device\n"); @@ -184,6 +188,11 @@ void pcidriver_remove_irq(pcidriver_privdata_t *privdata) /* Release the IRQ handler */ if (privdata->irq_enabled != 0) free_irq(privdata->pdev->irq, privdata); + + if (privdata->msi_mode) { + pci_disable_msi(privdata->pdev); + privdata->msi_mode = 0; + } pcidriver_irq_unmap_bars(privdata); } @@ -206,29 +215,6 @@ void pcidriver_irq_unmap_bars(pcidriver_privdata_t *privdata) } } -/** - * - * Acknowledge the interrupt by ACKing the interrupt generator. - * - * @returns true if the channel was acknowledged and the interrupt handler is done - * - */ -static bool check_acknowlegde_channel(pcidriver_privdata_t *privdata, int interrupt, - int channel, volatile unsigned int *bar) -{ - if (!(bar[ABB_INT_STAT] & interrupt)) - return false; - - bar[ABB_INT_ENABLE] &= !interrupt; - if (interrupt == ABB_INT_IG) - bar[ABB_IG_CTRL] = ABB_IG_ACK; - - /* Wake up the waiting loop in ioctl.c:ioctl_wait_interrupt() */ - atomic_inc(&(privdata->irq_outstanding[channel])); - wake_up_interruptible(&(privdata->irq_queues[channel])); - return true; -} - /** * * Acknowledges the receival of an interrupt to the card. @@ -241,38 +227,15 @@ static bool check_acknowlegde_channel(pcidriver_privdata_t *privdata, int interr */ static bool pcidriver_irq_acknowledge(pcidriver_privdata_t *privdata) { - volatile unsigned int *bar; + int channel = 0; +// volatile unsigned int *bar; +// bar = privdata->bars_kmapped[0]; +// mod_info_dbg("interrupt registers. ISR: %x, IER: %x\n", bar[ABB_INT_STAT], bar[ABB_INT_ENABLE]); - /* TODO: add subvendor / subsystem ids */ - /* FIXME: guillermo: which ones? all? */ - - /* Test if we have to handle this interrupt */ - return false; // The device is not supported any more - - /* Acknowledge the device */ - /* this is for ABB / wenxue DMA engine */ - bar = privdata->bars_kmapped[0]; - - mod_info_dbg("interrupt registers. ISR: %x, IER: %x\n", bar[ABB_INT_STAT], bar[ABB_INT_ENABLE]); - - if (check_acknowlegde_channel(privdata, ABB_INT_CH0, ABB_IRQ_CH0, bar)) - return true; - - if (check_acknowlegde_channel(privdata, ABB_INT_CH1, ABB_IRQ_CH1, bar)) - return true; - - if (check_acknowlegde_channel(privdata, ABB_INT_IG, ABB_IRQ_IG, bar)) - return true; - - if (check_acknowlegde_channel(privdata, ABB_INT_CH0_TIMEOUT, ABB_IRQ_CH0, bar)) - return true; - - if (check_acknowlegde_channel(privdata, ABB_INT_CH1_TIMEOUT, ABB_IRQ_CH1, bar)) - return true; - - mod_info_dbg("err: interrupt registers. ISR: %x, IER: %x\n", bar[ ABB_INT_STAT ], bar[ ABB_INT_ENABLE ] ); - - return false; + atomic_inc(&(privdata->irq_outstanding[channel])); + wake_up_interruptible(&(privdata->irq_queues[channel])); + + return true; } /** diff --git a/driver/ioctl.c b/driver/ioctl.c index 64985e8..0059833 100644 --- a/driver/ioctl.c +++ b/driver/ioctl.c @@ -335,18 +335,23 @@ static int ioctl_umem_sync(pcidriver_privdata_t *privdata, unsigned long arg) static int ioctl_wait_interrupt(pcidriver_privdata_t *privdata, unsigned long arg) { #ifdef ENABLE_IRQ + int ret; + unsigned long timeout; unsigned int irq_source; - int temp; + unsigned long temp = 0; - if (arg >= PCIDRIVER_INT_MAXSOURCES) + READ_FROM_USER(interrupt_wait_t, irq_handle); + + irq_source = irq_handle.source; + + if (irq_source >= PCIDRIVER_INT_MAXSOURCES) return -EFAULT; /* User tried to overrun the IRQ_SOURCES array */ - irq_source = arg; + timeout = jiffies + (irq_handle.timeout * HZ / 1000000); /* Thanks to Joern for the correction and tips! */ /* done this way to avoid wrong behaviour (endless loop) of the compiler in AMD platforms */ - temp=1; - while (temp) { + do { /* We wait here with an interruptible timeout. This will be interrupted * by int.c:check_acknowledge_channel() as soon as in interrupt for * the specified source arrives. */ @@ -355,8 +360,17 @@ static int ioctl_wait_interrupt(pcidriver_privdata_t *privdata, unsigned long ar if (atomic_add_negative( -1, &(privdata->irq_outstanding[irq_source])) ) atomic_inc( &(privdata->irq_outstanding[irq_source]) ); else - temp =0; + temp = 1; + } while ((!temp)&&(jiffies < timeout)); + + if ((temp)&&(irq_handle.count)) { + while (!atomic_add_negative( -1, &(privdata->irq_outstanding[irq_source]))) temp++; + atomic_inc( &(privdata->irq_outstanding[irq_source]) ); } + + irq_handle.count = temp; + + WRITE_TO_USER(interrupt_wait_t, irq_handle); return 0; #else diff --git a/driver/pciDriver.h b/driver/pciDriver.h index 94c98e7..2704ab5 100644 --- a/driver/pciDriver.h +++ b/driver/pciDriver.h @@ -64,8 +64,8 @@ #define PCIE_ML605_DEVICE_ID 0x04a0 /* Identifies the PCI-E IPE Camera */ -#define PCIE_IPECAMERA_DEVICE_ID 0x6081 -//#define PCIE_IPECAMERA_DEVICE_ID 0x6018 +//#define PCIE_IPECAMERA_DEVICE_ID 0x6081 +#define PCIE_IPECAMERA_DEVICE_ID 0x6018 /* Possible values for ioctl commands */ @@ -133,6 +133,11 @@ typedef struct { int dir; } kmem_sync_t; +typedef struct { + unsigned long count; + unsigned long timeout; // microseconds + unsigned int source; +} interrupt_wait_t; typedef struct { int size; -- cgit v1.2.3