Linux 中断

一. Linux中断概述

1.1 中断分类

根据中断的来源,中断可分为内部中断和外部中断,内部中断的中断源来源于CPU内部(软件中断指令,溢出,除法错误,例如,操作系统从用户态切换到内核态需要借助CPU内部的软件中断),外部中断的中断源来源于CPU外部,由外设提出请求。

根据中断是否可以屏蔽,中断可分为可屏蔽中断和不可屏蔽中断(NMI),可屏蔽中断可以通过设置中断控制器寄存器等方法被屏蔽,屏蔽后,该终端不再得到响应,而不可屏蔽中断不能被屏蔽。

根据中断入口跳入方法的不同,中断可分为向量中断和非向量中断。采用向量中断的CPU通常为不同的中断分配不同的中断号,当检测到某个中断号的中断到来后,就自动跳转到与该中断号对应的地址执行,不同中断号的中断有不同的入口地址。非向量中断的多个中断共享一个入口地址,进入到该入口地址后,再通过软件判断中断标志来识别具体是哪个中断。

1.2 Linux中断处理机制

顶半部用于完成尽量少的比较紧急的功能,它往往只是简单地读取寄存器的中断状态,并在清除中断标志后就进行“登记中断”的工作。“登记中断”意味着将底半部处理程序挂到该设备的底半部执行队列中去,这样顶半部执行的速度就会很快,从而可以服务更多的中断程序

二. Linux中断编程

一般来说,linux设备驱动编程中中断涉及到两部分:

(1)中断向量号的申请(亲和CPU和不亲和两种情况)

(2)中断请求(中断线程化或者中断服务函数注册)

1.1 申请中断向量号(with affinity

对于需要亲和CPU的中断向量而言,申请中断向量后会出现两个现象:

(1)一个CPU对应一个中断向量,即每个中断向量对应的中断服务函数由专一的CPU来处理

(2)多个CPU对应一个中断向量,即每个中断向量对应的中断服务函数由两个或多个CPU来处理

1.1.1 pci_alloc_irq_vectors_affinity

int

pci_alloc_irq_vectors_affinity

(struct pci_dev *dev, unsigned int min_vecs,unsigned int max_vecs, unsigned int flags, struct irq_affinity *affd)

(1)pci_dev *dev是pci device

(2)int min_vecs为所申请的中断向量的最小数

(3)int max_vecs为所申请的中断向量的最大数

(4)用来指明申请向量的属性,比如PCI_IRQ_AFFINITYPCI_IRQ_MSIXPCI_IRQ_MSIPCI_IRQ_LEGACY

(5)irq_affinity *affd包含前向中断数,后向中断数以及自添加的计算函数

  1. irq_affinity *affd参数跟中断亲和性相关,可以设置pre_vectors实现前几个中断向量不具备cpu亲和性,post_vectors实现后几个中断向量不具备cpu亲和性,不过不亲和的数量一定要大于int min_vecs参数,不然内核认定不给分配向量,见图2                                                                        图 1                                                                        图 2                                      irq_calc_affinity_vectors在一般情况下计算出的中断向量数将环境中cpu的数量考虑进去了
  2. int flags参数中一定要包含PCI_IRQ_AFFINITY才能开启中断亲和性功能,另外还需要包含PCI_IRQ_MSIXPCI_IRQ_MSIPCI_IRQ_LEGACY其中一个中断类型,或者均包含设置为PCI_IRQ_ALL_TYPES
  3. 图1中nr_sets默认值为1(标志亲和的方法只有一种),set_size数组各个成员表示各亲和方法下需要分配的亲和向量中断(默认只有set_size[0]有值)
  4. 当申请的亲和向量中断数小于环境中numa node的数量,内核会秉持着物尽其用的原则,将每一个numa节点的cpu都散布出去,这意味着会出现一个中断向量会有多个numa节点上的cpu响应
  5. node_to_cpumask作为二级指针存储着各个numa ID作为索引值,最终指向各个numa 节点的cpu mask.
  6. node_vectors根据node_to_cpumask计算出每个numa节点应该分配到的中断向量数
  7. 需要提一句的是总的亲和性中断向量数numvecs再一次被remain cpu数限制,另外numa是经过上升排序了的,可能会造成中断向量不从numa0开始
  8. 为每个中断向量分配中断cpu的核心算法,可能会出现一个numa节点中前几个中断向量每个都分配到了2个以上的cpu,后面的每个中断向量只分配到了一个cpu
  9. pre_vectorspost_vectors对应的irq_affinity_desc也需要初始化cpumask,均被初始化为irq_default_affinity,即表示为不与任何cpu亲和
  10. 每一个中断向量的准备工作统一由pci_msi_setup_msi_irqs实现,最终调用钩子函数ops->domain_alloc_irqs,具体为msi_domain_ops_default

1.2 中断请求

Linux命令行cat /proc/interrupts可以显示每个中断向量对应亲和的CPU以及CPU执行某一个中断向量的服务函数的计数值以及对应的向量名

1.2.1 pci_request_irq

int

pci_request_irq(struct pci_dev *dev, unsigned int nr, irq_handler_t handler, irq_handler_t thread_fn, void *dev_id, const char *fmt, ...)

(1)pci_dev *dev是当前的pci设备

(2)int nr是pci设备内部的中断向量索引,用来计算实际的中断号:通过pci_irq_vector(dev, nr)

(3)handler是注册的中断服务函数,执行于中断上下文;另外IRQF_SHARED表示可由多个设备共享该中断向量

(4)thread_fn对应的注册函数则执行于内核线程,执行该函数不可避免的需要进程切换开销;另外IRQF_ONESHOT可以保证thread_fn函数执行时由内核自动屏蔽对应的中断,从而保证thread_fn函数执行完整不被打断,执行完成之后再重新使能该中断

(5)dev_id用于传参入handler或thread_fn注册的函数

(6)fmt是中断向量的名字

三. 中断数据处理结构

Linux内核中处理中断主要有三个数据结构,irq_desc,irq_chip和irqaction。

在\include\linux\ irq.h中定义了

2.1 irq_desc

irq_desc用于描述IRQ线的属性与状态,被称为中断向量描述符。需要特别说明的是irq_desc在申请中断向量的时候就已经分配好了,并悬挂在irq_desc_tree上,可直接由中断向量号直接寻址到对应的irq_desc(由irq_to_desc),具体到msi_domain_ops-> domain_alloc_irqs的回调函数

struct irq_desc *desc:

2.2 irq_data

struct irq_data包含chip中断控制器,中断域irq_domain

2.3 irqaction

在\include\linux\interrupt.h中定义了 irqaction用来描述特定设备所产生的中断描述符,因为IRQF_SHARED带来的中断向量被多个设备共享的问题

struct irqaction *action:

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值