blob: cfdb63eb5c9450c288e7c76836e39cebf398d3b8 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/kernel/irq/autoprobe.c
3 *
4 * Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar
5 *
6 * This file contains the interrupt probing code and driver APIs.
7 */
8
9#include <linux/irq.h>
10#include <linux/module.h>
11#include <linux/interrupt.h>
Luca Falavigna47f176f2005-06-28 20:44:42 -070012#include <linux/delay.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013
14/*
15 * Autodetection depends on the fact that any interrupt that
16 * comes in on to an unassigned handler will get stuck with
17 * "IRQ_WAITING" cleared and the interrupt disabled.
18 */
Ingo Molnar74ffd552006-06-29 02:24:37 -070019static DEFINE_MUTEX(probing_active);
Linus Torvalds1da177e2005-04-16 15:20:36 -070020
21/**
22 * probe_irq_on - begin an interrupt autodetect
23 *
24 * Commence probing for an interrupt. The interrupts are scanned
25 * and a mask of potential interrupt lines is returned.
26 *
27 */
28unsigned long probe_irq_on(void)
29{
Ingo Molnar34ffdb72006-06-29 02:24:40 -070030 struct irq_desc *desc;
Ingo Molnar06fcb0c2006-06-29 02:24:40 -070031 unsigned long mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -070032 unsigned int i;
33
Ingo Molnar74ffd552006-06-29 02:24:37 -070034 mutex_lock(&probing_active);
Linus Torvalds1da177e2005-04-16 15:20:36 -070035 /*
36 * something may have generated an irq long ago and we want to
37 * flush such a longstanding irq before considering it as spurious.
38 */
39 for (i = NR_IRQS-1; i > 0; i--) {
40 desc = irq_desc + i;
41
42 spin_lock_irq(&desc->lock);
Thomas Gleixner6a6de9e2006-06-29 02:24:51 -070043 if (!desc->action && !(desc->status & IRQ_NOPROBE)) {
44 /*
45 * Some chips need to know about probing in
46 * progress:
47 */
48 if (desc->chip->set_type)
49 desc->chip->set_type(i, IRQ_TYPE_PROBE);
Ingo Molnar06fcb0c2006-06-29 02:24:40 -070050 desc->chip->startup(i);
Thomas Gleixner6a6de9e2006-06-29 02:24:51 -070051 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070052 spin_unlock_irq(&desc->lock);
53 }
54
55 /* Wait for longstanding interrupts to trigger. */
Luca Falavigna47f176f2005-06-28 20:44:42 -070056 msleep(20);
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
58 /*
59 * enable any unassigned irqs
60 * (we must startup again here because if a longstanding irq
61 * happened in the previous stage, it may have masked itself)
62 */
63 for (i = NR_IRQS-1; i > 0; i--) {
64 desc = irq_desc + i;
65
66 spin_lock_irq(&desc->lock);
Thomas Gleixner3418d722006-06-29 02:24:49 -070067 if (!desc->action && !(desc->status & IRQ_NOPROBE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070068 desc->status |= IRQ_AUTODETECT | IRQ_WAITING;
Ingo Molnard1bef4e2006-06-29 02:24:36 -070069 if (desc->chip->startup(i))
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 desc->status |= IRQ_PENDING;
71 }
72 spin_unlock_irq(&desc->lock);
73 }
74
75 /*
76 * Wait for spurious interrupts to trigger
77 */
Luca Falavigna47f176f2005-06-28 20:44:42 -070078 msleep(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
80 /*
81 * Now filter out any obviously spurious interrupts
82 */
Ingo Molnar06fcb0c2006-06-29 02:24:40 -070083 mask = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 for (i = 0; i < NR_IRQS; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070085 unsigned int status;
86
Ingo Molnar06fcb0c2006-06-29 02:24:40 -070087 desc = irq_desc + i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070088 spin_lock_irq(&desc->lock);
89 status = desc->status;
90
91 if (status & IRQ_AUTODETECT) {
92 /* It triggered already - consider it spurious. */
93 if (!(status & IRQ_WAITING)) {
94 desc->status = status & ~IRQ_AUTODETECT;
Ingo Molnard1bef4e2006-06-29 02:24:36 -070095 desc->chip->shutdown(i);
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 } else
97 if (i < 32)
Ingo Molnar06fcb0c2006-06-29 02:24:40 -070098 mask |= 1 << i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 }
100 spin_unlock_irq(&desc->lock);
101 }
102
Ingo Molnar06fcb0c2006-06-29 02:24:40 -0700103 return mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105EXPORT_SYMBOL(probe_irq_on);
106
107/**
108 * probe_irq_mask - scan a bitmap of interrupt lines
109 * @val: mask of interrupts to consider
110 *
111 * Scan the interrupt lines and return a bitmap of active
112 * autodetect interrupts. The interrupt probe logic state
113 * is then returned to its previous value.
114 *
115 * Note: we need to scan all the irq's even though we will
116 * only return autodetect irq numbers - just so that we reset
117 * them all to a known state.
118 */
119unsigned int probe_irq_mask(unsigned long val)
120{
121 unsigned int mask;
122 int i;
123
124 mask = 0;
125 for (i = 0; i < NR_IRQS; i++) {
Ingo Molnar34ffdb72006-06-29 02:24:40 -0700126 struct irq_desc *desc = irq_desc + i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 unsigned int status;
128
129 spin_lock_irq(&desc->lock);
130 status = desc->status;
131
132 if (status & IRQ_AUTODETECT) {
133 if (i < 16 && !(status & IRQ_WAITING))
134 mask |= 1 << i;
135
136 desc->status = status & ~IRQ_AUTODETECT;
Ingo Molnard1bef4e2006-06-29 02:24:36 -0700137 desc->chip->shutdown(i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 }
139 spin_unlock_irq(&desc->lock);
140 }
Ingo Molnar74ffd552006-06-29 02:24:37 -0700141 mutex_unlock(&probing_active);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142
143 return mask & val;
144}
145EXPORT_SYMBOL(probe_irq_mask);
146
147/**
148 * probe_irq_off - end an interrupt autodetect
149 * @val: mask of potential interrupts (unused)
150 *
151 * Scans the unused interrupt lines and returns the line which
152 * appears to have triggered the interrupt. If no interrupt was
153 * found then zero is returned. If more than one interrupt is
154 * found then minus the first candidate is returned to indicate
155 * their is doubt.
156 *
157 * The interrupt probe logic state is returned to its previous
158 * value.
159 *
160 * BUGS: When used in a module (which arguably shouldn't happen)
161 * nothing prevents two IRQ probe callers from overlapping. The
162 * results of this are non-optimal.
163 */
164int probe_irq_off(unsigned long val)
165{
166 int i, irq_found = 0, nr_irqs = 0;
167
168 for (i = 0; i < NR_IRQS; i++) {
Ingo Molnar34ffdb72006-06-29 02:24:40 -0700169 struct irq_desc *desc = irq_desc + i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 unsigned int status;
171
172 spin_lock_irq(&desc->lock);
173 status = desc->status;
174
175 if (status & IRQ_AUTODETECT) {
176 if (!(status & IRQ_WAITING)) {
177 if (!nr_irqs)
178 irq_found = i;
179 nr_irqs++;
180 }
181 desc->status = status & ~IRQ_AUTODETECT;
Ingo Molnard1bef4e2006-06-29 02:24:36 -0700182 desc->chip->shutdown(i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 }
184 spin_unlock_irq(&desc->lock);
185 }
Ingo Molnar74ffd552006-06-29 02:24:37 -0700186 mutex_unlock(&probing_active);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187
188 if (nr_irqs > 1)
189 irq_found = -irq_found;
Ingo Molnar74ffd552006-06-29 02:24:37 -0700190
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 return irq_found;
192}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193EXPORT_SYMBOL(probe_irq_off);
194