diff options
author | Stephen Rothwell <sfr@canb.auug.org.au> | 2010-08-05 12:43:11 +1000 |
---|---|---|
committer | Stephen Rothwell <sfr@canb.auug.org.au> | 2010-08-05 12:43:11 +1000 |
commit | 63a7dc5f560c1d854f85ddca8bbf081b84dd62f3 (patch) | |
tree | 555c978f8afd06c5352aa3ac2e5c8692c3b815e2 /include | |
parent | 5f5a8dd5c28d54e35a79dd4f96eb83513a30b2d5 (diff) | |
parent | fa7cd37f808c487f722d7a2ce9c0923a323922df (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.h | 43 | ||||
-rw-r--r-- | include/linux/irq.h | 40 | ||||
-rw-r--r-- | include/linux/libata.h | 2 |
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; |