summaryrefslogtreecommitdiffstats
path: root/driver
diff options
context:
space:
mode:
authorSuren A. Chilingaryan <csa@dside.dyndns.org>2011-07-11 01:37:54 +0200
committerSuren A. Chilingaryan <csa@dside.dyndns.org>2011-07-11 01:37:54 +0200
commitc095f06560a0efacc7a34ea4e7f1e69c1faab0cf (patch)
treec005686153325eadb3d5c97617154f0acba75fbb /driver
parent02924fc49641ca9c000054a7a540b6f1eaa0e8f8 (diff)
downloadpcitool-c095f06560a0efacc7a34ea4e7f1e69c1faab0cf.tar.gz
pcitool-c095f06560a0efacc7a34ea4e7f1e69c1faab0cf.tar.bz2
pcitool-c095f06560a0efacc7a34ea4e7f1e69c1faab0cf.tar.xz
pcitool-c095f06560a0efacc7a34ea4e7f1e69c1faab0cf.zip
IRQ support in NWL DMA engine
Diffstat (limited to 'driver')
-rw-r--r--driver/common.h2
-rw-r--r--driver/config.h2
-rw-r--r--driver/int.c71
-rw-r--r--driver/ioctl.c26
-rw-r--r--driver/pciDriver.h9
5 files changed, 46 insertions, 64 deletions
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);
}
@@ -208,29 +217,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.
*
* @returns true if the card was acknowledget
@@ -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;