Blame view

kernel/irq/autoprobe.c 4.57 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
1da177e4c   Linus Torvalds   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   Luca Falavigna   [PATCH] Using msl...
13
  #include <linux/delay.h>
22a9d6456   Arjan van de Ven   async: Asynchrono...
14
  #include <linux/async.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15

7a55713ab   Ingo Molnar   [PATCH] genirq: a...
16
  #include "internals.h"
1da177e4c   Linus Torvalds   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   Thomas Gleixner   genirq: Move IRQ_...
20
   * "IRQS_WAITING" cleared and the interrupt disabled.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
   */
74ffd553a   Ingo Molnar   [PATCH] genirq: s...
22
  static DEFINE_MUTEX(probing_active);
1da177e4c   Linus Torvalds   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   Ingo Molnar   [PATCH] genirq: c...
33
  	struct irq_desc *desc;
10e580842   Thomas Gleixner   genirq: use itera...
34
  	unsigned long mask = 0;
10e580842   Thomas Gleixner   genirq: use itera...
35
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36

22a9d6456   Arjan van de Ven   async: Asynchrono...
37
38
39
40
  	/*
  	 * quiesce the kernel, or at least the asynchronous portion
  	 */
  	async_synchronize_full();
74ffd553a   Ingo Molnar   [PATCH] genirq: s...
41
  	mutex_lock(&probing_active);
