xref: /openbmc/linux/kernel/irq/manage.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
1*1da177e4SLinus Torvalds /*
2*1da177e4SLinus Torvalds  * linux/kernel/irq/manage.c
3*1da177e4SLinus Torvalds  *
4*1da177e4SLinus Torvalds  * Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar
5*1da177e4SLinus Torvalds  *
6*1da177e4SLinus Torvalds  * This file contains driver APIs to the irq subsystem.
7*1da177e4SLinus Torvalds  */
8*1da177e4SLinus Torvalds 
9*1da177e4SLinus Torvalds #include <linux/irq.h>
10*1da177e4SLinus Torvalds #include <linux/module.h>
11*1da177e4SLinus Torvalds #include <linux/random.h>
12*1da177e4SLinus Torvalds #include <linux/interrupt.h>
13*1da177e4SLinus Torvalds 
14*1da177e4SLinus Torvalds #include "internals.h"
15*1da177e4SLinus Torvalds 
16*1da177e4SLinus Torvalds #ifdef CONFIG_SMP
17*1da177e4SLinus Torvalds 
18*1da177e4SLinus Torvalds cpumask_t irq_affinity[NR_IRQS] = { [0 ... NR_IRQS-1] = CPU_MASK_ALL };
19*1da177e4SLinus Torvalds 
20*1da177e4SLinus Torvalds /**
21*1da177e4SLinus Torvalds  *	synchronize_irq - wait for pending IRQ handlers (on other CPUs)
22*1da177e4SLinus Torvalds  *
23*1da177e4SLinus Torvalds  *	This function waits for any pending IRQ handlers for this interrupt
24*1da177e4SLinus Torvalds  *	to complete before returning. If you use this function while
25*1da177e4SLinus Torvalds  *	holding a resource the IRQ handler may need you will deadlock.
26*1da177e4SLinus Torvalds  *
27*1da177e4SLinus Torvalds  *	This function may be called - with care - from IRQ context.
28*1da177e4SLinus Torvalds  */
29*1da177e4SLinus Torvalds void synchronize_irq(unsigned int irq)
30*1da177e4SLinus Torvalds {
31*1da177e4SLinus Torvalds 	struct irq_desc *desc = irq_desc + irq;
32*1da177e4SLinus Torvalds 
33*1da177e4SLinus Torvalds 	while (desc->status & IRQ_INPROGRESS)
34*1da177e4SLinus Torvalds 		cpu_relax();
35*1da177e4SLinus Torvalds }
36*1da177e4SLinus Torvalds 
37*1da177e4SLinus Torvalds EXPORT_SYMBOL(synchronize_irq);
38*1da177e4SLinus Torvalds 
39*1da177e4SLinus Torvalds #endif
40*1da177e4SLinus Torvalds 
41*1da177e4SLinus Torvalds /**
42*1da177e4SLinus Torvalds  *	disable_irq_nosync - disable an irq without waiting
43*1da177e4SLinus Torvalds  *	@irq: Interrupt to disable
44*1da177e4SLinus Torvalds  *
45*1da177e4SLinus Torvalds  *	Disable the selected interrupt line.  Disables and Enables are
46*1da177e4SLinus Torvalds  *	nested.
47*1da177e4SLinus Torvalds  *	Unlike disable_irq(), this function does not ensure existing
48*1da177e4SLinus Torvalds  *	instances of the IRQ handler have completed before returning.
49*1da177e4SLinus Torvalds  *
50*1da177e4SLinus Torvalds  *	This function may be called from IRQ context.
51*1da177e4SLinus Torvalds  */
52*1da177e4SLinus Torvalds void disable_irq_nosync(unsigned int irq)
53*1da177e4SLinus Torvalds {
54*1da177e4SLinus Torvalds 	irq_desc_t *desc = irq_desc + irq;
55*1da177e4SLinus Torvalds 	unsigned long flags;
56*1da177e4SLinus Torvalds 
57*1da177e4SLinus Torvalds 	spin_lock_irqsave(&desc->lock, flags);
58*1da177e4SLinus Torvalds 	if (!desc->depth++) {
59*1da177e4SLinus Torvalds 		desc->status |= IRQ_DISABLED;
60*1da177e4SLinus Torvalds 		desc->handler->disable(irq);
61*1da177e4SLinus Torvalds 	}
62*1da177e4SLinus Torvalds 	spin_unlock_irqrestore(&desc->lock, flags);
63*1da177e4SLinus Torvalds }
64*1da177e4SLinus Torvalds 
65*1da177e4SLinus Torvalds EXPORT_SYMBOL(disable_irq_nosync);
66*1da177e4SLinus Torvalds 
67*1da177e4SLinus Torvalds /**
68*1da177e4SLinus Torvalds  *	disable_irq - disable an irq and wait for completion
69*1da177e4SLinus Torvalds  *	@irq: Interrupt to disable
70*1da177e4SLinus Torvalds  *
71*1da177e4SLinus Torvalds  *	Disable the selected interrupt line.  Enables and Disables are
72*1da177e4SLinus Torvalds  *	nested.
73*1da177e4SLinus Torvalds  *	This function waits for any pending IRQ handlers for this interrupt
74*1da177e4SLinus Torvalds  *	to complete before returning. If you use this function while
75*1da177e4SLinus Torvalds  *	holding a resource the IRQ handler may need you will deadlock.
76*1da177e4SLinus Torvalds  *
77*1da177e4SLinus Torvalds  *	This function may be called - with care - from IRQ context.
78*1da177e4SLinus Torvalds  */
79*1da177e4SLinus Torvalds void disable_irq(unsigned int irq)
80*1da177e4SLinus Torvalds {
81*1da177e4SLinus Torvalds 	irq_desc_t *desc = irq_desc + irq;
82*1da177e4SLinus Torvalds 
83*1da177e4SLinus Torvalds 	disable_irq_nosync(irq);
84*1da177e4SLinus Torvalds 	if (desc->action)
85*1da177e4SLinus Torvalds 		synchronize_irq(irq);
86*1da177e4SLinus Torvalds }
87*1da177e4SLinus Torvalds 
88*1da177e4SLinus Torvalds EXPORT_SYMBOL(disable_irq);
89*1da177e4SLinus Torvalds 
90*1da177e4SLinus Torvalds /**
91*1da177e4SLinus Torvalds  *	enable_irq - enable handling of an irq
92*1da177e4SLinus Torvalds  *	@irq: Interrupt to enable
93*1da177e4SLinus Torvalds  *
94*1da177e4SLinus Torvalds  *	Undoes the effect of one call to disable_irq().  If this
95*1da177e4SLinus Torvalds  *	matches the last disable, processing of interrupts on this
96*1da177e4SLinus Torvalds  *	IRQ line is re-enabled.
97*1da177e4SLinus Torvalds  *
98*1da177e4SLinus Torvalds  *	This function may be called from IRQ context.
99*1da177e4SLinus Torvalds  */
100*1da177e4SLinus Torvalds void enable_irq(unsigned int irq)
101*1da177e4SLinus Torvalds {
102*1da177e4SLinus Torvalds 	irq_desc_t *desc = irq_desc + irq;
103*1da177e4SLinus Torvalds 	unsigned long flags;
104*1da177e4SLinus Torvalds 
105*1da177e4SLinus Torvalds 	spin_lock_irqsave(&desc->lock, flags);
106*1da177e4SLinus Torvalds 	switch (desc->depth) {
107*1da177e4SLinus Torvalds 	case 0:
108*1da177e4SLinus Torvalds 		WARN_ON(1);
109*1da177e4SLinus Torvalds 		break;
110*1da177e4SLinus Torvalds 	case 1: {
111*1da177e4SLinus Torvalds 		unsigned int status = desc->status & ~IRQ_DISABLED;
112*1da177e4SLinus Torvalds 
113*1da177e4SLinus Torvalds 		desc->status = status;
114*1da177e4SLinus Torvalds 		if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
115*1da177e4SLinus Torvalds 			desc->status = status | IRQ_REPLAY;
116*1da177e4SLinus Torvalds 			hw_resend_irq(desc->handler,irq);
117*1da177e4SLinus Torvalds 		}
118*1da177e4SLinus Torvalds 		desc->handler->enable(irq);
119*1da177e4SLinus Torvalds 		/* fall-through */
120*1da177e4SLinus Torvalds 	}
121*1da177e4SLinus Torvalds 	default:
122*1da177e4SLinus Torvalds 		desc->depth--;
123*1da177e4SLinus Torvalds 	}
124*1da177e4SLinus Torvalds 	spin_unlock_irqrestore(&desc->lock, flags);
125*1da177e4SLinus Torvalds }
126*1da177e4SLinus Torvalds 
127*1da177e4SLinus Torvalds EXPORT_SYMBOL(enable_irq);
128*1da177e4SLinus Torvalds 
129*1da177e4SLinus Torvalds /*
130*1da177e4SLinus Torvalds  * Internal function that tells the architecture code whether a
131*1da177e4SLinus Torvalds  * particular irq has been exclusively allocated or is available
132*1da177e4SLinus Torvalds  * for driver use.
133*1da177e4SLinus Torvalds  */
134*1da177e4SLinus Torvalds int can_request_irq(unsigned int irq, unsigned long irqflags)
135*1da177e4SLinus Torvalds {
136*1da177e4SLinus Torvalds 	struct irqaction *action;
137*1da177e4SLinus Torvalds 
138*1da177e4SLinus Torvalds 	if (irq >= NR_IRQS)
139*1da177e4SLinus Torvalds 		return 0;
140*1da177e4SLinus Torvalds 
141*1da177e4SLinus Torvalds 	action = irq_desc[irq].action;
142*1da177e4SLinus Torvalds 	if (action)
143*1da177e4SLinus Torvalds 		if (irqflags & action->flags & SA_SHIRQ)
144*1da177e4SLinus Torvalds 			action = NULL;
145*1da177e4SLinus Torvalds 
146*1da177e4SLinus Torvalds 	return !action;
147*1da177e4SLinus Torvalds }
148*1da177e4SLinus Torvalds 
149*1da177e4SLinus Torvalds /*
150*1da177e4SLinus Torvalds  * Internal function to register an irqaction - typically used to
151*1da177e4SLinus Torvalds  * allocate special interrupts that are part of the architecture.
152*1da177e4SLinus Torvalds  */
153*1da177e4SLinus Torvalds int setup_irq(unsigned int irq, struct irqaction * new)
154*1da177e4SLinus Torvalds {
155*1da177e4SLinus Torvalds 	struct irq_desc *desc = irq_desc + irq;
156*1da177e4SLinus Torvalds 	struct irqaction *old, **p;
157*1da177e4SLinus Torvalds 	unsigned long flags;
158*1da177e4SLinus Torvalds 	int shared = 0;
159*1da177e4SLinus Torvalds 
160*1da177e4SLinus Torvalds 	if (desc->handler == &no_irq_type)
161*1da177e4SLinus Torvalds 		return -ENOSYS;
162*1da177e4SLinus Torvalds 	/*
163*1da177e4SLinus Torvalds 	 * Some drivers like serial.c use request_irq() heavily,
164*1da177e4SLinus Torvalds 	 * so we have to be careful not to interfere with a
165*1da177e4SLinus Torvalds 	 * running system.
166*1da177e4SLinus Torvalds 	 */
167*1da177e4SLinus Torvalds 	if (new->flags & SA_SAMPLE_RANDOM) {
168*1da177e4SLinus Torvalds 		/*
169*1da177e4SLinus Torvalds 		 * This function might sleep, we want to call it first,
170*1da177e4SLinus Torvalds 		 * outside of the atomic block.
171*1da177e4SLinus Torvalds 		 * Yes, this might clear the entropy pool if the wrong
172*1da177e4SLinus Torvalds 		 * driver is attempted to be loaded, without actually
173*1da177e4SLinus Torvalds 		 * installing a new handler, but is this really a problem,
174*1da177e4SLinus Torvalds 		 * only the sysadmin is able to do this.
175*1da177e4SLinus Torvalds 		 */
176*1da177e4SLinus Torvalds 		rand_initialize_irq(irq);
177*1da177e4SLinus Torvalds 	}
178*1da177e4SLinus Torvalds 
179*1da177e4SLinus Torvalds 	/*
180*1da177e4SLinus Torvalds 	 * The following block of code has to be executed atomically
181*1da177e4SLinus Torvalds 	 */
182*1da177e4SLinus Torvalds 	spin_lock_irqsave(&desc->lock,flags);
183*1da177e4SLinus Torvalds 	p = &desc->action;
184*1da177e4SLinus Torvalds 	if ((old = *p) != NULL) {
185*1da177e4SLinus Torvalds 		/* Can't share interrupts unless both agree to */
186*1da177e4SLinus Torvalds 		if (!(old->flags & new->flags & SA_SHIRQ)) {
187*1da177e4SLinus Torvalds 			spin_unlock_irqrestore(&desc->lock,flags);
188*1da177e4SLinus Torvalds 			return -EBUSY;
189*1da177e4SLinus Torvalds 		}
190*1da177e4SLinus Torvalds 
191*1da177e4SLinus Torvalds 		/* add new interrupt at end of irq queue */
192*1da177e4SLinus Torvalds 		do {
193*1da177e4SLinus Torvalds 			p = &old->next;
194*1da177e4SLinus Torvalds 			old = *p;
195*1da177e4SLinus Torvalds 		} while (old);
196*1da177e4SLinus Torvalds 		shared = 1;
197*1da177e4SLinus Torvalds 	}
198*1da177e4SLinus Torvalds 
199*1da177e4SLinus Torvalds 	*p = new;
200*1da177e4SLinus Torvalds 
201*1da177e4SLinus Torvalds 	if (!shared) {
202*1da177e4SLinus Torvalds 		desc->depth = 0;
203*1da177e4SLinus Torvalds 		desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT |
204*1da177e4SLinus Torvalds 				  IRQ_WAITING | IRQ_INPROGRESS);
205*1da177e4SLinus Torvalds 		if (desc->handler->startup)
206*1da177e4SLinus Torvalds 			desc->handler->startup(irq);
207*1da177e4SLinus Torvalds 		else
208*1da177e4SLinus Torvalds 			desc->handler->enable(irq);
209*1da177e4SLinus Torvalds 	}
210*1da177e4SLinus Torvalds 	spin_unlock_irqrestore(&desc->lock,flags);
211*1da177e4SLinus Torvalds 
212*1da177e4SLinus Torvalds 	new->irq = irq;
213*1da177e4SLinus Torvalds 	register_irq_proc(irq);
214*1da177e4SLinus Torvalds 	new->dir = NULL;
215*1da177e4SLinus Torvalds 	register_handler_proc(irq, new);
216*1da177e4SLinus Torvalds 
217*1da177e4SLinus Torvalds 	return 0;
218*1da177e4SLinus Torvalds }
219*1da177e4SLinus Torvalds 
220*1da177e4SLinus Torvalds /**
221*1da177e4SLinus Torvalds  *	free_irq - free an interrupt
222*1da177e4SLinus Torvalds  *	@irq: Interrupt line to free
223*1da177e4SLinus Torvalds  *	@dev_id: Device identity to free
224*1da177e4SLinus Torvalds  *
225*1da177e4SLinus Torvalds  *	Remove an interrupt handler. The handler is removed and if the
226*1da177e4SLinus Torvalds  *	interrupt line is no longer in use by any driver it is disabled.
227*1da177e4SLinus Torvalds  *	On a shared IRQ the caller must ensure the interrupt is disabled
228*1da177e4SLinus Torvalds  *	on the card it drives before calling this function. The function
229*1da177e4SLinus Torvalds  *	does not return until any executing interrupts for this IRQ
230*1da177e4SLinus Torvalds  *	have completed.
231*1da177e4SLinus Torvalds  *
232*1da177e4SLinus Torvalds  *	This function must not be called from interrupt context.
233*1da177e4SLinus Torvalds  */
234*1da177e4SLinus Torvalds void free_irq(unsigned int irq, void *dev_id)
235*1da177e4SLinus Torvalds {
236*1da177e4SLinus Torvalds 	struct irq_desc *desc;
237*1da177e4SLinus Torvalds 	struct irqaction **p;
238*1da177e4SLinus Torvalds 	unsigned long flags;
239*1da177e4SLinus Torvalds 
240*1da177e4SLinus Torvalds 	if (irq >= NR_IRQS)
241*1da177e4SLinus Torvalds 		return;
242*1da177e4SLinus Torvalds 
243*1da177e4SLinus Torvalds 	desc = irq_desc + irq;
244*1da177e4SLinus Torvalds 	spin_lock_irqsave(&desc->lock,flags);
245*1da177e4SLinus Torvalds 	p = &desc->action;
246*1da177e4SLinus Torvalds 	for (;;) {
247*1da177e4SLinus Torvalds 		struct irqaction * action = *p;
248*1da177e4SLinus Torvalds 
249*1da177e4SLinus Torvalds 		if (action) {
250*1da177e4SLinus Torvalds 			struct irqaction **pp = p;
251*1da177e4SLinus Torvalds 
252*1da177e4SLinus Torvalds 			p = &action->next;
253*1da177e4SLinus Torvalds 			if (action->dev_id != dev_id)
254*1da177e4SLinus Torvalds 				continue;
255*1da177e4SLinus Torvalds 
256*1da177e4SLinus Torvalds 			/* Found it - now remove it from the list of entries */
257*1da177e4SLinus Torvalds 			*pp = action->next;
258*1da177e4SLinus Torvalds 			if (!desc->action) {
259*1da177e4SLinus Torvalds 				desc->status |= IRQ_DISABLED;
260*1da177e4SLinus Torvalds 				if (desc->handler->shutdown)
261*1da177e4SLinus Torvalds 					desc->handler->shutdown(irq);
262*1da177e4SLinus Torvalds 				else
263*1da177e4SLinus Torvalds 					desc->handler->disable(irq);
264*1da177e4SLinus Torvalds 			}
265*1da177e4SLinus Torvalds 			spin_unlock_irqrestore(&desc->lock,flags);
266*1da177e4SLinus Torvalds 			unregister_handler_proc(irq, action);
267*1da177e4SLinus Torvalds 
268*1da177e4SLinus Torvalds 			/* Make sure it's not being used on another CPU */
269*1da177e4SLinus Torvalds 			synchronize_irq(irq);
270*1da177e4SLinus Torvalds 			kfree(action);
271*1da177e4SLinus Torvalds 			return;
272*1da177e4SLinus Torvalds 		}
273*1da177e4SLinus Torvalds 		printk(KERN_ERR "Trying to free free IRQ%d\n",irq);
274*1da177e4SLinus Torvalds 		spin_unlock_irqrestore(&desc->lock,flags);
275*1da177e4SLinus Torvalds 		return;
276*1da177e4SLinus Torvalds 	}
277*1da177e4SLinus Torvalds }
278*1da177e4SLinus Torvalds 
279*1da177e4SLinus Torvalds EXPORT_SYMBOL(free_irq);
280*1da177e4SLinus Torvalds 
281*1da177e4SLinus Torvalds /**
282*1da177e4SLinus Torvalds  *	request_irq - allocate an interrupt line
283*1da177e4SLinus Torvalds  *	@irq: Interrupt line to allocate
284*1da177e4SLinus Torvalds  *	@handler: Function to be called when the IRQ occurs
285*1da177e4SLinus Torvalds  *	@irqflags: Interrupt type flags
286*1da177e4SLinus Torvalds  *	@devname: An ascii name for the claiming device
287*1da177e4SLinus Torvalds  *	@dev_id: A cookie passed back to the handler function
288*1da177e4SLinus Torvalds  *
289*1da177e4SLinus Torvalds  *	This call allocates interrupt resources and enables the
290*1da177e4SLinus Torvalds  *	interrupt line and IRQ handling. From the point this
291*1da177e4SLinus Torvalds  *	call is made your handler function may be invoked. Since
292*1da177e4SLinus Torvalds  *	your handler function must clear any interrupt the board
293*1da177e4SLinus Torvalds  *	raises, you must take care both to initialise your hardware
294*1da177e4SLinus Torvalds  *	and to set up the interrupt handler in the right order.
295*1da177e4SLinus Torvalds  *
296*1da177e4SLinus Torvalds  *	Dev_id must be globally unique. Normally the address of the
297*1da177e4SLinus Torvalds  *	device data structure is used as the cookie. Since the handler
298*1da177e4SLinus Torvalds  *	receives this value it makes sense to use it.
299*1da177e4SLinus Torvalds  *
300*1da177e4SLinus Torvalds  *	If your interrupt is shared you must pass a non NULL dev_id
301*1da177e4SLinus Torvalds  *	as this is required when freeing the interrupt.
302*1da177e4SLinus Torvalds  *
303*1da177e4SLinus Torvalds  *	Flags:
304*1da177e4SLinus Torvalds  *
305*1da177e4SLinus Torvalds  *	SA_SHIRQ		Interrupt is shared
306*1da177e4SLinus Torvalds  *	SA_INTERRUPT		Disable local interrupts while processing
307*1da177e4SLinus Torvalds  *	SA_SAMPLE_RANDOM	The interrupt can be used for entropy
308*1da177e4SLinus Torvalds  *
309*1da177e4SLinus Torvalds  */
310*1da177e4SLinus Torvalds int request_irq(unsigned int irq,
311*1da177e4SLinus Torvalds 		irqreturn_t (*handler)(int, void *, struct pt_regs *),
312*1da177e4SLinus Torvalds 		unsigned long irqflags, const char * devname, void *dev_id)
313*1da177e4SLinus Torvalds {
314*1da177e4SLinus Torvalds 	struct irqaction * action;
315*1da177e4SLinus Torvalds 	int retval;
316*1da177e4SLinus Torvalds 
317*1da177e4SLinus Torvalds 	/*
318*1da177e4SLinus Torvalds 	 * Sanity-check: shared interrupts must pass in a real dev-ID,
319*1da177e4SLinus Torvalds 	 * otherwise we'll have trouble later trying to figure out
320*1da177e4SLinus Torvalds 	 * which interrupt is which (messes up the interrupt freeing
321*1da177e4SLinus Torvalds 	 * logic etc).
322*1da177e4SLinus Torvalds 	 */
323*1da177e4SLinus Torvalds 	if ((irqflags & SA_SHIRQ) && !dev_id)
324*1da177e4SLinus Torvalds 		return -EINVAL;
325*1da177e4SLinus Torvalds 	if (irq >= NR_IRQS)
326*1da177e4SLinus Torvalds 		return -EINVAL;
327*1da177e4SLinus Torvalds 	if (!handler)
328*1da177e4SLinus Torvalds 		return -EINVAL;
329*1da177e4SLinus Torvalds 
330*1da177e4SLinus Torvalds 	action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC);
331*1da177e4SLinus Torvalds 	if (!action)
332*1da177e4SLinus Torvalds 		return -ENOMEM;
333*1da177e4SLinus Torvalds 
334*1da177e4SLinus Torvalds 	action->handler = handler;
335*1da177e4SLinus Torvalds 	action->flags = irqflags;
336*1da177e4SLinus Torvalds 	cpus_clear(action->mask);
337*1da177e4SLinus Torvalds 	action->name = devname;
338*1da177e4SLinus Torvalds 	action->next = NULL;
339*1da177e4SLinus Torvalds 	action->dev_id = dev_id;
340*1da177e4SLinus Torvalds 
341*1da177e4SLinus Torvalds 	retval = setup_irq(irq, action);
342*1da177e4SLinus Torvalds 	if (retval)
343*1da177e4SLinus Torvalds 		kfree(action);
344*1da177e4SLinus Torvalds 
345*1da177e4SLinus Torvalds 	return retval;
346*1da177e4SLinus Torvalds }
347*1da177e4SLinus Torvalds 
348*1da177e4SLinus Torvalds EXPORT_SYMBOL(request_irq);
349*1da177e4SLinus Torvalds 
350