ImageVerifierCode 换一换
格式:DOCX , 页数:14 ,大小:22.27KB ,
资源ID:17259565      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/17259565.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(超强的Linux中断分析Word格式.docx)为本站会员(b****5)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

超强的Linux中断分析Word格式.docx

1、 #endif #if defined(CONFIG_GENERIC_PENDING_IRQ) | defined(CONFIG_IRQBALANCE) cpumask_t pending_mask; #ifdef CONFIG_PROC_FS struct proc_dir_entry *dir; const char *name; _cacheline_internodealigned_in_smp; Linux有一个全局变量, 包含了了所有的IRQ:(kernel/irq/handle.c) struct irq_desc irq_descNR_IRQS _cacheline_align

2、ed = 0 . NR_IRQS-1 = .status = IRQ_DISABLED, .chip = &no_irq_chip, .handle_irq = handle_bad_irq, .depth = 1, .lock = SPIN_LOCK_UNLOCKED, .affinity = CPU_MASK_ALL 3) irq_chip(即在genericirq之前的hw_interrupt_type) 以下这段是genericirq之前的:Linux支持N种可编程中断控制器PIC, 所以有一个struct hw_interrupt_type,对于i8259A来说,这个结构是i8259

3、A_irq_type, 对于IOAPIC来说, 根据设置为电平触发或边沿触发的方式, 分别有ioapic_level_type和ioapic_edge_type两个不同的结构。 在引入genericirq补丁之后,定义了几个irq_chip结构: 针对i386和x86-64各有一个定义的: ioapic_chip, i8259A_chip, lapic_chip, msi_chip, ht_irq_chip, vmi_chip, 针对visw体系的: cobalt_irq_chip, piix4_master_irq_type, piix4_virtual_irq_type 针对voyager

4、体系的: vic_chip 其它目的的: no_irq_chip, dummy_irq_chip4) irq_statNR_CPUS Linux定义了一个全局的数组,用来描述每个CPU上的irq处理状态:(arch/i386/kernel/irq.c) DEFINE_PER_CPU(irq_cpustat_t, irq_stat) _cacheline_internodealigned_in_smp; EXPORT_PER_CPU_SYMBOL(irq_stat); irq_stat_t的定义。 typedef struct unsigned int _softirq_pending; uns

5、igned long idle_timestamp; unsigned int _nmi_count; /* arch dependent */ unsigned int apic_timer_irqs; _cacheline_aligned irq_cpustat_t;5). 中断共享 我们知道,多个中断源可以共享一个irq线。 Linux的实现方式是,每个中断源都有自己的 一个struct irqaction, irqaction结构的定义: struct irqaction irq_handler_t handler; unsigned long flags; cpumask_t mas

6、k; void *dev_id; struct irqaction *next; int irq; ; 同一个irq可能有多个irqaction,组成一个链表。 struct irq_desc中有个域: 这个链表就包含了所有共享该irq号的中断源(及其对应的handler等信息)。 当device driver 进行request_irq()时,会为它生成一个irqaction,设置相应的值,然后挂载 irq_desc.action队列中(是添加在链表的最后面)。 request_irq(irq, handler, irqflags, devname, dev_id) setup_irq(ir

7、q, irqaction) flags有3个: IRQF_SHARED : 共享中断号 IRQF_DISABLED : 就是旧时代的SA_INTERRUPT,设置了该标志,则执行ISR时关本地中断 IRQF_SAMPLE_RANDOM : 告诉内核,本中断源可以用作随机数生成器的熵池 只有满足以下条件,irq才可以在多个中断源之间共享: a). 每个中断源都愿意共享irq: request_irq时指定了IRQF_SHARED b). 试图共享一个irq的中断源,具有相同的触发机制(都是level trigger,或者都是edge trigger),并且具有相同的polarity(都是低电平有

8、效,或者都是高电平有效) 下面是set_irq()函数中判断old和new两个中断源是否可以share同一个irq号的代码: /* * Cant 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. */ if (!(old-flags & new-flags) & IRQF

9、_SHARED) | (old-flags new- IRQF_TRIGGER_MASK) old_name = old-name; goto mismatch;6). 中断处理(do_IRQ, _do_IRQ, generic_handle_irq, etc) - Part I: _do_IRQ _do_IRQ()是genericirq引入之前的通用中断处理函数(除了IPI中断,其它所有中断/异常 都经过它),它由do_IRQ调用,并调用handle_IRQ_event(而handle_IRQ_event会调用各个 driver的ISR)。 在引入genericirq之后,_do_IRQ()

