Blame view
kernel/irq/autoprobe.c
4.57 KB
b24413180 License cleanup: ... |
1 |
// SPDX-License-Identifier: GPL-2.0 |
1da177e4c Linux-2.6.12-rc2 |
2 3 4 5 6 7 8 9 10 11 12 |
/* * linux/kernel/irq/autoprobe.c * * Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar * * This file contains the interrupt probing code and driver APIs. */ #include <linux/irq.h> #include <linux/module.h> #include <linux/interrupt.h> |
47f176fda [PATCH] Using msl... |
13 |
#include <linux/delay.h> |
22a9d6456 async: Asynchrono... |
14 |
#include <linux/async.h> |
1da177e4c Linux-2.6.12-rc2 |
15 |
|
7a55713ab [PATCH] genirq: a... |
16 |
#include "internals.h" |
1da177e4c Linux-2.6.12-rc2 |
17 18 19 |
/* * Autodetection depends on the fact that any interrupt that * comes in on to an unassigned handler will get stuck with |
163ef3091 genirq: Move IRQ_... |
20 |
* "IRQS_WAITING" cleared and the interrupt disabled. |
1da177e4c Linux-2.6.12-rc2 |
21 |
*/ |
74ffd553a [PATCH] genirq: s... |
22 |
static DEFINE_MUTEX(probing_active); |
1da177e4c Linux-2.6.12-rc2 |
23 24 25 26 27 28 29 30 31 32 |
/** * probe_irq_on - begin an interrupt autodetect * * Commence probing for an interrupt. The interrupts are scanned * and a mask of potential interrupt lines is returned. * */ unsigned long probe_irq_on(void) { |
34ffdb723 [PATCH] genirq: c... |
33 |
struct irq_desc *desc; |
10e580842 genirq: use itera... |
34 |
unsigned long mask = 0; |
10e580842 genirq: use itera... |
35 |
int i; |
1da177e4c Linux-2.6.12-rc2 |
36 |
|
22a9d6456 async: Asynchrono... |
37 38 39 40 |
/* * quiesce the kernel, or at least the asynchronous portion */ async_synchronize_full(); |
74ffd553a [PATCH] genirq: s... |
41 |
mutex_lock(&probing_active); |
1da177e4c Linux-2.6.12-rc2 |
42 43 44 45 |
/* * something may have generated an irq long ago and we want to * flush such a longstanding irq before considering it as spurious. */ |
10e580842 genirq: use itera... |
46 |
for_each_irq_desc_reverse(i, desc) { |
239007b84 genirq: Convert i... |
47 |
raw_spin_lock_irq(&desc->lock); |
1ccb4e612 genirq: Wrap the ... |
48 |
if (!desc->action && irq_settings_can_probe(desc)) { |
6a6de9ef5 [PATCH] genirq: core |
49 50 51 52 |
/* * Some chips need to know about probing in * progress: */ |
b2ba2c300 genirq: Provide c... |
53 54 55 |
if (desc->irq_data.chip->irq_set_type) desc->irq_data.chip->irq_set_type(&desc->irq_data, IRQ_TYPE_PROBE); |
4cde9c6b8 genirq: Add force... |
56 |
irq_startup(desc, IRQ_NORESEND, IRQ_START_FORCE); |
6a6de9ef5 [PATCH] genirq: core |
57 |
} |
239007b84 genirq: Convert i... |
58 |
raw_spin_unlock_irq(&desc->lock); |
1da177e4c Linux-2.6.12-rc2 |
59 60 61 |
} /* Wait for longstanding interrupts to trigger. */ |
47f176fda [PATCH] Using msl... |
62 |
msleep(20); |
1da177e4c Linux-2.6.12-rc2 |
63 64 65 66 67 68 |
/* * enable any unassigned irqs * (we must startup again here because if a longstanding irq * happened in the previous stage, it may have masked itself) */ |
10e580842 genirq: use itera... |
69 |
for_each_irq_desc_reverse(i, desc) { |
239007b84 genirq: Convert i... |
70 |
raw_spin_lock_irq(&desc->lock); |
1ccb4e612 genirq: Wrap the ... |
71 |
if (!desc->action && irq_settings_can_probe(desc)) { |
163ef3091 genirq: Move IRQ_... |
72 |
desc->istate |= IRQS_AUTODETECT | IRQS_WAITING; |
4cde9c6b8 genirq: Add force... |
73 |
if (irq_startup(desc, IRQ_NORESEND, IRQ_START_FORCE)) |
2a0d6fb33 genirq: Move IRQ_... |
74 |
desc->istate |= IRQS_PENDING; |
1da177e4c Linux-2.6.12-rc2 |
75 |
} |
239007b84 genirq: Convert i... |
76 |
raw_spin_unlock_irq(&desc->lock); |
1da177e4c Linux-2.6.12-rc2 |
77 78 79 80 81 |
} /* * Wait for spurious interrupts to trigger */ |
47f176fda [PATCH] Using msl... |
82 |
msleep(100); |
1da177e4c Linux-2.6.12-rc2 |
83 84 85 86 |
/* * Now filter out any obviously spurious interrupts */ |
10e580842 genirq: use itera... |
87 |
for_each_irq_desc(i, desc) { |
239007b84 genirq: Convert i... |
88 |
raw_spin_lock_irq(&desc->lock); |
1da177e4c Linux-2.6.12-rc2 |
89 |
|
bd062e766 genirq: Move IRQ_... |
90 |
if (desc->istate & IRQS_AUTODETECT) { |
1da177e4c Linux-2.6.12-rc2 |
91 |
/* It triggered already - consider it spurious. */ |
163ef3091 genirq: Move IRQ_... |
92 |
if (!(desc->istate & IRQS_WAITING)) { |
bd062e766 genirq: Move IRQ_... |
93 |
desc->istate &= ~IRQS_AUTODETECT; |
469992386 genirq: Consolida... |
94 |
irq_shutdown(desc); |
1da177e4c Linux-2.6.12-rc2 |
95 96 |
} else if (i < 32) |
06fcb0c6f [PATCH] genirq: c... |
97 |
mask |= 1 << i; |
1da177e4c Linux-2.6.12-rc2 |
98 |
} |
239007b84 genirq: Convert i... |
99 |
raw_spin_unlock_irq(&desc->lock); |
1da177e4c Linux-2.6.12-rc2 |
100 |
} |
06fcb0c6f [PATCH] genirq: c... |
101 |
return mask; |
1da177e4c Linux-2.6.12-rc2 |
102 |
} |
1da177e4c Linux-2.6.12-rc2 |
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
EXPORT_SYMBOL(probe_irq_on); /** * probe_irq_mask - scan a bitmap of interrupt lines * @val: mask of interrupts to consider * * Scan the interrupt lines and return a bitmap of active * autodetect interrupts. The interrupt probe logic state * is then returned to its previous value. * * Note: we need to scan all the irq's even though we will * only return autodetect irq numbers - just so that we reset * them all to a known state. */ unsigned int probe_irq_mask(unsigned long val) { |
bd062e766 genirq: Move IRQ_... |
119 |
unsigned int mask = 0; |
10e580842 genirq: use itera... |
120 |
struct irq_desc *desc; |
1da177e4c Linux-2.6.12-rc2 |
121 |
int i; |
10e580842 genirq: use itera... |
122 |
for_each_irq_desc(i, desc) { |
239007b84 genirq: Convert i... |
123 |
raw_spin_lock_irq(&desc->lock); |
bd062e766 genirq: Move IRQ_... |
124 |
if (desc->istate & IRQS_AUTODETECT) { |
163ef3091 genirq: Move IRQ_... |
125 |
if (i < 16 && !(desc->istate & IRQS_WAITING)) |
1da177e4c Linux-2.6.12-rc2 |
126 |
mask |= 1 << i; |
bd062e766 genirq: Move IRQ_... |
127 |
desc->istate &= ~IRQS_AUTODETECT; |
469992386 genirq: Consolida... |
128 |
irq_shutdown(desc); |
1da177e4c Linux-2.6.12-rc2 |
129 |
} |
239007b84 genirq: Convert i... |
130 |
raw_spin_unlock_irq(&desc->lock); |
1da177e4c Linux-2.6.12-rc2 |
131 |
} |
74ffd553a [PATCH] genirq: s... |
132 |
mutex_unlock(&probing_active); |
1da177e4c Linux-2.6.12-rc2 |
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
return mask & val; } EXPORT_SYMBOL(probe_irq_mask); /** * probe_irq_off - end an interrupt autodetect * @val: mask of potential interrupts (unused) * * Scans the unused interrupt lines and returns the line which * appears to have triggered the interrupt. If no interrupt was * found then zero is returned. If more than one interrupt is * found then minus the first candidate is returned to indicate * their is doubt. * * The interrupt probe logic state is returned to its previous * value. * * BUGS: When used in a module (which arguably shouldn't happen) * nothing prevents two IRQ probe callers from overlapping. The * results of this are non-optimal. */ int probe_irq_off(unsigned long val) { |
63d659d55 genirq: fix name ... |
157 |
int i, irq_found = 0, nr_of_irqs = 0; |
10e580842 genirq: use itera... |
158 |
struct irq_desc *desc; |
1da177e4c Linux-2.6.12-rc2 |
159 |
|
10e580842 genirq: use itera... |
160 |
for_each_irq_desc(i, desc) { |
239007b84 genirq: Convert i... |
161 |
raw_spin_lock_irq(&desc->lock); |
1da177e4c Linux-2.6.12-rc2 |
162 |
|
bd062e766 genirq: Move IRQ_... |
163 |
if (desc->istate & IRQS_AUTODETECT) { |
163ef3091 genirq: Move IRQ_... |
164 |
if (!(desc->istate & IRQS_WAITING)) { |
63d659d55 genirq: fix name ... |
165 |
if (!nr_of_irqs) |
1da177e4c Linux-2.6.12-rc2 |
166 |
irq_found = i; |
63d659d55 genirq: fix name ... |
167 |
nr_of_irqs++; |
1da177e4c Linux-2.6.12-rc2 |
168 |
} |
bd062e766 genirq: Move IRQ_... |
169 |
desc->istate &= ~IRQS_AUTODETECT; |
469992386 genirq: Consolida... |
170 |
irq_shutdown(desc); |
1da177e4c Linux-2.6.12-rc2 |
171 |
} |
239007b84 genirq: Convert i... |
172 |
raw_spin_unlock_irq(&desc->lock); |
1da177e4c Linux-2.6.12-rc2 |
173 |
} |
74ffd553a [PATCH] genirq: s... |
174 |
mutex_unlock(&probing_active); |
1da177e4c Linux-2.6.12-rc2 |
175 |
|
63d659d55 genirq: fix name ... |
176 |
if (nr_of_irqs > 1) |
1da177e4c Linux-2.6.12-rc2 |
177 |
irq_found = -irq_found; |
74ffd553a [PATCH] genirq: s... |
178 |
|
1da177e4c Linux-2.6.12-rc2 |
179 180 |
return irq_found; } |
1da177e4c Linux-2.6.12-rc2 |
181 |
EXPORT_SYMBOL(probe_irq_off); |