ia64/xen-unstable

changeset 3061:911ddd7a09c1

bitkeeper revision 1.1159.179.11 (419dfcf5D6fLg4ewlxJ8pXQaNbvyLw)

manage.c, irq.h:
Add teardown_irq to uninstall irq's installed with setup_irq.
ctrl_if.c:
Use teardown_irq instead of SA_STATIC_ACTION.
manage.c, irq.h:
new file
author cl349@arcadians.cl.cam.ac.uk
date Fri Nov 19 14:02:29 2004 +0000 (2004-11-19)
parents f81923f8591f
children 38c450a5a8a3
files .rootkeys linux-2.6.10-rc2-xen-sparse/arch/xen/kernel/ctrl_if.c linux-2.6.10-rc2-xen-sparse/include/linux/irq.h linux-2.6.10-rc2-xen-sparse/kernel/irq/manage.c
line diff
     1.1 --- a/.rootkeys	Fri Nov 19 13:31:36 2004 +0000
     1.2 +++ b/.rootkeys	Fri Nov 19 14:02:29 2004 +0000
     1.3 @@ -245,7 +245,9 @@ 40f5623cndVUFlkxpf7Lfx7xu8madQ linux-2.6
     1.4  4122466356eIBnC9ot44WSVVIFyhQA linux-2.6.10-rc2-xen-sparse/include/asm-xen/queues.h
     1.5  3f689063BoW-HWV3auUJ-OqXfcGArw linux-2.6.10-rc2-xen-sparse/include/asm-xen/xen_proc.h
     1.6  419b4e93z2S0gR17XTy8wg09JEwAhg linux-2.6.10-rc2-xen-sparse/include/linux/gfp.h
     1.7 +419dfc609zbti8rqL60tL2dHXQ_rvQ linux-2.6.10-rc2-xen-sparse/include/linux/irq.h
     1.8  4124f66f4NaKNa0xPiGGykn9QaZk3w linux-2.6.10-rc2-xen-sparse/include/linux/skbuff.h
     1.9 +419dfc6awx7w88wk6cG9P3mPidX6LQ linux-2.6.10-rc2-xen-sparse/kernel/irq/manage.c
    1.10  40f56a0ddHCSs3501MY4hRf22tctOw linux-2.6.10-rc2-xen-sparse/mkbuildtree
    1.11  412f46c0LJuKAgSPGoC0Z1DEkLfuLA linux-2.6.10-rc2-xen-sparse/mm/memory.c
    1.12  410a94a4KT6I6X0LVc7djB39tRDp4g linux-2.6.10-rc2-xen-sparse/mm/page_alloc.c
     2.1 --- a/linux-2.6.10-rc2-xen-sparse/arch/xen/kernel/ctrl_if.c	Fri Nov 19 13:31:36 2004 +0000
     2.2 +++ b/linux-2.6.10-rc2-xen-sparse/arch/xen/kernel/ctrl_if.c	Fri Nov 19 14:02:29 2004 +0000
     2.3 @@ -462,7 +462,7 @@ ctrl_if_unregister_receiver(
     2.4  
     2.5  void ctrl_if_suspend(void)
     2.6  {
     2.7 -    free_irq(ctrl_if_irq, NULL);
     2.8 +    teardown_irq(ctrl_if_irq, &ctrl_if_irq_action);
     2.9      unbind_evtchn_from_irq(ctrl_if_evtchn);
    2.10  }
    2.11  
    2.12 @@ -496,11 +496,9 @@ void ctrl_if_resume(void)
    2.13      ctrl_if_evtchn = xen_start_info.domain_controller_evtchn;
    2.14      ctrl_if_irq    = bind_evtchn_to_irq(ctrl_if_evtchn);
    2.15  
    2.16 -#define SA_STATIC_ACTION 0x01000000 /* so that free_irq() doesn't do kfree() */
    2.17      memset(&ctrl_if_irq_action, 0, sizeof(ctrl_if_irq_action));
    2.18      ctrl_if_irq_action.handler = ctrl_if_interrupt;
    2.19      ctrl_if_irq_action.name    = "ctrl-if";
    2.20 -    ctrl_if_irq_action.flags   = SA_STATIC_ACTION;
    2.21      (void)setup_irq(ctrl_if_irq, &ctrl_if_irq_action);
    2.22  }
    2.23  
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/linux-2.6.10-rc2-xen-sparse/include/linux/irq.h	Fri Nov 19 14:02:29 2004 +0000
     3.3 @@ -0,0 +1,97 @@
     3.4 +#ifndef __irq_h
     3.5 +#define __irq_h
     3.6 +
     3.7 +/*
     3.8 + * Please do not include this file in generic code.  There is currently
     3.9 + * no requirement for any architecture to implement anything held
    3.10 + * within this file.
    3.11 + *
    3.12 + * Thanks. --rmk
    3.13 + */
    3.14 +
    3.15 +#include <linux/config.h>
    3.16 +
    3.17 +#if !defined(CONFIG_ARCH_S390)
    3.18 +
    3.19 +#include <linux/linkage.h>
    3.20 +#include <linux/cache.h>
    3.21 +#include <linux/spinlock.h>
    3.22 +#include <linux/cpumask.h>
    3.23 +
    3.24 +#include <asm/irq.h>
    3.25 +#include <asm/ptrace.h>
    3.26 +
    3.27 +/*
    3.28 + * IRQ line status.
    3.29 + */
    3.30 +#define IRQ_INPROGRESS	1	/* IRQ handler active - do not enter! */
    3.31 +#define IRQ_DISABLED	2	/* IRQ disabled - do not enter! */
    3.32 +#define IRQ_PENDING	4	/* IRQ pending - replay on enable */
    3.33 +#define IRQ_REPLAY	8	/* IRQ has been replayed but not acked yet */
    3.34 +#define IRQ_AUTODETECT	16	/* IRQ is being autodetected */
    3.35 +#define IRQ_WAITING	32	/* IRQ not yet seen - for autodetection */
    3.36 +#define IRQ_LEVEL	64	/* IRQ level triggered */
    3.37 +#define IRQ_MASKED	128	/* IRQ masked - shouldn't be seen again */
    3.38 +#define IRQ_PER_CPU	256	/* IRQ is per CPU */
    3.39 +
    3.40 +/*
    3.41 + * Interrupt controller descriptor. This is all we need
    3.42 + * to describe about the low-level hardware. 
    3.43 + */
    3.44 +struct hw_interrupt_type {
    3.45 +	const char * typename;
    3.46 +	unsigned int (*startup)(unsigned int irq);
    3.47 +	void (*shutdown)(unsigned int irq);
    3.48 +	void (*enable)(unsigned int irq);
    3.49 +	void (*disable)(unsigned int irq);
    3.50 +	void (*ack)(unsigned int irq);
    3.51 +	void (*end)(unsigned int irq);
    3.52 +	void (*set_affinity)(unsigned int irq, cpumask_t dest);
    3.53 +};
    3.54 +
    3.55 +typedef struct hw_interrupt_type  hw_irq_controller;
    3.56 +
    3.57 +/*
    3.58 + * This is the "IRQ descriptor", which contains various information
    3.59 + * about the irq, including what kind of hardware handling it has,
    3.60 + * whether it is disabled etc etc.
    3.61 + *
    3.62 + * Pad this out to 32 bytes for cache and indexing reasons.
    3.63 + */
    3.64 +typedef struct irq_desc {
    3.65 +	unsigned int status;		/* IRQ status */
    3.66 +	hw_irq_controller *handler;
    3.67 +	struct irqaction *action;	/* IRQ action list */
    3.68 +	unsigned int depth;		/* nested irq disables */
    3.69 +	unsigned int irq_count;		/* For detecting broken interrupts */
    3.70 +	unsigned int irqs_unhandled;
    3.71 +	spinlock_t lock;
    3.72 +} ____cacheline_aligned irq_desc_t;
    3.73 +
    3.74 +extern irq_desc_t irq_desc [NR_IRQS];
    3.75 +
    3.76 +#include <asm/hw_irq.h> /* the arch dependent stuff */
    3.77 +
    3.78 +extern int setup_irq(unsigned int irq, struct irqaction * new);
    3.79 +extern int teardown_irq(unsigned int irq, struct irqaction * old);
    3.80 +
    3.81 +#ifdef CONFIG_GENERIC_HARDIRQS
    3.82 +extern cpumask_t irq_affinity[NR_IRQS];
    3.83 +extern int no_irq_affinity;
    3.84 +extern int noirqdebug_setup(char *str);
    3.85 +
    3.86 +extern fastcall int handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
    3.87 +				       struct irqaction *action);
    3.88 +extern fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs);
    3.89 +extern void note_interrupt(unsigned int irq, irq_desc_t *desc, int action_ret);
    3.90 +extern void report_bad_irq(unsigned int irq, irq_desc_t *desc, int action_ret);
    3.91 +extern int can_request_irq(unsigned int irq, unsigned long irqflags);
    3.92 +
    3.93 +extern void init_irq_proc(void);
    3.94 +#endif
    3.95 +
    3.96 +extern hw_irq_controller no_irq_type;  /* needed in every arch ? */
    3.97 +
    3.98 +#endif
    3.99 +
   3.100 +#endif /* __irq_h */
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/linux-2.6.10-rc2-xen-sparse/kernel/irq/manage.c	Fri Nov 19 14:02:29 2004 +0000
     4.3 @@ -0,0 +1,376 @@
     4.4 +/*
     4.5 + * linux/kernel/irq/manage.c
     4.6 + *
     4.7 + * Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar
     4.8 + *
     4.9 + * This file contains driver APIs to the irq subsystem.
    4.10 + */
    4.11 +
    4.12 +#include <linux/irq.h>
    4.13 +#include <linux/module.h>
    4.14 +#include <linux/random.h>
    4.15 +#include <linux/interrupt.h>
    4.16 +
    4.17 +#include "internals.h"
    4.18 +
    4.19 +#ifdef CONFIG_SMP
    4.20 +
    4.21 +/**
    4.22 + *	synchronize_irq - wait for pending IRQ handlers (on other CPUs)
    4.23 + *
    4.24 + *	This function waits for any pending IRQ handlers for this interrupt
    4.25 + *	to complete before returning. If you use this function while
    4.26 + *	holding a resource the IRQ handler may need you will deadlock.
    4.27 + *
    4.28 + *	This function may be called - with care - from IRQ context.
    4.29 + */
    4.30 +void synchronize_irq(unsigned int irq)
    4.31 +{
    4.32 +	struct irq_desc *desc = irq_desc + irq;
    4.33 +
    4.34 +	while (desc->status & IRQ_INPROGRESS)
    4.35 +		cpu_relax();
    4.36 +}
    4.37 +
    4.38 +EXPORT_SYMBOL(synchronize_irq);
    4.39 +
    4.40 +#endif
    4.41 +
    4.42 +/**
    4.43 + *	disable_irq_nosync - disable an irq without waiting
    4.44 + *	@irq: Interrupt to disable
    4.45 + *
    4.46 + *	Disable the selected interrupt line.  Disables and Enables are
    4.47 + *	nested.
    4.48 + *	Unlike disable_irq(), this function does not ensure existing
    4.49 + *	instances of the IRQ handler have completed before returning.
    4.50 + *
    4.51 + *	This function may be called from IRQ context.
    4.52 + */
    4.53 +void disable_irq_nosync(unsigned int irq)
    4.54 +{
    4.55 +	irq_desc_t *desc = irq_desc + irq;
    4.56 +	unsigned long flags;
    4.57 +
    4.58 +	spin_lock_irqsave(&desc->lock, flags);
    4.59 +	if (!desc->depth++) {
    4.60 +		desc->status |= IRQ_DISABLED;
    4.61 +		desc->handler->disable(irq);
    4.62 +	}
    4.63 +	spin_unlock_irqrestore(&desc->lock, flags);
    4.64 +}
    4.65 +
    4.66 +EXPORT_SYMBOL(disable_irq_nosync);
    4.67 +
    4.68 +/**
    4.69 + *	disable_irq - disable an irq and wait for completion
    4.70 + *	@irq: Interrupt to disable
    4.71 + *
    4.72 + *	Disable the selected interrupt line.  Enables and Disables are
    4.73 + *	nested.
    4.74 + *	This function waits for any pending IRQ handlers for this interrupt
    4.75 + *	to complete before returning. If you use this function while
    4.76 + *	holding a resource the IRQ handler may need you will deadlock.
    4.77 + *
    4.78 + *	This function may be called - with care - from IRQ context.
    4.79 + */
    4.80 +void disable_irq(unsigned int irq)
    4.81 +{
    4.82 +	irq_desc_t *desc = irq_desc + irq;
    4.83 +
    4.84 +	disable_irq_nosync(irq);
    4.85 +	if (desc->action)
    4.86 +		synchronize_irq(irq);
    4.87 +}
    4.88 +
    4.89 +EXPORT_SYMBOL(disable_irq);
    4.90 +
    4.91 +/**
    4.92 + *	enable_irq - enable handling of an irq
    4.93 + *	@irq: Interrupt to enable
    4.94 + *
    4.95 + *	Undoes the effect of one call to disable_irq().  If this
    4.96 + *	matches the last disable, processing of interrupts on this
    4.97 + *	IRQ line is re-enabled.
    4.98 + *
    4.99 + *	This function may be called from IRQ context.
   4.100 + */
   4.101 +void enable_irq(unsigned int irq)
   4.102 +{
   4.103 +	irq_desc_t *desc = irq_desc + irq;
   4.104 +	unsigned long flags;
   4.105 +
   4.106 +	spin_lock_irqsave(&desc->lock, flags);
   4.107 +	switch (desc->depth) {
   4.108 +	case 0:
   4.109 +		WARN_ON(1);
   4.110 +		break;
   4.111 +	case 1: {
   4.112 +		unsigned int status = desc->status & ~IRQ_DISABLED;
   4.113 +
   4.114 +		desc->status = status;
   4.115 +		if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
   4.116 +			desc->status = status | IRQ_REPLAY;
   4.117 +			hw_resend_irq(desc->handler,irq);
   4.118 +		}
   4.119 +		desc->handler->enable(irq);
   4.120 +		/* fall-through */
   4.121 +	}
   4.122 +	default:
   4.123 +		desc->depth--;
   4.124 +	}
   4.125 +	spin_unlock_irqrestore(&desc->lock, flags);
   4.126 +}
   4.127 +
   4.128 +EXPORT_SYMBOL(enable_irq);
   4.129 +
   4.130 +/*
   4.131 + * Internal function that tells the architecture code whether a
   4.132 + * particular irq has been exclusively allocated or is available
   4.133 + * for driver use.
   4.134 + */
   4.135 +int can_request_irq(unsigned int irq, unsigned long irqflags)
   4.136 +{
   4.137 +	struct irqaction *action;
   4.138 +
   4.139 +	if (irq >= NR_IRQS)
   4.140 +		return 0;
   4.141 +
   4.142 +	action = irq_desc[irq].action;
   4.143 +	if (action)
   4.144 +		if (irqflags & action->flags & SA_SHIRQ)
   4.145 +			action = NULL;
   4.146 +
   4.147 +	return !action;
   4.148 +}
   4.149 +
   4.150 +/*
   4.151 + * Internal function to register an irqaction - typically used to
   4.152 + * allocate special interrupts that are part of the architecture.
   4.153 + */
   4.154 +int setup_irq(unsigned int irq, struct irqaction * new)
   4.155 +{
   4.156 +	struct irq_desc *desc = irq_desc + irq;
   4.157 +	struct irqaction *old, **p;
   4.158 +	unsigned long flags;
   4.159 +	int shared = 0;
   4.160 +
   4.161 +	if (desc->handler == &no_irq_type)
   4.162 +		return -ENOSYS;
   4.163 +	/*
   4.164 +	 * Some drivers like serial.c use request_irq() heavily,
   4.165 +	 * so we have to be careful not to interfere with a
   4.166 +	 * running system.
   4.167 +	 */
   4.168 +	if (new->flags & SA_SAMPLE_RANDOM) {
   4.169 +		/*
   4.170 +		 * This function might sleep, we want to call it first,
   4.171 +		 * outside of the atomic block.
   4.172 +		 * Yes, this might clear the entropy pool if the wrong
   4.173 +		 * driver is attempted to be loaded, without actually
   4.174 +		 * installing a new handler, but is this really a problem,
   4.175 +		 * only the sysadmin is able to do this.
   4.176 +		 */
   4.177 +		rand_initialize_irq(irq);
   4.178 +	}
   4.179 +
   4.180 +	/*
   4.181 +	 * The following block of code has to be executed atomically
   4.182 +	 */
   4.183 +	spin_lock_irqsave(&desc->lock,flags);
   4.184 +	p = &desc->action;
   4.185 +	if ((old = *p) != NULL) {
   4.186 +		/* Can't share interrupts unless both agree to */
   4.187 +		if (!(old->flags & new->flags & SA_SHIRQ)) {
   4.188 +			spin_unlock_irqrestore(&desc->lock,flags);
   4.189 +			return -EBUSY;
   4.190 +		}
   4.191 +
   4.192 +		/* add new interrupt at end of irq queue */
   4.193 +		do {
   4.194 +			p = &old->next;
   4.195 +			old = *p;
   4.196 +		} while (old);
   4.197 +		shared = 1;
   4.198 +	}
   4.199 +
   4.200 +	*p = new;
   4.201 +
   4.202 +	if (!shared) {
   4.203 +		desc->depth = 0;
   4.204 +		desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT |
   4.205 +				  IRQ_WAITING | IRQ_INPROGRESS);
   4.206 +		if (desc->handler->startup)
   4.207 +			desc->handler->startup(irq);
   4.208 +		else
   4.209 +			desc->handler->enable(irq);
   4.210 +	}
   4.211 +	spin_unlock_irqrestore(&desc->lock,flags);
   4.212 +
   4.213 +	new->irq = irq;
   4.214 +	register_irq_proc(irq);
   4.215 +	new->dir = NULL;
   4.216 +	register_handler_proc(irq, new);
   4.217 +
   4.218 +	return 0;
   4.219 +}
   4.220 +
   4.221 +/*
   4.222 + * Internal function to unregister an irqaction - typically used to
   4.223 + * deallocate special interrupts that are part of the architecture.
   4.224 + */
   4.225 +int teardown_irq(unsigned int irq, struct irqaction * old)
   4.226 +{
   4.227 +	struct irq_desc *desc;
   4.228 +	struct irqaction **p;
   4.229 +	unsigned long flags;
   4.230 +
   4.231 +	if (irq >= NR_IRQS)
   4.232 +		return -ENOENT;
   4.233 +
   4.234 +	desc = irq_desc + irq;
   4.235 +	spin_lock_irqsave(&desc->lock,flags);
   4.236 +	p = &desc->action;
   4.237 +	for (;;) {
   4.238 +		struct irqaction * action = *p;
   4.239 +
   4.240 +		if (action) {
   4.241 +			struct irqaction **pp = p;
   4.242 +
   4.243 +			p = &action->next;
   4.244 +			if (action != old)
   4.245 +				continue;
   4.246 +
   4.247 +			/* Found it - now remove it from the list of entries */
   4.248 +			*pp = action->next;
   4.249 +			if (!desc->action) {
   4.250 +				desc->status |= IRQ_DISABLED;
   4.251 +				if (desc->handler->shutdown)
   4.252 +					desc->handler->shutdown(irq);
   4.253 +				else
   4.254 +					desc->handler->disable(irq);
   4.255 +			}
   4.256 +			spin_unlock_irqrestore(&desc->lock,flags);
   4.257 +			unregister_handler_proc(irq, action);
   4.258 +
   4.259 +			/* Make sure it's not being used on another CPU */
   4.260 +			synchronize_irq(irq);
   4.261 +			return 0;
   4.262 +		}
   4.263 +		printk(KERN_ERR "Trying to teardown free IRQ%d\n",irq);
   4.264 +		spin_unlock_irqrestore(&desc->lock,flags);
   4.265 +		return -ENOENT;
   4.266 +	}
   4.267 +}
   4.268 +
   4.269 +/**
   4.270 + *	free_irq - free an interrupt
   4.271 + *	@irq: Interrupt line to free
   4.272 + *	@dev_id: Device identity to free
   4.273 + *
   4.274 + *	Remove an interrupt handler. The handler is removed and if the
   4.275 + *	interrupt line is no longer in use by any driver it is disabled.
   4.276 + *	On a shared IRQ the caller must ensure the interrupt is disabled
   4.277 + *	on the card it drives before calling this function. The function
   4.278 + *	does not return until any executing interrupts for this IRQ
   4.279 + *	have completed.
   4.280 + *
   4.281 + *	This function must not be called from interrupt context.
   4.282 + */
   4.283 +void free_irq(unsigned int irq, void *dev_id)
   4.284 +{
   4.285 +	struct irq_desc *desc;
   4.286 +	struct irqaction *action;
   4.287 +	unsigned long flags;
   4.288 +
   4.289 +	if (irq >= NR_IRQS)
   4.290 +		return;
   4.291 +
   4.292 +	desc = irq_desc + irq;
   4.293 +	spin_lock_irqsave(&desc->lock,flags);
   4.294 +	for (action = desc->action; action != NULL; action = action->next) {
   4.295 +		if (action->dev_id != dev_id)
   4.296 +			continue;
   4.297 +
   4.298 +		spin_unlock_irqrestore(&desc->lock,flags);
   4.299 +
   4.300 +		if (teardown_irq(irq, action) == 0)
   4.301 +			kfree(action);
   4.302 +		return;
   4.303 +	}
   4.304 +	printk(KERN_ERR "Trying to free free IRQ%d\n",irq);
   4.305 +	spin_unlock_irqrestore(&desc->lock,flags);
   4.306 +	return;
   4.307 +}
   4.308 +
   4.309 +EXPORT_SYMBOL(free_irq);
   4.310 +
   4.311 +/**
   4.312 + *	request_irq - allocate an interrupt line
   4.313 + *	@irq: Interrupt line to allocate
   4.314 + *	@handler: Function to be called when the IRQ occurs
   4.315 + *	@irqflags: Interrupt type flags
   4.316 + *	@devname: An ascii name for the claiming device
   4.317 + *	@dev_id: A cookie passed back to the handler function
   4.318 + *
   4.319 + *	This call allocates interrupt resources and enables the
   4.320 + *	interrupt line and IRQ handling. From the point this
   4.321 + *	call is made your handler function may be invoked. Since
   4.322 + *	your handler function must clear any interrupt the board
   4.323 + *	raises, you must take care both to initialise your hardware
   4.324 + *	and to set up the interrupt handler in the right order.
   4.325 + *
   4.326 + *	Dev_id must be globally unique. Normally the address of the
   4.327 + *	device data structure is used as the cookie. Since the handler
   4.328 + *	receives this value it makes sense to use it.
   4.329 + *
   4.330 + *	If your interrupt is shared you must pass a non NULL dev_id
   4.331 + *	as this is required when freeing the interrupt.
   4.332 + *
   4.333 + *	Flags:
   4.334 + *
   4.335 + *	SA_SHIRQ		Interrupt is shared
   4.336 + *	SA_INTERRUPT		Disable local interrupts while processing
   4.337 + *	SA_SAMPLE_RANDOM	The interrupt can be used for entropy
   4.338 + *
   4.339 + */
   4.340 +int request_irq(unsigned int irq,
   4.341 +		irqreturn_t (*handler)(int, void *, struct pt_regs *),
   4.342 +		unsigned long irqflags, const char * devname, void *dev_id)
   4.343 +{
   4.344 +	struct irqaction * action;
   4.345 +	int retval;
   4.346 +
   4.347 +	/*
   4.348 +	 * Sanity-check: shared interrupts must pass in a real dev-ID,
   4.349 +	 * otherwise we'll have trouble later trying to figure out
   4.350 +	 * which interrupt is which (messes up the interrupt freeing
   4.351 +	 * logic etc).
   4.352 +	 */
   4.353 +	if ((irqflags & SA_SHIRQ) && !dev_id)
   4.354 +		return -EINVAL;
   4.355 +	if (irq >= NR_IRQS)
   4.356 +		return -EINVAL;
   4.357 +	if (!handler)
   4.358 +		return -EINVAL;
   4.359 +
   4.360 +	action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC);
   4.361 +	if (!action)
   4.362 +		return -ENOMEM;
   4.363 +
   4.364 +	action->handler = handler;
   4.365 +	action->flags = irqflags;
   4.366 +	cpus_clear(action->mask);
   4.367 +	action->name = devname;
   4.368 +	action->next = NULL;
   4.369 +	action->dev_id = dev_id;
   4.370 +
   4.371 +	retval = setup_irq(irq, action);
   4.372 +	if (retval)
   4.373 +		kfree(action);
   4.374 +
   4.375 +	return retval;
   4.376 +}
   4.377 +
   4.378 +EXPORT_SYMBOL(request_irq);
   4.379 +