summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorStephen Rothwell <sfr@canb.auug.org.au>2010-08-05 12:43:11 +1000
committerStephen Rothwell <sfr@canb.auug.org.au>2010-08-05 12:43:11 +1000
commit63a7dc5f560c1d854f85ddca8bbf081b84dd62f3 (patch)
tree555c978f8afd06c5352aa3ac2e5c8692c3b815e2 /include
parent5f5a8dd5c28d54e35a79dd4f96eb83513a30b2d5 (diff)
parentfa7cd37f808c487f722d7a2ce9c0923a323922df (diff)
Merge remote branch 'lost-spurious-irq/lost-spurious-irq'
Conflicts: drivers/ata/sata_fsl.c drivers/ata/sata_mv.c drivers/ata/sata_nv.c
Diffstat (limited to 'include')
-rw-r--r--include/linux/interrupt.h43
-rw-r--r--include/linux/irq.h40
-rw-r--r--include/linux/libata.h2
3 files changed, 63 insertions, 22 deletions
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index a0384a4d1e6f..76a1192c14be 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -47,9 +47,6 @@
* IRQF_TIMER - Flag to mark this interrupt as timer interrupt
* IRQF_PERCPU - Interrupt is per cpu
* IRQF_NOBALANCING - Flag to exclude this interrupt from irq balancing
- * IRQF_IRQPOLL - Interrupt is used for polling (only the interrupt that is
- * registered first in an shared interrupt is considered for
- * performance reasons)
* IRQF_ONESHOT - Interrupt is not reenabled after the hardirq handler finished.
* Used by threaded interrupts which need to keep the
* irq line disabled until the threaded handler has been run.
@@ -63,7 +60,6 @@
#define __IRQF_TIMER 0x00000200
#define IRQF_PERCPU 0x00000400
#define IRQF_NOBALANCING 0x00000800
-#define IRQF_IRQPOLL 0x00001000
#define IRQF_ONESHOT 0x00002000
#define IRQF_NO_SUSPEND 0x00004000
@@ -97,6 +93,16 @@ enum {
typedef irqreturn_t (*irq_handler_t)(int, void *);
+struct irq_expect;
+
+struct irq_watch {
+ irqreturn_t last_ret;
+ unsigned int flags;
+ unsigned long started;
+ unsigned int nr_samples;
+ unsigned int nr_polled;
+};
+
/**
* struct irqaction - per interrupt action descriptor
* @handler: interrupt handler function
@@ -109,18 +115,22 @@ typedef irqreturn_t (*irq_handler_t)(int, void *);
* @thread_fn: interupt handler function for threaded interrupts
* @thread: thread pointer for threaded interrupts
* @thread_flags: flags related to @thread
+ * @watch: data for irq watching
+ * @expects: data for irq expecting
*/
struct irqaction {
- irq_handler_t handler;
- unsigned long flags;
- const char *name;
- void *dev_id;
- struct irqaction *next;
- int irq;
- struct proc_dir_entry *dir;
- irq_handler_t thread_fn;
- struct task_struct *thread;
- unsigned long thread_flags;
+ irq_handler_t handler;
+ unsigned long flags;
+ const char *name;
+ void *dev_id;
+ struct irqaction *next;
+ int irq;
+ struct proc_dir_entry *dir;
+ irq_handler_t thread_fn;
+ struct task_struct *thread;
+ unsigned long thread_flags;
+ struct irq_watch watch;
+ struct irq_expect *expects;
};
extern irqreturn_t no_action(int cpl, void *dev_id);
@@ -193,6 +203,11 @@ devm_request_irq(struct device *dev, unsigned int irq, irq_handler_t handler,
extern void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id);
+extern struct irq_expect *init_irq_expect(unsigned int irq, void *dev_id);
+extern void expect_irq(struct irq_expect *exp);
+extern void unexpect_irq(struct irq_expect *exp, bool timedout);
+extern void watch_irq(unsigned int irq, void *dev_id);
+
/*
* On lockdep we dont want to enable hardirqs in hardirq
* context. Use local_irq_enable_in_hardirq() to annotate
diff --git a/include/linux/irq.h b/include/linux/irq.h
index c03243ad84b4..98530ef9068e 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -21,6 +21,7 @@
#include <linux/irqreturn.h>
#include <linux/irqnr.h>
#include <linux/errno.h>
+#include <linux/timer.h>
#include <linux/topology.h>
#include <linux/wait.h>
@@ -71,6 +72,8 @@ typedef void (*irq_flow_handler_t)(unsigned int irq,
#define IRQ_SUSPENDED 0x04000000 /* IRQ has gone through suspend sequence */
#define IRQ_ONESHOT 0x08000000 /* IRQ is not unmasked after hardirq */
#define IRQ_NESTED_THREAD 0x10000000 /* IRQ is nested into another, no own handler thread */
+#define IRQ_IN_POLLING 0x20000000 /* IRQ polling in progress */
+#define IRQ_CHECK_WATCHES 0x40000000 /* IRQ watch enabled */
#ifdef CONFIG_IRQ_PER_CPU
# define CHECK_IRQ_PER_CPU(var) ((var) & IRQ_PER_CPU)
@@ -144,6 +147,17 @@ struct irq_chip {
struct timer_rand_state;
struct irq_2_iommu;
+
+/* spurious IRQ tracking and handling */
+struct irq_spr {
+ unsigned long last_bad; /* when was the last bad? */
+ unsigned long period_start; /* period start jiffies */
+ unsigned int nr_samples; /* nr of irqs in this period */
+ unsigned int nr_bad; /* nr of bad deliveries */
+ unsigned int poll_cnt; /* nr to poll once activated */
+ unsigned int poll_rem; /* how many polls are left? */
+};
+
/**
* struct irq_desc - interrupt descriptor
* @irq: interrupt number for this descriptor
@@ -160,15 +174,14 @@ struct irq_2_iommu;
* @status: status information
* @depth: disable-depth, for nested irq_disable() calls
* @wake_depth: enable depth, for multiple set_irq_wake() callers
- * @irq_count: stats field to detect stalled irqs
- * @last_unhandled: aging timer for unhandled count
- * @irqs_unhandled: stats field for spurious unhandled interrupts
* @lock: locking for SMP
* @affinity: IRQ affinity on SMP
* @node: node index useful for balancing
* @pending_mask: pending rebalanced interrupts
* @threads_active: number of irqaction threads currently running
* @wait_for_threads: wait queue for sync_irq to wait for threaded handlers
+ * @spr: data for spurious IRQ handling
+ * @poll_timer: timer for IRQ polling
* @dir: /proc/irq/ procfs entry
* @name: flow handler name for /proc/interrupts output
*/
@@ -189,9 +202,6 @@ struct irq_desc {
unsigned int depth; /* nested irq disables */
unsigned int wake_depth; /* nested wake enables */
- unsigned int irq_count; /* For detecting broken IRQs */
- unsigned long last_unhandled; /* Aging timer for unhandled count */
- unsigned int irqs_unhandled;
raw_spinlock_t lock;
#ifdef CONFIG_SMP
cpumask_var_t affinity;
@@ -203,6 +213,11 @@ struct irq_desc {
#endif
atomic_t threads_active;
wait_queue_head_t wait_for_threads;
+
+ struct irq_spr spr;
+ struct timer_list poll_timer;
+ bool poll_warned;
+
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *dir;
#endif
@@ -324,8 +339,17 @@ static inline void generic_handle_irq(unsigned int irq)
}
/* Handling of unhandled and spurious interrupts: */
-extern void note_interrupt(unsigned int irq, struct irq_desc *desc,
- irqreturn_t action_ret);
+extern void __note_interrupt(unsigned int irq, struct irq_desc *desc,
+ irqreturn_t action_ret);
+
+static inline void note_interrupt(unsigned int irq, struct irq_desc *desc,
+ irqreturn_t action_ret)
+{
+ extern int noirqdebug;
+
+ if (!noirqdebug)
+ __note_interrupt(irq, desc, action_ret);
+}
/* Resending of interrupts :*/
void check_irq_resend(struct irq_desc *desc, unsigned int irq);
diff --git a/include/linux/libata.h b/include/linux/libata.h
index b85f3ff34d7d..3f5f159c8e62 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -751,6 +751,8 @@ struct ata_port {
struct ata_host *host;
struct device *dev;
+ struct irq_expect *irq_expect; /* for irq expecting */
+
struct delayed_work hotplug_task;
struct work_struct scsi_rescan_task;