中断之中断请求队列的初始化

来源:互联网 发布:蒙特卡洛算法数学建模 编辑:程序博客网 时间:2024/04/30 00:51

参考文章:http://bbs.chinaunix.net/thread-3566316-1-1.html

参考文章:http://www.linuxidc.com/Linux/2011-02/32129.htm

在“初始化中断向量表”的博文中,我们留下了一个问题,就是

void __init native_init_IRQ(void){    int i;    /* Execute any quirks before the call gates are initialised: */    x86_init.irqs.pre_vector_init(); //调用 init_ISA_irqs ,我们将在“中断队列初始化”的博文中详述    .......}

/* * The platform setup functions are preset with the default functions * for standard PC hardware. */struct x86_init_ops x86_init __initdata = {
。。。。。。
.irqs = {.pre_vector_init = init_ISA_irqs,.intr_init = native_init_IRQ,.trap_init = x86_init_noop,},
。。。。。。
}

因此,最终调用init_ISA_irqs,这是个异常重要的函数,我们的中断队列初始化的工作就主要由它来完成。

在讲解init_ISA_irqs之前,我们先来看一些重要的数据结构:

/* * Core internal functions to deal with irq descriptors * * This include will move to kernel/irq once we cleaned up the tree. * For now it's included from <linux/irq.h> */struct irq_affinity_notify;struct proc_dir_entry;struct timer_rand_state;/** * struct irq_desc - interrupt descriptor * @irq_data:per irq and chip data passed down to chip functions * @timer_rand_state:pointer to timer rand state struct * @kstat_irqs:irq stats per cpu * @handle_irq:highlevel irq-events handler * @preflow_handler:handler called before the flow handler (currently used by sparc) * @action:the irq action chain * @status:status information * @core_internal_state__do_not_mess_with_it: core internal status information * @depth:disable-depth, for nested irq_disable() calls * @wake_depth:enable depth, for multiple irq_set_irq_wake() callers * @irq_count:stats field to detect stalled irqs * @last_unhandled:aging timer for unhandled count * @irqs_unhandled:stats field for spurious unhandled interrupts * @lock:locking for SMP * @affinity_hint:hint to user space for preferred irq affinity * @affinity_notify:context for notification of affinity changes * @pending_mask:pending rebalanced interrupts * @threads_oneshot:bitfield to handle shared oneshot threads * @threads_active:number of irqaction threads currently running * @wait_for_threads:wait queue for sync_irq to wait for threaded handlers * @dir:/proc/irq/ procfs entry * @name:flow handler name for /proc/interrupts output */struct irq_desc {struct irq_datairq_data;struct timer_rand_state *timer_rand_state;unsigned int __percpu*kstat_irqs;irq_flow_handler_thandle_irq; //指向一些函数指针,用于该队列,或者说该共用“中断通道”的控制(并不是对具体中断源的服务)。#ifdef CONFIG_IRQ_PREFLOW_FASTEOIirq_preflow_handler_tpreflow_handler;#endifstruct irqaction*action;/* IRQ action list 由中断服务程序构成的单链表队列*/ unsigned intstatus_use_accessors;unsigned intcore_internal_state__do_not_mess_with_it;unsigned intdepth;/* nested irq disables */unsigned intwake_depth;/* nested wake enables */unsigned intirq_count;/* For detecting broken IRQs */unsigned longlast_unhandled;/* Aging timer for unhandled count */unsigned intirqs_unhandled;raw_spinlock_tlock;#ifdef CONFIG_SMPconst struct cpumask*affinity_hint;struct irq_affinity_notify *affinity_notify;#ifdef CONFIG_GENERIC_PENDING_IRQcpumask_var_tpending_mask;#endif#endifunsigned longthreads_oneshot;atomic_tthreads_active;wait_queue_head_t       wait_for_threads;#ifdef CONFIG_PROC_FSstruct proc_dir_entry*dir;#endifconst char*name;} ____cacheline_internodealigned_in_smp;

这个数据结构中的第一字段需要给予特殊的关注,因为这相比于2.4有很大的区别:

/** * struct irq_data - per irq and irq chip data passed down to chip functions * @irq:interrupt number * @node:node index useful for balancing * @state_use_accessors: status information for irq chip functions. *Use accessor functions to deal with it * @chip:low level interrupt hardware access * @handler_data:per-IRQ data for the irq_chip methods * @chip_data:platform-specific per-chip private data for the chip *methods, to allow shared chip implementations * @msi_desc:MSI descriptor * @affinity:IRQ affinity on SMP * * The fields here need to overlay the ones in irq_desc until we * cleaned up the direct references and switched everything over to * irq_data. */struct irq_data {unsigned intirq;unsigned intnode;unsigned intstate_use_accessors;struct irq_chip*chip;void*handler_data;void*chip_data;struct msi_desc*msi_desc;#ifdef CONFIG_SMPcpumask_var_taffinity;#endif};

在这个结构中,我们需要关注字段*chip:

/** * struct irq_chip - hardware interrupt chip descriptor * * @name:name for /proc/interrupts * @irq_startup:start up the interrupt (defaults to ->enable if NULL) * @irq_shutdown:shut down the interrupt (defaults to ->disable if NULL) * @irq_enable:enable the interrupt (defaults to chip->unmask if NULL) * @irq_disable:disable the interrupt * @irq_ack:start of a new interrupt * @irq_mask:mask an interrupt source * @irq_mask_ack:ack and mask an interrupt source * @irq_unmask:unmask an interrupt source * @irq_eoi:end of interrupt * @irq_set_affinity:set the CPU affinity on SMP machines * @irq_retrigger:resend an IRQ to the CPU * @irq_set_type:set the flow type (IRQ_TYPE_LEVEL/etc.) of an IRQ * @irq_set_wake:enable/disable power-management wake-on of an IRQ * @irq_bus_lock:function to lock access to slow bus (i2c) chips * @irq_bus_sync_unlock:function to sync and unlock slow bus (i2c) chips * @irq_cpu_online:configure an interrupt source for a secondary CPU * @irq_cpu_offline:un-configure an interrupt source for a secondary CPU * @irq_suspend:function called from core code on suspend once per chip * @irq_resume:function called from core code on resume once per chip * @irq_pm_shutdown:function called from core code on shutdown once per chip * @irq_print_chip:optional to print special chip info in show_interrupts * @flags:chip specific flags * * @release:release function solely used by UML */struct irq_chip {const char*name;unsigned int(*irq_startup)(struct irq_data *data);void(*irq_shutdown)(struct irq_data *data);void(*irq_enable)(struct irq_data *data);void(*irq_disable)(struct irq_data *data);void(*irq_ack)(struct irq_data *data);void(*irq_mask)(struct irq_data *data);void(*irq_mask_ack)(struct irq_data *data);void(*irq_unmask)(struct irq_data *data);void(*irq_eoi)(struct irq_data *data);int(*irq_set_affinity)(struct irq_data *data, const struct cpumask *dest, bool force);int(*irq_retrigger)(struct irq_data *data);int(*irq_set_type)(struct irq_data *data, unsigned int flow_type);int(*irq_set_wake)(struct irq_data *data, unsigned int on);void(*irq_bus_lock)(struct irq_data *data);void(*irq_bus_sync_unlock)(struct irq_data *data);void(*irq_cpu_online)(struct irq_data *data);void(*irq_cpu_offline)(struct irq_data *data);void(*irq_suspend)(struct irq_data *data);void(*irq_resume)(struct irq_data *data);void(*irq_pm_shutdown)(struct irq_data *data);void(*irq_print_chip)(struct irq_data *data, struct seq_file *p);unsigned longflags;/* Currently used only by UML, might disappear one day.*/#ifdef CONFIG_IRQ_RELEASE_METHODvoid(*release)(unsigned int irq, void *dev_id);#endif};
这个结构体和2.4内核中的hw_interrupt_type()功能类似,其初始化是在init_ISA_irqs中完成的:
void __init init_ISA_irqs(void){struct irq_chip *chip = legacy_pic->chip;const char *name = chip->name;int i;#if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC)init_bsp_APIC();#endiflegacy_pic->init(0);for (i = 0; i < legacy_pic->nr_legacy_irqs; i++)irq_set_chip_and_handler_name(i, chip, handle_level_irq, name);}

其中,legacy_pic是全局变量:struct legacy_pic *legacy_pic = &default_legacy_pic;

struct legacy_pic default_legacy_pic = {.nr_legacy_irqs = NR_IRQS_LEGACY,  // = 16.chip  = &i8259A_chip,.mask = mask_8259A_irq,.unmask = unmask_8259A_irq,.mask_all = mask_8259A,.restore_mask = unmask_8259A,.init = init_8259A,.irq_pending = i8259A_irq_pending,.make_irq = make_8259A_irq,}; 

终于找到我们要找的函数了——init8259A(),我们并不会详细的解释这个函数,因为它要求对8259有比较深入的了解,对于这个函数,浏览一下,知道大概的意思即可。:

static void init_8259A(int auto_eoi){unsigned long flags;i8259A_auto_eoi = auto_eoi;raw_spin_lock_irqsave(&i8259A_lock, flags);outb(0xff, PIC_MASTER_IMR);/* mask all of 8259A-1 */outb(0xff, PIC_SLAVE_IMR);/* mask all of 8259A-2 *//* * outb_pic - this has to work on a wide range of PC hardware. */outb_pic(0x11, PIC_MASTER_CMD);/* ICW1: select 8259A-1 init *//* ICW2: 8259A-1 IR0-7 mapped to 0x30-0x37 on x86-64,   to 0x20-0x27 on i386 */outb_pic(IRQ0_VECTOR, PIC_MASTER_IMR);/* 8259A-1 (the master) has a slave on IR2 */outb_pic(1U << PIC_CASCADE_IR, PIC_MASTER_IMR);if (auto_eoi)/* master does Auto EOI */outb_pic(MASTER_ICW4_DEFAULT | PIC_ICW4_AEOI, PIC_MASTER_IMR);else/* master expects normal EOI */outb_pic(MASTER_ICW4_DEFAULT, PIC_MASTER_IMR);outb_pic(0x11, PIC_SLAVE_CMD);/* ICW1: select 8259A-2 init *//* ICW2: 8259A-2 IR0-7 mapped to IRQ8_VECTOR */outb_pic(IRQ8_VECTOR, PIC_SLAVE_IMR);/* 8259A-2 is a slave on master's IR2 */outb_pic(PIC_CASCADE_IR, PIC_SLAVE_IMR);/* (slave's support for AEOI in flat mode is to be investigated) */outb_pic(SLAVE_ICW4_DEFAULT, PIC_SLAVE_IMR);if (auto_eoi)/* * In AEOI mode we just have to mask the interrupt * when acking. */i8259A_chip.irq_mask_ack = disable_8259A_irq;elsei8259A_chip.irq_mask_ack = mask_and_ack_8259A;udelay(100);/* wait for 8259A to initialize */outb(cached_master_mask, PIC_MASTER_IMR); /* restore master IRQ mask */outb(cached_slave_mask, PIC_SLAVE_IMR);  /* restore slave IRQ mask */raw_spin_unlock_irqrestore(&i8259A_lock, flags);}

回到init_ISA_irqs中,接下来是:

for (i = 0; i < legacy_pic->nr_legacy_irqs; i++)irq_set_chip_and_handler_name(i, chip, handle_level_irq, name);

简单的说就是,前16个中断请求与其余的中断是不同的,因此handle_irq需要被设置成特定的处理函数,而其余的中断只有在需要的时候才会将其handle_irq函数登记。

前16个中断请求通道IR0~IR15是由中断请求控制器8259A控制的。

下面来看一下具体中断服务程序描述项:

首先让我们回到irq_desc中,来看中断服务程序描述项的数据结构irqaction:

/** * struct irqaction - per interrupt action descriptor * @handler:interrupt handler function * @flags:flags (see IRQF_* above) * @name:name of the device * @dev_id:cookie to identify the device * @next:pointer to the next irqaction for shared interrupts * @irq:interrupt number * @dir:pointer to the proc/irq/NN/name entry * @thread_fn:interrupt handler function for threaded interrupts * @thread:thread pointer for threaded interrupts * @thread_flags:flags related to @thread * @thread_mask:bitmask for keeping track of @thread activity */struct irqaction {irq_handler_t handler;unsigned long flags;void *dev_id;struct irqaction *next;int irq;irq_handler_t thread_fn;struct task_struct *thread;unsigned long thread_flags;unsigned long thread_mask;const char *name;struct proc_dir_entry *dir;} ____cacheline_internodealigned_in_smp;

IDT表初始化完成时,irq->action指向NULL,那么这样是没有意义的,因为不会执行相应的服务程序,而只是在栈中绕了一圈就走了。需要将中断服务程序进行登记之后才会有意义,实现这个功能的函数是request_irq:

应该说request_irq并不属于初始化的工作,前文讲到的前16个中断的服务程序是必须在初始阶段就设置好的,但是对于其他的中断服务程序,只有驱动程序需要处理与中断相关的工作,它才会注册一个中断处理程序,比如:e100驱动中注册其中断处理函数(一下博文参考网站:http://bbs.chinaunix.net/thread-3566316-1-1.html)

static int e100_up(struct nic *nic){        ……        if ((err = request_irq(nic->pdev->irq, e100_intr, IRQF_SHARED,                nic->netdev->name, nic->netdev)))        ……}

好,现在我们来看看request_irq:
static inline int __must_checkrequest_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,        const char *name, void *dev){    return request_threaded_irq(irq, handler, NULL, flags, name, dev);}
/** *request_threaded_irq - allocate an interrupt line *@irq: Interrupt line to allocate 注意,这个irq为中断请求队列的序号,即“中断请求号”,但不是中断号或者中断向量《情景分析》 P *@handler: Function to be called when the IRQ occurs. *  Primary handler for threaded interrupts *  If NULL and thread_fn != NULL the default *  primary handler is installed *@thread_fn: Function called from the irq handler thread *    If NULL, no irq thread is created *@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. * *If you want to set up a threaded irq handler for your device *then you need to supply @handler and @thread_fn. @handler ist *still called in hard interrupt context and has to check *whether the interrupt originates from the device. If yes it *needs to disable the interrupt on the device and return *IRQ_WAKE_THREAD which will wake up the handler thread and run *@thread_fn. This split handler design is necessary to support *shared interrupts. * *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: * *IRQF_SHAREDInterrupt is shared *IRQF_SAMPLE_RANDOMThe interrupt can be used for entropy *IRQF_TRIGGER_*Specify active edge(s) or level * */int request_threaded_irq(unsigned int irq, irq_handler_t handler, irq_handler_t thread_fn, unsigned long irqflags, const char *devname, void *dev_id){struct irqaction *action;struct irq_desc *desc;int retval;/* * 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). */        //共享中断需要给出具体的中断请求号        if ((irqflags & IRQF_SHARED) && !dev_id)return -EINVAL;desc = irq_to_desc(irq); //获取对应的中断描述符——return (irq < NR_IRQS) ? irq_desc + irq : NULL;        if (!desc)return -EINVAL;
/* 关于_IRQ_NOREQUEST When allocating irqs, wait to clear the IRQ_NOREQUEST flag until the host map hook has been called. When freeing irqs, set the IRQ_NOREQUEST flag before calling the host unmap hook.*/
//如果IRQ_NOREQUEST置位,意味着中断不能被请求注册。为什么???if (!irq_settings_can_request(desc)) // return !(desc->status_use_accessors & _IRQ_NOREQUEST);
return -EINVAL;if (!handler) { //注释中解释的很清楚了。if (!thread_fn) //如果中断服务程序是空的,但是线中断服务程序不是空的,那么肯定是出错了。return -EINVAL;handler = irq_default_primary_handler;}action = kzalloc(sizeof(struct irqaction), GFP_KERNEL); if (!action)return -ENOMEM;action->handler = handler;action->thread_fn = thread_fn;action->flags = irqflags;action->name = devname;action->dev_id = dev_id;chip_bus_lock(desc);
  //注册irqaction
retval = __setup_irq(irq, desc, action); //*******************************chip_bus_sync_unlock(desc);if (retval)kfree(action);#ifdef CONFIG_DEBUG_SHIRQ_FIXMEif (!retval && (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 disable the irq to make sure that a 'real' IRQ doesn't * run in parallel with our fake. */unsigned long flags;disable_irq(irq);local_irq_save(flags);handler(irq, dev_id);local_irq_restore(flags);enable_irq(irq);}#endifreturn retval;}我们首先看一下request_threaded_irq()函数中的各个形参(1)irq:表示申请的中断号。(2)handler:表示中断服务例程(3) thread_fn:中断线程化,此处传递的是NULL。NULL表示没有中断线程化。
此参数是最新版本中才出现的。为什么要提出中断线程化?在 Linux 中,中断具有最高的优先级。不论在任何时刻,只要产生中断事件,内核将立即执行相应的中断处理程序,等到所有挂起的中断和软中断处理完毕后才能执行正常的任务,因此有可能造成实时任务得不到及时的处理。中断线程化之后,中断将作为内核线程运行而且被赋予不同的实时优先级,实时任务可以有比中断线程更高的优先级。这样,具有最高优先级的实时任务就能得到优先处理,即使在严重负载下仍有实时性保证。but,并不是所有的中断都可以被线程化,比如时钟中断,主要用来维护系统时间以及定时器等,其中定时器是操作系统的脉搏,一旦被线程化,就有可能被挂起,这样后果将不堪设想,所以不应当被线程化。
(4)irqflags:表示中断标志位。(5)devname:表示请求中断的设备的名称。

(6)dev_id: 对应于request_irq()函数中所传递的第五个参数,可取任意值,但必须唯一能够代表发出中断请求的设备,通常取描述该设备的结构体。 共享中断时所用。

我们来看其中的一个核心函数__setup_irq(),它完成了中断处理函数的注册工作:

/* * Internal function to register an irqaction - typically used to * allocate special interrupts that are part of the architecture. */static int__setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new){struct irqaction *old, **old_ptr;const char *old_name = NULL;unsigned long flags, thread_mask = 0;int ret, nested, shared = 0;cpumask_var_t mask;                //检查中断描述符其及对应用中断控制器if (!desc)return -EINVAL;if (desc->irq_data.chip == &no_irq_chip)return -ENOSYS;/* * Some drivers like serial.c use request_irq() heavily, * so we have to be careful not to interfere with a * running system. */     //如果指定了IRQF_SAMPLE_RANDOM,意味着设备将对内核随机数熵池有所贡献,rand_initialize_ir     //函数处理相应的工作 if (new->flags & IRQF_SAMPLE_RANDOM) { //与随机数产生相关的标志《情景分析》 P209/* * 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); //为中断请求初始化一个数据结构,用来记录中断的时序。}/* * Check whether the interrupt nests into another interrupt * thread. */nested = irq_settings_is_nested_thread(desc); //???????????????if (nested) {if (!new->thread_fn)return -EINVAL;/* * Replace the primary handler which was provided from * the driver for non nested interrupt handling by the * dummy function which warns when called. */new->handler = irq_nested_primary_handler;} else {if (irq_settings_can_thread(desc))irq_setup_forced_threading(new);}/* * Create a handler thread when a thread function is supplied * and the interrupt does not nest into another interrupt * thread. */if (new->thread_fn && !nested) {  //传递的参数thread_fn是NULL,所以不会被执行struct task_struct *t;t = kthread_create(irq_thread, new, "irq/%d-%s", irq,   new->name);if (IS_ERR(t))return PTR_ERR(t);/* * We keep the reference to the task struct even if * the thread dies to avoid that the interrupt code * references an already freed task_struct. */get_task_struct(t);new->thread = t;}if (!alloc_cpumask_var(&mask, GFP_KERNEL)) {ret = -ENOMEM;goto out_thread;}/* * The following block of code has to be executed atomically */raw_spin_lock_irqsave(&desc->lock, flags);old_ptr = &desc->action;old = *old_ptr;        //考虑到一个事实,中断描述符的action链上,可能一个也没有,可能已经注册了一个或多        //如果是后者,则需要判断新伙伴是否是允许共享 if (old) {/* * Can't share interrupts unless both agree to and are * the same type (level, edge, polarity). So both flag * fields must have IRQF_SHARED set and the bits which * set the trigger type must match. Also all must * agree on ONESHOT. */                //这里的验证表明,它使终使用第一个old来匹备,这意味着action链上的所有节点,都拥有相同的类                 //后面的IRQF_PERCPU也是同样的道理 if (!((old->flags & new->flags) & IRQF_SHARED) ||    ((old->flags ^ new->flags) & IRQF_TRIGGER_MASK) ||    ((old->flags ^ new->flags) & IRQF_ONESHOT)) {old_name = old->name;goto mismatch;}/* All handlers must agree on per-cpuness */if ((old->flags & IRQF_PERCPU) !=    (new->flags & IRQF_PERCPU))goto mismatch;/* add new interrupt at end of irq queue */do {thread_mask |= old->thread_mask;old_ptr = &old->next;old = *old_ptr;} while (old);shared = 1;}/* * Setup the thread mask for this irqaction. Unlikely to have * 32 resp 64 irqs sharing one line, but who knows. */if (new->flags & IRQF_ONESHOT && thread_mask == ~0UL) {ret = -EBUSY;goto out_mask;}new->thread_mask = 1 << ffz(thread_mask);        //如果是共享,则仅需要验证新的action的类型与中断描述符是否一致即可。        //否则,这意味着中断描述符的action上一无所有,这是一个新伙计,则需要通过新的action,为中断描符述设置一些标志位、状态位等诸如此类if (!shared) {init_waitqueue_head(&desc->wait_for_threads);/* Setup the type (level, edge polarity) if configured: */if (new->flags & IRQF_TRIGGER_MASK) {ret = __irq_set_trigger(desc, irq,new->flags & IRQF_TRIGGER_MASK);if (ret)goto out_mask;}desc->istate &= ~(IRQS_AUTODETECT | IRQS_SPURIOUS_DISABLED | \  IRQS_ONESHOT | IRQS_WAITING);irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS);if (new->flags & IRQF_PERCPU) {irqd_set(&desc->irq_data, IRQD_PER_CPU);irq_settings_set_per_cpu(desc);}if (new->flags & IRQF_ONESHOT)desc->istate |= IRQS_ONESHOT;if (irq_settings_can_autoenable(desc))irq_startup(desc);else/* Undo nested disables: */desc->depth = 1;/* Exclude IRQ from balancing if requested */if (new->flags & IRQF_NOBALANCING) {irq_settings_set_no_balancing(desc);irqd_set(&desc->irq_data, IRQD_NO_BALANCING);}/* Set default affinity mask once everything is setup */setup_affinity(irq, desc, mask);} else if (new->flags & IRQF_TRIGGER_MASK) {unsigned int nmsk = new->flags & IRQF_TRIGGER_MASK;unsigned int omsk = irq_settings_get_trigger_mask(desc);if (nmsk != omsk)/* hope the handler works with current  trigger mode */pr_warning("IRQ %d uses trigger mode %u; requested %u\n",   irq, nmsk, omsk);}        //设置中断号new->irq = irq;        //注册中断服务*old_ptr = new;/* Reset broken irq detection when installing new handler */desc->irq_count = 0;desc->irqs_unhandled = 0;/* * Check whether we disabled the irq via the spurious handler * before. Reenable it and give it another chance. */if (shared && (desc->istate & IRQS_SPURIOUS_DISABLED)) {desc->istate &= ~IRQS_SPURIOUS_DISABLED;__enable_irq(desc, irq, false);}raw_spin_unlock_irqrestore(&desc->lock, flags);/* * Strictly no need to wake it up, but hung_task complains * when no hard interrupt wakes the thread up. */        //如果有内核线程,则将其唤醒if (new->thread)wake_up_process(new->thread);       //注册procregister_irq_proc(irq, desc);new->dir = NULL;register_handler_proc(irq, new);free_cpumask_var(mask);return 0;mismatch:#ifdef CONFIG_DEBUG_SHIRQif (!(new->flags & IRQF_PROBE_SHARED)) {printk(KERN_ERR "IRQ handler type mismatch for IRQ %d\n", irq);if (old_name)printk(KERN_ERR "current handler: %s\n", old_name);dump_stack();}#endifret = -EBUSY;out_mask:raw_spin_unlock_irqrestore(&desc->lock, flags);free_cpumask_var(mask);out_thread:if (new->thread) {struct task_struct *t = new->thread;new->thread = NULL;if (likely(!test_bit(IRQTF_DIED, &new->thread_flags)))kthread_stop(t);put_task_struct(t);}return ret;}
	
				
		
原创粉丝点击