Blame view

kernel/irq/manage.c 13.9 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
  /*
   * linux/kernel/irq/manage.c
   *
a34db9b28   Ingo Molnar   [PATCH] genirq: u...
4
5
   * Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar
   * Copyright (C) 2005-2006 Thomas Gleixner
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
7
8
9
10
11
12
13
14
15
16
17
   *
   * This file contains driver APIs to the irq subsystem.
   */
  
  #include <linux/irq.h>
  #include <linux/module.h>
  #include <linux/random.h>
  #include <linux/interrupt.h>
  
  #include "internals.h"
  
  #ifdef CONFIG_SMP
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
  /**
   *	synchronize_irq - wait for pending IRQ handlers (on other CPUs)
1e5d53314   Randy Dunlap   [PATCH] more kern...
20
   *	@irq: interrupt number to wait for
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
23
24
25
26
27
28
29
30
   *
   *	This function waits for any pending IRQ handlers for this interrupt
   *	to complete before returning. If you use this function while
   *	holding a resource the IRQ handler may need you will deadlock.
   *
   *	This function may be called - with care - from IRQ context.
   */
  void synchronize_irq(unsigned int irq)
  {
  	struct irq_desc *desc = irq_desc + irq;
c2b5a251b   Matthew Wilcox   [PATCH] Check the...
31
32
  	if (irq >= NR_IRQS)
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
34
35
  	while (desc->status & IRQ_INPROGRESS)
  		cpu_relax();
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
  EXPORT_SYMBOL(synchronize_irq);
771ee3b04   Thomas Gleixner   [PATCH] Add a fun...
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
  /**
   *	irq_can_set_affinity - Check if the affinity of a given irq can be set
   *	@irq:		Interrupt to check
   *
   */
  int irq_can_set_affinity(unsigned int irq)
  {
  	struct irq_desc *desc = irq_desc + irq;
  
  	if (CHECK_IRQ_PER_CPU(desc->status) || !desc->chip ||
  	    !desc->chip->set_affinity)
  		return 0;
  
  	return 1;
  }
  
  /**
   *	irq_set_affinity - Set the irq affinity of a given irq
   *	@irq:		Interrupt to set affinity
   *	@cpumask:	cpumask
   *
   */
  int irq_set_affinity(unsigned int irq, cpumask_t cpumask)
  {
  	struct irq_desc *desc = irq_desc + irq;
  
  	if (!desc->chip->set_affinity)
  		return -EINVAL;
  
  	set_balance_irq_affinity(irq, cpumask);
  
  #ifdef CONFIG_GENERIC_PENDING_IRQ
  	set_pending_irq(irq, cpumask);
  #else
  	desc->affinity = cpumask;
  	desc->chip->set_affinity(irq, cpumask);
  #endif
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
  #endif
  
  /**
   *	disable_irq_nosync - disable an irq without waiting
   *	@irq: Interrupt to disable
   *
   *	Disable the selected interrupt line.  Disables and Enables are
   *	nested.
   *	Unlike disable_irq(), this function does not ensure existing
   *	instances of the IRQ handler have completed before returning.
   *
   *	This function may be called from IRQ context.
   */
  void disable_irq_nosync(unsigned int irq)
  {
34ffdb723   Ingo Molnar   [PATCH] genirq: c...
91
  	struct irq_desc *desc = irq_desc + irq;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
  	unsigned long flags;
c2b5a251b   Matthew Wilcox   [PATCH] Check the...
93
94
  	if (irq >= NR_IRQS)
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
96
97
  	spin_lock_irqsave(&desc->lock, flags);
  	if (!desc->depth++) {
  		desc->status |= IRQ_DISABLED;
d1bef4ed5   Ingo Molnar   [PATCH] genirq: r...
98
  		desc->chip->disable(irq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
99
100
101
  	}
  	spin_unlock_irqrestore(&desc->lock, flags);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
  EXPORT_SYMBOL(disable_irq_nosync);
  
  /**
   *	disable_irq - disable an irq and wait for completion
   *	@irq: Interrupt to disable
   *
   *	Disable the selected interrupt line.  Enables and Disables are
   *	nested.
   *	This function waits for any pending IRQ handlers for this interrupt
   *	to complete before returning. If you use this function while
   *	holding a resource the IRQ handler may need you will deadlock.
   *
   *	This function may be called - with care - from IRQ context.
   */
  void disable_irq(unsigned int irq)
  {
34ffdb723   Ingo Molnar   [PATCH] genirq: c...
118
  	struct irq_desc *desc = irq_desc + irq;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119

c2b5a251b   Matthew Wilcox   [PATCH] Check the...
120
121
  	if (irq >= NR_IRQS)
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
123
124
125
  	disable_irq_nosync(irq);
  	if (desc->action)
  		synchronize_irq(irq);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
127
128
129
130
131
132
133
134
135
136
137
138
139
  EXPORT_SYMBOL(disable_irq);
  
  /**
   *	enable_irq - enable handling of an irq
   *	@irq: Interrupt to enable
   *
   *	Undoes the effect of one call to disable_irq().  If this
   *	matches the last disable, processing of interrupts on this
   *	IRQ line is re-enabled.
   *
   *	This function may be called from IRQ context.
   */
  void enable_irq(unsigned int irq)
  {
34ffdb723   Ingo Molnar   [PATCH] genirq: c...
140
  	struct irq_desc *desc = irq_desc + irq;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
  	unsigned long flags;
c2b5a251b   Matthew Wilcox   [PATCH] Check the...
142
143
  	if (irq >= NR_IRQS)
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
145
146
  	spin_lock_irqsave(&desc->lock, flags);
  	switch (desc->depth) {
  	case 0:
e8c4b9d00   Bjorn Helgaas   [PATCH] IRQ: warn...
147
148
  		printk(KERN_WARNING "Unbalanced enable for IRQ %d
  ", irq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
150
151
  		WARN_ON(1);
  		break;
  	case 1: {
3418d7240   Thomas Gleixner   [PATCH] genirq: a...
152
153
154
155
  		unsigned int status = desc->status & ~IRQ_DISABLED;
  
  		/* Prevent probing on this irq: */
  		desc->status = status | IRQ_NOPROBE;
a4633adcd   Thomas Gleixner   [PATCH] genirq: a...
156
  		check_irq_resend(desc, irq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
158
159
160
161
162
163
  		/* fall-through */
  	}
  	default:
  		desc->depth--;
  	}
  	spin_unlock_irqrestore(&desc->lock, flags);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
  EXPORT_SYMBOL(enable_irq);
ba9a2331b   Thomas Gleixner   [PATCH] genirq: a...
165
166
167
168
169
  /**
   *	set_irq_wake - control irq power management wakeup
   *	@irq:	interrupt to control
   *	@on:	enable/disable power management wakeup
   *
15a647eba   David Brownell   [PATCH] genirq: {...
170
171
172
173
174
175
   *	Enable/disable power management wakeup mode, which is
   *	disabled by default.  Enables and disables must match,
   *	just as they match for non-wakeup mode support.
   *
   *	Wakeup mode lets this IRQ wake the system from sleep
   *	states like "suspend to RAM".
ba9a2331b   Thomas Gleixner   [PATCH] genirq: a...
176
177
178
179
180
181
   */
  int set_irq_wake(unsigned int irq, unsigned int on)
  {
  	struct irq_desc *desc = irq_desc + irq;
  	unsigned long flags;
  	int ret = -ENXIO;
15a647eba   David Brownell   [PATCH] genirq: {...
182
  	int (*set_wake)(unsigned, unsigned) = desc->chip->set_wake;
ba9a2331b   Thomas Gleixner   [PATCH] genirq: a...
183

15a647eba   David Brownell   [PATCH] genirq: {...
184
185
186
  	/* wakeup-capable irqs can be shared between drivers that
  	 * don't need to have the same sleep mode behaviors.
  	 */
ba9a2331b   Thomas Gleixner   [PATCH] genirq: a...
187
  	spin_lock_irqsave(&desc->lock, flags);
15a647eba   David Brownell   [PATCH] genirq: {...
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
  	if (on) {
  		if (desc->wake_depth++ == 0)
  			desc->status |= IRQ_WAKEUP;
  		else
  			set_wake = NULL;
  	} else {
  		if (desc->wake_depth == 0) {
  			printk(KERN_WARNING "Unbalanced IRQ %d "
  					"wake disable
  ", irq);
  			WARN_ON(1);
  		} else if (--desc->wake_depth == 0)
  			desc->status &= ~IRQ_WAKEUP;
  		else
  			set_wake = NULL;
  	}
  	if (set_wake)
ba9a2331b   Thomas Gleixner   [PATCH] genirq: a...
205
206
207
208
209
  		ret = desc->chip->set_wake(irq, on);
  	spin_unlock_irqrestore(&desc->lock, flags);
  	return ret;
  }
  EXPORT_SYMBOL(set_irq_wake);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
211
212
213
214
215
216
217
  /*
   * Internal function that tells the architecture code whether a
   * particular irq has been exclusively allocated or is available
   * for driver use.
   */
  int can_request_irq(unsigned int irq, unsigned long irqflags)
  {
  	struct irqaction *action;
6550c775c   Thomas Gleixner   [PATCH] genirq: a...
218
  	if (irq >= NR_IRQS || irq_desc[irq].status & IRQ_NOREQUEST)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219
220
221
222
  		return 0;
  
  	action = irq_desc[irq].action;
  	if (action)
3cca53b02   Thomas Gleixner   [PATCH] irq-flags...
223
  		if (irqflags & action->flags & IRQF_SHARED)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
224
225
226
227
  			action = NULL;
  
  	return !action;
  }
6a6de9ef5   Thomas Gleixner   [PATCH] genirq: core
228
229
230
231
232
233
234
235
236
237
  void compat_irq_chip_set_default_handler(struct irq_desc *desc)
  {
  	/*
  	 * If the architecture still has not overriden
  	 * the flow handler then zap the default. This
  	 * should catch incorrect flow-type setting.
  	 */
  	if (desc->handle_irq == &handle_bad_irq)
  		desc->handle_irq = NULL;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238
239
240
241
  /*
   * Internal function to register an irqaction - typically used to
   * allocate special interrupts that are part of the architecture.
   */
06fcb0c6f   Ingo Molnar   [PATCH] genirq: c...
242
  int setup_irq(unsigned int irq, struct irqaction *new)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
243
244
245
  {
  	struct irq_desc *desc = irq_desc + irq;
  	struct irqaction *old, **p;
8b126b775   Andrew Morton   [PATCH] setup_irq...
246
  	const char *old_name = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
248
  	unsigned long flags;
  	int shared = 0;
c2b5a251b   Matthew Wilcox   [PATCH] Check the...
249
250
  	if (irq >= NR_IRQS)
  		return -EINVAL;
f1c2662cb   Ingo Molnar   [PATCH] genirq: c...
251
  	if (desc->chip == &no_irq_chip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252
253
254
255
256
257
  		return -ENOSYS;
  	/*
  	 * Some drivers like serial.c use request_irq() heavily,
  	 * so we have to be careful not to interfere with a
  	 * running system.
  	 */
3cca53b02   Thomas Gleixner   [PATCH] irq-flags...
258
  	if (new->flags & IRQF_SAMPLE_RANDOM) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259
260
261
262
263
264
265
266
267
268
269
270
271
272
  		/*
  		 * This function might sleep, we want to call it first,
  		 * outside of the atomic block.
  		 * Yes, this might clear the entropy pool if the wrong
  		 * driver is attempted to be loaded, without actually
  		 * installing a new handler, but is this really a problem,
  		 * only the sysadmin is able to do this.
  		 */
  		rand_initialize_irq(irq);
  	}
  
  	/*
  	 * The following block of code has to be executed atomically
  	 */
06fcb0c6f   Ingo Molnar   [PATCH] genirq: c...
273
  	spin_lock_irqsave(&desc->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
  	p = &desc->action;
06fcb0c6f   Ingo Molnar   [PATCH] genirq: c...
275
276
  	old = *p;
  	if (old) {
e76de9f8e   Thomas Gleixner   [PATCH] genirq: a...
277
278
279
  		/*
  		 * Can't share interrupts unless both agree to and are
  		 * the same type (level, edge, polarity). So both flag
3cca53b02   Thomas Gleixner   [PATCH] irq-flags...
280
  		 * fields must have IRQF_SHARED set and the bits which
e76de9f8e   Thomas Gleixner   [PATCH] genirq: a...
281
282
  		 * set the trigger type must match.
  		 */
3cca53b02   Thomas Gleixner   [PATCH] irq-flags...
283
  		if (!((old->flags & new->flags) & IRQF_SHARED) ||
8b126b775   Andrew Morton   [PATCH] setup_irq...
284
285
  		    ((old->flags ^ new->flags) & IRQF_TRIGGER_MASK)) {
  			old_name = old->name;
f51634274   Dimitri Sivanich   [PATCH] Add SA_PE...
286
  			goto mismatch;
8b126b775   Andrew Morton   [PATCH] setup_irq...
287
  		}
f51634274   Dimitri Sivanich   [PATCH] Add SA_PE...
288

284c66806   Thomas Gleixner   [PATCH] genirq:fi...
289
  #if defined(CONFIG_IRQ_PER_CPU)
f51634274   Dimitri Sivanich   [PATCH] Add SA_PE...
290
  		/* All handlers must agree on per-cpuness */
3cca53b02   Thomas Gleixner   [PATCH] irq-flags...
291
292
  		if ((old->flags & IRQF_PERCPU) !=
  		    (new->flags & IRQF_PERCPU))
f51634274   Dimitri Sivanich   [PATCH] Add SA_PE...
293
294
  			goto mismatch;
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
296
297
298
299
300
301
302
303
304
  
  		/* add new interrupt at end of irq queue */
  		do {
  			p = &old->next;
  			old = *p;
  		} while (old);
  		shared = 1;
  	}
  
  	*p = new;
f75d222b8   Ahmed S. Darwish   IRQ: check for PE...
305

950f4427c   Thomas Gleixner   [PATCH] Add irq f...
306
307
308
  	/* Exclude IRQ from balancing */
  	if (new->flags & IRQF_NOBALANCING)
  		desc->status |= IRQ_NO_BALANCING;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
  	if (!shared) {
6a6de9ef5   Thomas Gleixner   [PATCH] genirq: core
310
  		irq_chip_set_defaults(desc->chip);
e76de9f8e   Thomas Gleixner   [PATCH] genirq: a...
311

f75d222b8   Ahmed S. Darwish   IRQ: check for PE...
312
313
314
315
  #if defined(CONFIG_IRQ_PER_CPU)
  		if (new->flags & IRQF_PERCPU)
  			desc->status |= IRQ_PER_CPU;
  #endif
e76de9f8e   Thomas Gleixner   [PATCH] genirq: a...
316
  		/* Setup the type (level, edge polarity) if configured: */
3cca53b02   Thomas Gleixner   [PATCH] irq-flags...
317
  		if (new->flags & IRQF_TRIGGER_MASK) {
e76de9f8e   Thomas Gleixner   [PATCH] genirq: a...
318
319
  			if (desc->chip && desc->chip->set_type)
  				desc->chip->set_type(irq,
3cca53b02   Thomas Gleixner   [PATCH] irq-flags...
320
  						new->flags & IRQF_TRIGGER_MASK);
e76de9f8e   Thomas Gleixner   [PATCH] genirq: a...
321
322
  			else
  				/*
3cca53b02   Thomas Gleixner   [PATCH] irq-flags...
323
  				 * IRQF_TRIGGER_* but the PIC does not support
e76de9f8e   Thomas Gleixner   [PATCH] genirq: a...
324
325
  				 * multiple flow-types?
  				 */
3cca53b02   Thomas Gleixner   [PATCH] irq-flags...
326
  				printk(KERN_WARNING "No IRQF_TRIGGER set_type "
e8c4b9d00   Bjorn Helgaas   [PATCH] IRQ: warn...
327
328
329
330
  				       "function for IRQ %d (%s)
  ", irq,
  				       desc->chip ? desc->chip->name :
  				       "unknown");
e76de9f8e   Thomas Gleixner   [PATCH] genirq: a...
331
332
  		} else
  			compat_irq_chip_set_default_handler(desc);
6a6de9ef5   Thomas Gleixner   [PATCH] genirq: core
333

94d39e1f6   Thomas Gleixner   [PATCH] genirq: a...
334
335
336
337
338
339
340
341
342
343
  		desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING |
  				  IRQ_INPROGRESS);
  
  		if (!(desc->status & IRQ_NOAUTOEN)) {
  			desc->depth = 0;
  			desc->status &= ~IRQ_DISABLED;
  			if (desc->chip->startup)
  				desc->chip->startup(irq);
  			else
  				desc->chip->enable(irq);
e76de9f8e   Thomas Gleixner   [PATCH] genirq: a...
344
345
346
  		} else
  			/* Undo nested disables: */
  			desc->depth = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347
  	}
8528b0f1d   Linus Torvalds   Clear spurious ir...
348
349
350
  	/* Reset broken irq detection when installing new handler */
  	desc->irq_count = 0;
  	desc->irqs_unhandled = 0;
06fcb0c6f   Ingo Molnar   [PATCH] genirq: c...
351
  	spin_unlock_irqrestore(&desc->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
353
354
355
356
357
358
  
  	new->irq = irq;
  	register_irq_proc(irq);
  	new->dir = NULL;
  	register_handler_proc(irq, new);
  
  	return 0;
f51634274   Dimitri Sivanich   [PATCH] Add SA_PE...
359
360
  
  mismatch:
3f0504471   Alan Cox   [PATCH] kernel: s...
361
  #ifdef CONFIG_DEBUG_SHIRQ
3cca53b02   Thomas Gleixner   [PATCH] irq-flags...
362
  	if (!(new->flags & IRQF_PROBE_SHARED)) {
e8c4b9d00   Bjorn Helgaas   [PATCH] IRQ: warn...
363
364
  		printk(KERN_ERR "IRQ handler type mismatch for IRQ %d
  ", irq);
8b126b775   Andrew Morton   [PATCH] setup_irq...
365
366
367
  		if (old_name)
  			printk(KERN_ERR "current handler: %s
  ", old_name);
13e87ec68   Andrew Morton   [PATCH] request_i...
368
369
  		dump_stack();
  	}
3f0504471   Alan Cox   [PATCH] kernel: s...
370
  #endif
8b126b775   Andrew Morton   [PATCH] setup_irq...
371
  	spin_unlock_irqrestore(&desc->lock, flags);
f51634274   Dimitri Sivanich   [PATCH] Add SA_PE...
372
  	return -EBUSY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
  }
  
  /**
   *	free_irq - free an interrupt
   *	@irq: Interrupt line to free
   *	@dev_id: Device identity to free
   *
   *	Remove an interrupt handler. The handler is removed and if the
   *	interrupt line is no longer in use by any driver it is disabled.
   *	On a shared IRQ the caller must ensure the interrupt is disabled
   *	on the card it drives before calling this function. The function
   *	does not return until any executing interrupts for this IRQ
   *	have completed.
   *
   *	This function must not be called from interrupt context.
   */
  void free_irq(unsigned int irq, void *dev_id)
  {
  	struct irq_desc *desc;
  	struct irqaction **p;
  	unsigned long flags;
a304e1b82   David Woodhouse   [PATCH] Debug sha...
394
  	irqreturn_t (*handler)(int, void *) = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395

cd7b24bb1   Ingo Molnar   [PATCH] warn if f...
396
  	WARN_ON(in_interrupt());
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
397
398
399
400
  	if (irq >= NR_IRQS)
  		return;
  
  	desc = irq_desc + irq;
06fcb0c6f   Ingo Molnar   [PATCH] genirq: c...
401
  	spin_lock_irqsave(&desc->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
402
403
  	p = &desc->action;
  	for (;;) {
06fcb0c6f   Ingo Molnar   [PATCH] genirq: c...
404
  		struct irqaction *action = *p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405
406
407
408
409
410
411
412
413
414
  
  		if (action) {
  			struct irqaction **pp = p;
  
  			p = &action->next;
  			if (action->dev_id != dev_id)
  				continue;
  
  			/* Found it - now remove it from the list of entries */
  			*pp = action->next;
dbce706e2   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: add ...
415

b77d6adc9   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: make...
416
417
  			/* Currently used only by UML, might disappear one day.*/
  #ifdef CONFIG_IRQ_RELEASE_METHOD
d1bef4ed5   Ingo Molnar   [PATCH] genirq: r...
418
419
  			if (desc->chip->release)
  				desc->chip->release(irq, dev_id);
b77d6adc9   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: make...
420
  #endif
dbce706e2   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: add ...
421

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422
423
  			if (!desc->action) {
  				desc->status |= IRQ_DISABLED;
d1bef4ed5   Ingo Molnar   [PATCH] genirq: r...
424
425
  				if (desc->chip->shutdown)
  					desc->chip->shutdown(irq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
426
  				else
d1bef4ed5   Ingo Molnar   [PATCH] genirq: r...
427
  					desc->chip->disable(irq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428
  			}
06fcb0c6f   Ingo Molnar   [PATCH] genirq: c...
429
  			spin_unlock_irqrestore(&desc->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
431
432
433
  			unregister_handler_proc(irq, action);
  
  			/* Make sure it's not being used on another CPU */
  			synchronize_irq(irq);
a304e1b82   David Woodhouse   [PATCH] Debug sha...
434
435
  			if (action->flags & IRQF_SHARED)
  				handler = action->handler;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
436
437
438
  			kfree(action);
  			return;
  		}
e8c4b9d00   Bjorn Helgaas   [PATCH] IRQ: warn...
439
440
  		printk(KERN_ERR "Trying to free already-free IRQ %d
  ", irq);
06fcb0c6f   Ingo Molnar   [PATCH] genirq: c...
441
  		spin_unlock_irqrestore(&desc->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
443
  		return;
  	}
a304e1b82   David Woodhouse   [PATCH] Debug sha...
444
445
446
447
448
449
450
451
452
453
454
  #ifdef CONFIG_DEBUG_SHIRQ
  	if (handler) {
  		/*
  		 * It's a shared IRQ -- the driver ought to be prepared for it
  		 * to happen even now it's being freed, so let's make sure....
  		 * We do this after actually deregistering it, to make sure that
  		 * a 'real' IRQ doesn't run in parallel with our fake
  		 */
  		handler(irq, dev_id);
  	}
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
455
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
  EXPORT_SYMBOL(free_irq);
  
  /**
   *	request_irq - allocate an interrupt line
   *	@irq: Interrupt line to allocate
   *	@handler: Function to be called when the IRQ occurs
   *	@irqflags: Interrupt type flags
   *	@devname: An ascii name for the claiming device
   *	@dev_id: A cookie passed back to the handler function
   *
   *	This call allocates interrupt resources and enables the
   *	interrupt line and IRQ handling. From the point this
   *	call is made your handler function may be invoked. Since
   *	your handler function must clear any interrupt the board
   *	raises, you must take care both to initialise your hardware
   *	and to set up the interrupt handler in the right order.
   *
   *	Dev_id must be globally unique. Normally the address of the
   *	device data structure is used as the cookie. Since the handler
   *	receives this value it makes sense to use it.
   *
   *	If your interrupt is shared you must pass a non NULL dev_id
   *	as this is required when freeing the interrupt.
   *
   *	Flags:
   *
3cca53b02   Thomas Gleixner   [PATCH] irq-flags...
482
483
484
   *	IRQF_SHARED		Interrupt is shared
   *	IRQF_DISABLED	Disable local interrupts while processing
   *	IRQF_SAMPLE_RANDOM	The interrupt can be used for entropy
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
485
486
   *
   */
da482792a   David Howells   IRQ: Typedef the ...
487
  int request_irq(unsigned int irq, irq_handler_t handler,
06fcb0c6f   Ingo Molnar   [PATCH] genirq: c...
488
  		unsigned long irqflags, const char *devname, void *dev_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489
  {
06fcb0c6f   Ingo Molnar   [PATCH] genirq: c...
490
  	struct irqaction *action;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
491
  	int retval;
fbb9ce953   Ingo Molnar   [PATCH] lockdep: ...
492
493
494
495
  #ifdef CONFIG_LOCKDEP
  	/*
  	 * Lockdep wants atomic interrupt handlers:
  	 */
38515e908   Thomas Gleixner   [PATCH] Scheduled...
496
  	irqflags |= IRQF_DISABLED;
fbb9ce953   Ingo Molnar   [PATCH] lockdep: ...
497
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
498
499
500
501
502
503
  	/*
  	 * Sanity-check: shared interrupts must pass in a real dev-ID,
  	 * otherwise we'll have trouble later trying to figure out
  	 * which interrupt is which (messes up the interrupt freeing
  	 * logic etc).
  	 */
3cca53b02   Thomas Gleixner   [PATCH] irq-flags...
504
  	if ((irqflags & IRQF_SHARED) && !dev_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
505
506
507
  		return -EINVAL;
  	if (irq >= NR_IRQS)
  		return -EINVAL;
6550c775c   Thomas Gleixner   [PATCH] genirq: a...
508
509
  	if (irq_desc[irq].status & IRQ_NOREQUEST)
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
510
511
512
513
514
515
516
517
518
519
520
521
522
  	if (!handler)
  		return -EINVAL;
  
  	action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC);
  	if (!action)
  		return -ENOMEM;
  
  	action->handler = handler;
  	action->flags = irqflags;
  	cpus_clear(action->mask);
  	action->name = devname;
  	action->next = NULL;
  	action->dev_id = dev_id;
eee45269b   Ivan Kokshaysky   [PATCH] Alpha: co...
523
  	select_smp_affinity(irq);
a304e1b82   David Woodhouse   [PATCH] Debug sha...
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
  #ifdef CONFIG_DEBUG_SHIRQ
  	if (irqflags & IRQF_SHARED) {
  		/*
  		 * It's a shared IRQ -- the driver ought to be prepared for it
  		 * to happen immediately, so let's make sure....
  		 * We do this before actually registering it, to make sure that
  		 * a 'real' IRQ doesn't run in parallel with our fake
  		 */
  		if (irqflags & IRQF_DISABLED) {
  			unsigned long flags;
  
  			local_irq_save(flags);
  			handler(irq, dev_id);
  			local_irq_restore(flags);
  		} else
  			handler(irq, dev_id);
  	}
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
543
544
545
546
547
  	retval = setup_irq(irq, action);
  	if (retval)
  		kfree(action);
  
  	return retval;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
548
  EXPORT_SYMBOL(request_irq);