1da177e4c   Linus Torvalds   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   Thomas Gleixner   genirq: use itera...
46
  	for_each_irq_desc_reverse(i, desc) {
239007b84   Thomas Gleixner   genirq: Convert i...
47
  		raw_spin_lock_irq(&desc->lock);
1ccb4e612   Thomas Gleixner   genirq: Wrap the ...
48
  		if (!desc->action && irq_settings_can_probe(desc)) {
6a6de9ef5   Thomas Gleixner   [PATCH] genirq: core
49
50
51
52
  			/*
  			 * Some chips need to know about probing in
  			 * progress:
  			 */
b2ba2c300   Thomas Gleixner   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   Thomas Gleixner   genirq: Add force...
56
  			irq_startup(desc, IRQ_NORESEND, IRQ_START_FORCE);
6a6de9ef5   Thomas Gleixner   [PATCH] genirq: core
57
  		}
239007b84   Thomas Gleixner   genirq: Convert i...
58
  		raw_spin_unlock_irq(&desc->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59
60
61
  	}
  
  	/* Wait for longstanding interrupts to trigger. */
47f176fda   Luca Falavigna   [PATCH] Using msl...
62
  	msleep(20);
1da177e4c   Linus Torvalds   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   Thomas Gleixner   genirq: use itera...
69
  	for_each_irq_desc_reverse(i, desc) {
239007b84   Thomas Gleixner   genirq: Convert i...
70
  		raw_spin_lock_irq(&desc->lock);
1ccb4e612   Thomas Gleixner   genirq: Wrap the ...
71
  		if (!desc->action && irq_settings_can_probe(desc)) {
163ef3091   Thomas Gleixner   genirq: Move IRQ_...
72
  			desc->istate |= IRQS_AUTODETECT | IRQS_WAITING;
4cde9c6b8   Thomas Gleixner   genirq: Add force...
73
  			if (irq_startup(desc, IRQ_NORESEND, IRQ_START_FORCE))
2a0d6fb33   Thomas Gleixner   genirq: Move IRQ_...
74
  				desc->istate |= IRQS_PENDING;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
  		}
239007b84   Thomas Gleixner   genirq: Convert i...
76
  		raw_spin_unlock_irq(&desc->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
78
79
80
81
  	}
  
  	/*
  	 * Wait for spurious interrupts to trigger
  	 */
47f176fda   Luca Falavigna   [PATCH] Using msl...
82
  	msleep(100);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
84
85
86
  
  	/*
  	 * Now filter out any obviously spurious interrupts
  	 */
10e580842   Thomas Gleixner   genirq: use itera...
87
  	for_each_irq_desc(i, desc) {
239007b84   Thomas Gleixner   genirq: Convert i...
88
  		raw_spin_lock_irq(&desc->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89

bd062e766   Thomas Gleixner   genirq: Move IRQ_...
90
  		if (desc->istate & IRQS_AUTODETECT) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
  			/* It triggered already - consider it spurious. */
163ef3091   Thomas Gleixner   genirq: Move IRQ_...
92
  			if (!(desc->istate & IRQS_WAITING)) {
bd062e766   Thomas Gleixner   genirq: Move IRQ_...
93
  				desc->istate &= ~IRQS_AUTODETECT;
469992386   Thomas Gleixner   genirq: Consolida...
94
  				irq_shutdown(desc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
96
  			} else
  				if (i < 32)
06fcb0c6f   Ingo Molnar   [PATCH] genirq: c...
97
  					mask |= 1 << i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
  		}
239007b84   Thomas Gleixner   genirq: Convert i...
99
  		raw_spin_unlock_irq(&desc->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
  	}
06fcb0c6f   Ingo Molnar   [PATCH] genirq: c...
101
  	return mask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
  }
1da177e4c   Linus Torvalds   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   Thomas Gleixner   genirq: Move IRQ_...
119
  	unsigned int mask = 0;
10e580842   Thomas Gleixner   genirq: use itera...
120
  	struct irq_desc *desc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
  	int i;
10e580842   Thomas Gleixner   genirq: use itera...
122
  	for_each_irq_desc(i, desc) {
239007b84   Thomas Gleixner   genirq: Convert i...
123
  		raw_spin_lock_irq(&desc->lock);
bd062e766   Thomas Gleixner   genirq: Move IRQ_...
124
  		if (desc->istate & IRQS_AUTODETECT) {
163ef3091   Thomas Gleixner   genirq: Move IRQ_...
125
  			if (i < 16 && !(desc->istate & IRQS_WAITING))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
  				mask |= 1 << i;
bd062e766   Thomas Gleixner   genirq: Move IRQ_...
127
  			desc->istate &= ~IRQS_AUTODETECT;
469992386   Thomas Gleixner   genirq: Consolida...
128
  			irq_shutdown(desc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
  		}
239007b84   Thomas Gleixner   genirq: Convert i...
130
  		raw_spin_unlock_irq(&desc->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
  	}
74ffd553a   Ingo Molnar   [PATCH] genirq: s...
132
  	mutex_unlock(&probing_active);
1da177e4c   Linus Torvalds   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   Thomas Gleixner   genirq: fix name ...
157
  	int i, irq_found = 0, nr_of_irqs = 0;
10e580842   Thomas Gleixner   genirq: use itera...
158
  	struct irq_desc *desc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159

10e580842   Thomas Gleixner   genirq: use itera...
160
  	for_each_irq_desc(i, desc) {
239007b84   Thomas Gleixner   genirq: Convert i...
161
  		raw_spin_lock_irq(&desc->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162

bd062e766   Thomas Gleixner   genirq: Move IRQ_...
163
  		if (desc->istate & IRQS_AUTODETECT) {
163ef3091   Thomas Gleixner   genirq: Move IRQ_...
164
  			if (!(desc->istate & IRQS_WAITING)) {
63d659d55   Thomas Gleixner   genirq: fix name ...
165
  				if (!nr_of_irqs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166
  					irq_found = i;
63d659d55   Thomas Gleixner   genirq: fix name ...
167
  				nr_of_irqs++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
  			}
bd062e766   Thomas Gleixner   genirq: Move IRQ_...
169
  			desc->istate &= ~IRQS_AUTODETECT;
469992386   Thomas Gleixner   genirq: Consolida...
170
  			irq_shutdown(desc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
  		}
239007b84   Thomas Gleixner   genirq: Convert i...
172
  		raw_spin_unlock_irq(&desc->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
  	}
74ffd553a   Ingo Molnar   [PATCH] genirq: s...
174
  	mutex_unlock(&probing_active);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175

63d659d55   Thomas Gleixner   genirq: fix name ...
176
  	if (nr_of_irqs > 1)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
  		irq_found = -irq_found;
74ffd553a   Ingo Molnar   [PATCH] genirq: s...
178

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
180
  	return irq_found;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
  EXPORT_SYMBOL(probe_irq_off);