10、函数已基本不用了。 64位的X86系统上还可能使用 它(通过do_IRQ generic_handle_irq),32位的x86已经完全不用它了。 然而我们还是看一下_do_IRQ函数,因为道理是一样的: _do_IRQ():/*/ /首先给irq_descirq.lock加锁,以免别的CPU访问该desc结构 spin_lock(&desc-lock); /发送ACK给中断控制器 if (desc-chip-ack) desc-ack(irq); * REPLAY is when Linux resends an IRQ that was dropped earlier * WAITING

11、is used by probe to mark irqs that are being tested /*清除IRQ_REPLAY和IRQ_WAITING标志*/ status = desc-status & (IRQ_REPLAY | IRQ_WAITING); /*设置IRQ_PENDING标志。 这个flag的意思是,已经ACK但尚未处理*/ status |= IRQ_PENDING; /* we _want_ to handle it */ * If the IRQ is disabled for whatever reason, we cannot * use the actio

12、n we have. /*如果IRQ被disable了,但是我们收到了中断,说明这是个spurious interrupt, * 有些有BUG的主板等硬件会干这种事 action = NULL; /* 只要IRQ_DISABLED或者IRQ_INPROGRESS被设置,我们就不handle该irq。 * * 对于IRQ_INPROGRESS被设置的情况,说明此irq号的另一个实例正运行在 * 另一个CPU上,我们就不处理了,而是让 _那个_ CPU在运行完它的ISR时再检查 * 一下IRQ_PENDING标志,那时候它会再去处理我们这里逃避的事情的 if (likely(!(status &

13、(IRQ_DISABLED | IRQ_INPROGRESS) /*正常情况下2这都不被设置, *那我们就设置desc-status action = desc-action; status &= IRQ_PENDING; /* we commit to handling,清除pending标志 */ status |= IRQ_INPROGRESS; /* we are handling it ,设置inprogress标志*/status = status; * If there is no IRQ handler or it was disabled, exit early. * Sin

14、ce we set PENDING, if another processor is handling * a different instance of this same irq, the other processor * will take care of it. if (unlikely(!action) goto out; * Edge triggered interrupts need to remember * pending events. * This applies to any hw interrupts that allow a second * instance o

15、f the same irq to arrive while we are in do_IRQ * or in the handler. But the code herefor (;) irqreturn_t action_ret; /真正的IRQ处理是handle_IRQ_event,我们先unlock spin_unlock(& action_ret = handle_IRQ_event(irq, action); /再lock,因为后面还要unlock * 在我们调用handle_IRQ_event时,如果同一个irq又在另一个CPU上 * 来了一次,那个CPU会检测到IRQ_INPR

16、OGRESS标志,只设置了IRQ_PENDING * 标志便退出了。 这时我们就会检测到该标志,从而再处理第2次到来的irq * 注意! IRQ_PENDING只是个逻辑标志,而不是一个counter!所以,这种方式 * 只能处理同一irq的两个实例!如果发生了更多实例,第3个,第4个就丢失了 /如果没有第2个需要处理,退出(desc- IRQ_PENDING) break; /还有第2个需要处理,那么就清除IRQ_PENDING标志,表示我们已经答应要处理它了/*/7). 中断处理(do_IRQ, _do_IRQ, generic_handle_irq, etc) - Part II: ha

17、ndle_IRQ_event handle_IRQ_event()依次调用irq_descirq-action链表上的每一个action。 它会先打开中断(如果request_irq时没有设置IRQF_DISABLED标志),然后一个个执行irqaction, 再禁用本地中断。 handle_IRQ_event: irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action) irqreturn_t ret, retval = IRQ_NONE; unsigned int status = 0; handle_d

18、ynamic_tick(action); /如果指定了IRQF_DISABLED,就在关中断的情形下执行ISR /否则的话,在开中断的情形下执行ISR(action- IRQF_DISABLED) local_irq_enable_in_hardirq(); /该循环遍历irq_descirq-action链表,一个个调用其handler域 do ret = action-handler(irq, action-dev_id); if (ret = IRQ_HANDLED) status |= action-flags; retval |= ret; action = action-next;

19、 while (action); if (status & IRQF_SAMPLE_RANDOM) add_interrupt_randomness(irq); local_irq_disable(); return retval; Linux有两种情况可能导致丢中断,都是在SMP下才会发生的: a). CPU1在处理irq N,结果又来了一个irq N在CPU2上执行,这时候该CPU2只设置 irq_descirq.status的IRQ_PENDING标志,以便CPU1去检查从而再执行一遍。 当如果CPU3又收到一次,也设置IRQ_PENDING标志,这时CPU2设置的信息会丢失。 补救办法

20、:无 b). CPU1在处理器某IRQ之前,先发送ACK给PIC,结果这时候CPU2通过PIC禁用了该irq, 从而导致irq_descirq.status的IRQ_DISABLED标志被设置。 然后CPU1在正要处理 irq时发现对应的IRQ_DISABLED标志置位,于是退出。 这样就丢了一次中断。 在下一次enable_irq()被调用时,检查是否存在的这样的丢失。若然, 调用check_irq_resend()重新generate一次中断。 注意,在_do_IRQ()的一开始会清楚irq_descirq.status的IRQ_REPLAY 标志,这时为了防止对一次irq丢失补救多次。8

21、). 中断处理(do_IRQ, _do_IRQ, generic_handle_irq, etc) - Part III: Generic IRQ补丁 FIXME:我记得generic irq补丁是Thomas Gleixner和Ingo Molnar在大约2.6.17时引入的, 当时支持i386、x86-64和arm三个体系结构。 generic irq层的引入,是为了剥离irq flow和irq chip过于紧密的耦合。 为driver程序员提供 通用的API来request/enable/disable/free中断,这样程序员不用知道任何底层的中断控制器细节。8.1) 它为driver

22、程序员提供的highlevel的API: request_irq() free_irq() disable_irq() enable_irq() disable_irq_nosync() (SMP) synchronize_irq() (SMP set_irq_type() set_irq_wake() set_irq_data() set_irq_chip() set_irq_chip_data()8.2) 它为irq flow提供了一组预定义了的方法: handle_level_irq() = 针对level type的irq handler handle_edge_irq() = 针对e

23、dge type的irq handler handle_simple_irq() = 针对Simple and software-decoded IRQS /FIXME: 我猜测percpu irq不是IPI,而是某种x86没有的东西 handle_percpu_irq() = 针对per-cpu local IRQs handle_fasteoi_irq() = 针对transparent controllers, 目前IO-APIC主要用它和edge 什么叫透明的中断控制器?老子咋看不懂涅?Irq的flow type, generic irq有以下数种: #define IRQ_TYPE_

24、NONE 0x00000000 /* Default, unspecified type */ #define IRQ_TYPE_EDGE_RISING 0x00000001 /* Edge rising type */ #define IRQ_TYPE_EDGE_FALLING 0x00000002 /* Edge falling type */ #define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING) #define IRQ_TYPE_LEVEL_HIGH 0x00000004 /* Level hi

25、gh type */ #define IRQ_TYPE_LEVEL_LOW 0x00000008 /* Level low type */ #define IRQ_TYPE_SENSE_MASK 0x0000000f /* Mask of the above */ #define IRQ_TYPE_PROBE 0x00000010 /* Probing in progress */-没有看到simple类型和per-cpu类型,我估计这2者都是其他architectures上的。 这里把EDGE触发的irq又分成了上升沿、下降沿和both, level触发的又分成了低电平有效和high act

26、ive。这5个函数取代了原来的_do_IRQ,由do_IRQ直接调用:handle_irq(irq, desc);而这个irq_descirq.handle_irq又是在哪里设置的呢? 不同的irq chip有不同的设置,现在让我们看一下ioapic_chip上的irqs的设置: static void ioapic_register_intr(int irq, unsigned long trigger) /* 如果不是edge触发的,就设置为handle_fasteoi_irq */ if (trigger) irq_descirq.status |= IRQ_LEVEL; set_irq_chip_and_handler_name(irq, &ioapic_chip, handle_fasteoi_irq, fasteoi); else /* 如果是edge触发的,就设置为handle_edge_irq */ irq_descirq.status &= IRQ_LEVEL; handle_edge_irq, edge

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1