RK3399 PCIe 中断处理与映射分析(INTx中断机制源码分析)

往期内容

本文章相关专栏往期内容,PCI/PCIe子系统专栏:

  1. 嵌入式系统的内存访问和总线通信机制解析、PCI/PCIe引入
  2. 深入解析非桥PCI设备的访问和配置方法
  3. PCI桥设备的访问方法、软件角度讲解PCIe设备的硬件结构
  4. 深入解析PCIe设备事务层与配置过程
  5. PCIe的三种路由方式
  6. PCI驱动与AXI总线框架解析(RK3399)
  7. 深入解析PCIe地址空间与寄存器机制:从地址映射到TLP生成的完整流程
  8. PCIe_Host驱动分析_地址映射
  9. PCIe_Host驱动分析_设备枚举
  10. PCI/PCIe设备INTx中断机制和MSI中断机制
  11. MSI-X中断机制、MSI/MSI-X操作流程详解

Uart子系统专栏:

  1. 专栏地址:Uart子系统
  2. Linux内核早期打印机制与RS485通信技术
    -- 末片,有专栏内容观看顺序

interrupt子系统专栏:

  1. 专栏地址:interrupt子系统
  2. Linux 链式与层级中断控制器讲解:原理与驱动开发
    -- 末片,有专栏内容观看顺序

pinctrl和gpio子系统专栏:

  1. 专栏地址:pinctrl和gpio子系统

  2. 编写虚拟的GPIO控制器的驱动程序:和pinctrl的交互使用

    -- 末片,有专栏内容观看顺序

input子系统专栏:

  1. 专栏地址:input子系统
  2. input角度:I2C触摸屏驱动分析和编写一个简单的I2C驱动程序
    -- 末片,有专栏内容观看顺序

I2C子系统专栏:

  1. 专栏地址:IIC子系统
  2. 具体芯片的IIC控制器驱动程序分析:i2c-imx.c-CSDN博客
    -- 末篇,有专栏内容观看顺序

总线和设备树专栏:

  1. 专栏地址:总线和设备树
  2. 设备树与 Linux 内核设备驱动模型的整合-CSDN博客
    -- 末篇,有专栏内容观看顺序

目录

1.前言

参考资料:

  • 《PCI_SPEV_V3_0.pdf》6.8节
  • 《devicetree-specification-v0.2.pdf》

开发板资料:

分析的文件:

2.中断处理流程

要分析PCIe设备中断号的分配过程,需要从RK3399的芯片资料开始学习。

层级结构为:PCIe设备 => PCIe控制器 => GIC =>CPU

设备发生中断:PICe设备1 --> PCIe控制器 --> GIC --> CPU

那就从软件上来讲,也就是处理流程,根据之前在中断子系统说讲的,如下:

(1)CPU肯定是会去跳到vector向量表,去对中断现场进行保存,调用GIC中的handle函数,这里假设是gic_handle_irq (\Linux-4.9.88\drivers\irqchip\irq-gic-v3.c)

(2)GIC的handle函数会执行:

  • 读GIC的寄存器,去获得hwirq_1硬件中断号 ,假设是80
  • 得到硬件中断号了,那接下来肯定就是在domain找到其对于的virq_1,假设是221
  • 得到硬件中断号了,就可以找到其PCIe控制器的irq_desc中断描述符,也就是irq_desc[virq_1]
  • 调用irq_desc[virq_1].handle_irq,这个函数是PCIe控制器提供的

(3)irq_desc[virq_1].handle_irq假设是rockchip_pcie_legacy _int handler(\Linux-4.9.88\drivers\pci\host\pcie-rockchip.c)

  • PCIe控制器要做的事情也和GIC差不多,获取设备硬件中断hwirq_2,这里是10
  • 获取virq_2:10 --> 225(假设)
  • 得到PCIe设备1的irq_desc:irq_desc[virq_2]
  • 调用irq_desc[virq_2].irq_handle

(4)调用irq_desc[virq_2].irq_handle???其实就是调用PCIe设备驱动request_irq的func,也就是irq_desc[virq_2].action.handler(func)

这里只是对流程进行简单讲解,还有一些mask屏蔽中断的操作,在中断子系统专栏有讲。

2.设备树和支持的中断

c 复制代码
       gic: interrupt-controller@fee00000 {
                compatible = "arm,gic-v3";
                #interrupt-cells = <4>;
                #address-cells = <2>;
                #size-cells = <2>;
                ranges;
                interrupt-controller;
                /* 省略 */
		};

       pcie0: pcie@f8000000 {
                compatible = "rockchip,rk3399-pcie";
                #address-cells = <3>;
                #size-cells = <2>;
                aspm-no-l0s;
                clocks = <&cru ACLK_PCIE>, <&cru ACLK_PERF_PCIE>,
                         <&cru PCLK_PCIE>, <&cru SCLK_PCIE_PM>;
                clock-names = "aclk", "aclk-perf",
                              "hclk", "pm";
                bus-range = <0x0 0x1f>;
                max-link-speed = <1>;
                linux,pci-domain = <0>;
                msi-map = <0x0 &its 0x0 0x1000>;
                interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH 0>,
                             <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH 0>,
                             <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH 0>;
                interrupt-names = "sys", "legacy", "client";
                #interrupt-cells = <1>;
                interrupt-map-mask = <0 0 0 7>;
                interrupt-map = <0 0 0 1 &pcie0_intc 0>,
                                <0 0 0 2 &pcie0_intc 1>,
                                <0 0 0 3 &pcie0_intc 2>,
                                <0 0 0 4 &pcie0_intc 3>;
	};

对于RK3399,PCIe控制器可以向GIC发出3个中断:sys、legacy、client:

  • sys:下图中Event ID为81,就是SPI 49号中断(81=32+49),用来处理一些系统性的中断,比如电源状态、热拔插
  • legacy:用来处理PCIe设备发来的INTA/INTB/INTC/INTD中断
  • client:跟外接的PCIe设备通信时,可能会发送传输错误,用这个中断来处理

接下来的代码分析就是以legacy为主

3.注册PCIe控制器的handle

c 复制代码
                interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH 0>,
                             <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH 0>,
                             <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH 0>;
                interrupt-names = "sys", "legacy", "client";

对应的设备树部分,根据PCIe设备选择的是哪种中断方式,来设置PCIe控制器的handle,这里是 <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH 0>,也就是legacy的方式,其实50+32就是硬件中断号,PCIe控制器要发送到中断控制器的hwirq82

  1. rockchip_pcie_init_irq_domain 中是否完成映射?
  • rockchip_pcie_init_irq_domain 是创建一个 IRQ domain 的过程。这个函数通过调用 irq_domain_add_linear 创建了一个线性 IRQ domain,这个 domain 是 PCIe
    控制器用于管理挂接到其上面的设备的 INTx 中断(如 INTA、INTB、INTC、INTD)。此时,还没有具体到 PCIe
    设备的中断映射,只是为 PCIe 控制器建立了一个 虚拟中断控制器域,供后续 PCIe 设备使用。
  • 当 PCIe 设备扫描并初始化时,会根据该域为设备映射中断号,所以这个函数仅仅是 为 PCIe 控制器的 INTx 引脚建立域,具体的映射会在之后处理设备中断时完成。
  1. pcie0_intc 是虚拟中断控制器,它是管理 INTA# 的设备吗?
  • pcie0_intc 是一个虚拟的中断控制器节点,它负责管理连接到 PCIe 控制器的所有 PCIe 设备的 INTx 中断 (包括 INTA、INTB、INTC、INTD)。每个 INTx 中断引脚会根据设备树的 interrupt-map
    进行映射。通过设备树的 interrupt-map,会为连接到 PCIe 控制器的设备的中断分配具体的中断号。
  • 并不是专门对应 INTA# ,而是通过映射机制为连接到 PCIe 的多个设备分配中断号。PCIe 设备的 INTx 中断(INTA, INTB, INTC, INTD)会映射到对应的硬件中断,pcie0_intc 管理所有挂在 PCIe
    控制器上的设备中断。
  1. PCIe 设备中断映射的过程:代码流程解析

这个流程实际上是描述了 PCIe 设备初始化时的中断号分配过程 。在这个过程中,系统会扫描挂接到 PCIe

控制器的设备,并为每个设备分配中断号。流程大致如下:

  1. 设备扫描与初始化:

    • 调用 pci_scan_root_bus 和相关函数递归扫描并初始化挂接在 PCIe 总线上的所有设备。
    • pci_scan_single_device 负责扫描单个 PCIe 设备,通过 pci_setup_device 设置其硬件资源,并通过 pci_device_add 添加设备。
  2. 解析设备中断信息:

    • pci_device_add 中,调用 pcibios_add_device,最终调用 of_irq_parse_and_map_pci 来解析设备的中断信息。
    • of_irq_parse_and_map_pci 通过读取 PCIe 设备的中断引脚号(INTx),调用设备树的 interrupt-map,映射设备的中断号。这里解析设备树中 interrupt-map 的过程是在
      of_irq_parse_raw 中完成的。
  3. 分配中断号:

    • irq_create_of_mapping 最终为该设备创建一个中断号,并将其存储在 pci_dev->irq 中。此时,PCIe 设备的中断号已经完成映射。
  4. 设备中断号的存储:

    • 映射得到的中断号会存放在 pci_dev->irq 中,后续可以通过该中断号为设备注册中断处理函数。
  1. 映射的具体过程
  • 映射的过程 发生在调用 of_irq_parse_and_map_pci 及其后续调用的 of_irq_parse_raw 函数时。此时,设备的 PCIe 配置空间中的中断引脚号(INTx)会通过
    interrupt-map 的定义映射到虚拟中断控制器(如 pcie0_intc),并得到一个实际的中断号。
  • 比如 interrupt-map = <0 0 0 1 &pcie0_intc 0>,,当设备配置空间中的 interrupt pin1 时(即使用 INTA# 中断),映射到 &pcie0_intc 0,并得到相应的中断号。
  1. 总结:映射与域的关系
  • rockchip_pcie_init_irq_domain 的作用是为 PCIe 控制器创建一个域,供后续设备映射中断号使用。这是一个准备工作,域的创建并不代表已经完成了映射,而是为 PCIe 设备的中断号分配提供了基础。
  • 映射真正发生在 of_irq_parse_and_map_pci 函数中,它解析设备树的 interrupt-map 并将 PCIe 设备的中断号与虚拟中断控制器 pcie0_intc 进行关联,最终得到具体的硬件中断号。

c 复制代码
static void rockchip_pcie_legacy_int_handler(struct irq_desc *desc)
{
    //........
    irq = platform_get_irq_byname(pdev, "legacy"); //---(1)
    if (irq < 0) {
        dev_err(dev, "missing legacy IRQ resource\n");
        return -EINVAL;
    }

    irq_set_chained_handler_and_data(irq,
                                     rockchip_pcie_legacy_int_handler,
                                     rockchip);  // ------(2)
    //........
}

(1)这里 platform_get_irq_byname() 函数通过设备树中的 interrupt-names 获取与 "legacy" 对应的 GIC 中断线(即 GIC_SPI 50),并将其传递给 irq_set_chained_handler_and_data() 来设置中断处理函数。

(2) 将 GIC 中断处理与 PCIe 控制器的中断处理流程连接起来。设置了PCIe控制器的irq_desc[].handle_irq 为 rockchip_pcie_legacy_int_handler,采用legacy的中断方式,设置函数如下:

c 复制代码
void
irq_set_chained_handler_and_data(unsigned int irq, irq_flow_handler_t handle,
				 void *data)
{
	unsigned long flags;
	struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, 0);

	if (!desc)
		return;

	desc->irq_common_data.handler_data = data;
	__irq_do_set_handler(desc, handle, 1, NULL);

	irq_put_desc_busunlock(desc, flags);
}

其实也很好懂,上锁,根据virq获取中断描述符,设置其data和handler_irq,解锁

rockchip_pcie_legacy_int_handler函数要进一步分辨设置的是INTA还是INTB、INTC、INTD中断:

上图,每个INTx#都有对应的irq_desc中断描述符,发生中断后PCIe控制器调用了rockchip_pcie_legacy_int_handler,去分辨

c 复制代码
static void rockchip_pcie_legacy_int_handler(struct irq_desc *desc)
{
	struct irq_chip *chip = irq_desc_get_chip(desc);
	struct rockchip_pcie *rockchip = irq_desc_get_handler_data(desc);
	struct device *dev = rockchip->dev;
	u32 reg;
	u32 hwirq;
	u32 virq;

	chained_irq_enter(chip, desc);

	reg = rockchip_pcie_read(rockchip, PCIE_CLIENT_INT_STATUS);  // ----(1)
	reg = (reg & PCIE_CLIENT_INTR_MASK) >> PCIE_CLIENT_INTR_SHIFT;

	while (reg) {  
		hwirq = ffs(reg) - 1;
		reg &= ~BIT(hwirq);// ----(2)

		virq = irq_find_mapping(rockchip->irq_domain, hwirq);// ----(3)
		if (virq)
			generic_handle_irq(virq);
		else
			dev_err(dev, "unexpected IRQ, INT%d\n", hwirq);
	}

	chained_irq_exit(chip, desc);
}

(1)读取中断状态寄存器 :这两行代码从 PCIe 设备读取中断状态寄存器(PCIE_CLIENT_INT_STATUS)。该寄存器通常包含有关当前触发的中断的信息。通过将寄存器值与中断掩码 (PCIE_CLIENT_INTR_MASK) 进行按位与操作,然后通过右移操作,提取出实际的中断状态。

(2)处理每个中断:

  • 逐个处理中断while (reg) 循环用来处理寄存器中每一个设置为 1 的中断标志。
  • 获取硬件中断号hwirq = ffs(reg) - 1; 通过调用 ffs(find first set)函数来查找 reg 中最右侧的 1 的位置,得到的值就是当前中断的硬件 IRQ(hwirq)。
  • 清除当前中断reg &= ~BIT(hwirq); 通过清除当前处理中断的位来避免重复处理。

(3)映射和触发虚拟中断:

  • 查找虚拟 IRQ :通过 irq_find_mapping 函数将硬件 IRQ (hwirq) 映射到对应的虚拟 IRQ (virq)。这个映射关系是在初始化时通过 irq_domain 创建的(下小点会讲到),它定义了硬件 IRQ 和内核中的虚拟 IRQ 之间的关系。
  • 触发 IRQ 处理程序 :如果找到有效的虚拟 IRQ,调用 generic_handle_irq(virq) 触发相应的中断处理程序。这个函数会调用与 virq 相关联的中断处理程序,执行实际的中断处理逻辑。

4.创建控制器的domain

PCIe控制器的节点里有一个更下一级的中断控制器,这是一个虚拟的中断控制器,是对PCIe控制器的进一步的信息设置。创建的域实际上是 PCIe 控制器的 ,它主要用于管理连接到该 PCIe 控制器的所有 PCIe 设备的中断映射关系。具体来说,创建的 IRQ domain 会负责映射 PCIe 设备的中断号,确保每个设备的中断号与系统的中断控制器之间进行正确的转换。

c 复制代码
          pcie0: pcie@f8000000 {
          		#address-cells = <3>;
          		#interrupt-cells = <1>; 
          		
               	interrupt-map-mask = <0 0 0 7>;
                interrupt-map = <0 0 0 1 &pcie0_intc 0>,
                                <0 0 0 2 &pcie0_intc 1>,
                                <0 0 0 3 &pcie0_intc 2>,
                                <0 0 0 4 &pcie0_intc 3>;
          
                pcie0_intc: interrupt-controller {
                        interrupt-controller;
                        #address-cells = <0>;
                        #interrupt-cells = <1>;
                };                    
          };

在代码里,对于pcie0_intc会创建出一个IRQ domain:

c 复制代码
static int rockchip_pcie_init_irq_domain(struct rockchip_pcie *rockchip)
{
	struct device *dev = rockchip->dev;
	struct device_node *intc = of_get_next_child(dev->of_node, NULL); //获取pcie0_intc节点

	if (!intc) {
		dev_err(dev, "missing child interrupt-controller node\n");
		return -EINVAL;
	}

	rockchip->irq_domain = irq_domain_add_linear(intc, 4,  //创建外设的domain
						    &intx_domain_ops, rockchip);
    //通过调用 irq_domain_add_linear() 创建 IRQ 域并将其与设备树中的中断控制器节点关联。
	if (!rockchip->irq_domain) {
		dev_err(dev, "failed to get a INTx IRQ domain\n");
		return -EINVAL;
	}

	return 0;
}

rockchip_pcie_init_irq_domain 中是否完成映射?

  • rockchip_pcie_init_irq_domain 是创建一个 IRQ domain 的过程。这个函数通过调用 irq_domain_add_linear 创建了一个线性 IRQ domain,这个 domain 是 PCIe 控制器用于管理挂接到其上面的设备的 INTx 中断(如 INTA、INTB、INTC、INTD)。此时,还没有具体到 PCIe 设备的中断映射,只是为 PCIe 控制器建立了一个 虚拟中断控制器域,供后续 PCIe 设备使用。
  • 当 PCIe 设备扫描并初始化时,会根据该域为设备映射中断号,所以这个函数仅仅是 为 PCIe 控制器的 INTx 引脚建立域,具体的映射会在之后处理设备中断时完成。

pcie0_intc 是虚拟中断控制器,它是管理 INTA# 的设备吗? ----- 个人想法

  • pcie0_intc** 是一个虚拟的中断控制器节点,它负责管理连接到 PCIe 控制器的所有 PCIe 设备的 INTx 中断 (包括 INTA、INTB、INTC、INTD)。每个 INTx 中断引脚会根据设备树的 interrupt-map 进行映射。通过设备树的 interrupt-map,会为连接到 PCIe 控制器的设备的中断分配具体的中断号。
  • 并不是专门对应 INTA# ,而是通过映射机制为连接到 PCIe 的多个设备分配中断号。PCIe 设备的 INTx 中断(INTA, INTB, INTC, INTD)会映射到对应的硬件中断,pcie0_intc 管理所有挂在 PCIe 控制器上的设备中断。

5.创建映射关系

5.1 如何映射

interrupt-mapinterrupt-map-mask 的作用

  • interrupt-map-mask 定义了从 PCI/PCIe 配置空间中的哪些字段参与中断映射。例如,在这个例子中,interrupt-map-mask = <0 0 0 7>; 表示只有配置空间中最后 3 位有效,它们参与中断映射。
  • interrupt-map 定义了设备树中的中断映射关系,将 PCIe 设备的中断映射到主机系统的中断控制器。

**interrupt-map = <0 0 0 1 &pcie0_intc 0>, ...**
  • <0 0 0 1>:这四个数字的含义分别是:

    • 第 1 个数字 (0):表示设备号。在 PCIe 中,0 通常代表某个设备的地址,参与设备编号映射。
    • 第 2 个数字 (0) :表示功能号。对于多功能设备,功能号用于区分同一个 PCIe 设备的不同功能模块,这里是 0
    • 第 3 个数字 (0) :表示中断引脚 (INTx)。这个数字代表哪个 INT 引脚触发了中断。在 PCIe 中,中断引脚可以是 INTA, INTB, INTC 或 INTD。这种机制源自传统的 PCI 中断机制,在这里对应的值是 0(表示 INTA)。
    • 第 4 个数字 (1) :代表中断线号,即设备的中断编号。这里的 1 表示是设备的第 1 号中断。
  • &pcie0_intc:这是一个设备树的节点引用,指向 PCIe 控制器下的虚拟中断控制器 pcie0_intc,表示该设备的中断需要交由 pcie0_intc 处理。

  • 0:这是最后一个参数,通常表示硬件 IRQ 号或中断标志。在这个例子中,它是 0,表示这是第 0 号硬件中断线。


**interrupt-map-mask = <0 0 0 7>;**
  • 0 0 0 7:表示只有设备号(第 3 位)和中断引脚号(第 4 位)有效,参与映射。实际上,它用最后 3 位来判断是哪个 PCIe 设备、哪个功能模块、哪个中断引脚触发了中断。

中断映射的流程:

  1. PCIe 配置空间中的 interrupt pin 字段 :这个字段记录了设备使用的中断引脚(INTA、INTB、INTC 或 INTD)。比如当PCIe设备的配置空间中 interrupt pin1,表示使用 INTA# 引脚触发的中断。
  2. PCIe 地址映射 :根据 PCIe 设备的 bus、device、function 号,以及 interrupt pin,组合出 0 0 0 1
  3. interrupt-map-mask 进行与操作0 0 0 1interrupt-map-mask = <0 0 0 7>; 进行按位与运算,只保留最后 3 位。因此 0 0 0 1 会与 0 0 0 7 计算后仍然是 0 0 0 1,表示 INTA# 对应的中断号。
  4. 映射到 interrupt-map:根据 interrupt-map<0 0 0 1 &pcie0_intc 0> 表示 PCIe 设备的 INTA# 中断被映射到虚拟中断控制器 pcie0_intc,并由其处理为第 0 号硬件中断。应该就是指这个设备发出的就是0号硬件中断

那么它在代码中是如何体现出来的???看下面

5.2 代码体现

c 复制代码
rockchip_pcie_probe
    bus = pci_scan_root_bus(&pdev->dev, 0, &rockchip_pcie_ops, rockchip, &res);
		pci_scan_root_bus_msi
            pci_scan_child_bus
            	pci_scan_slot
            		dev = pci_scan_single_device(bus, devfn);
						dev = pci_scan_device(bus, devfn);  //----(1)
							struct pci_dev *dev;
							dev = pci_alloc_dev(bus);
							pci_setup_device
                                pci_read_bases(dev, 6, PCI_ROM_ADDRESS);	
                        pci_device_add(dev, bus); //-----(2.1)
                        	pcibios_add_device(struct pci_dev *dev)
                        		dev->irq = of_irq_parse_and_map_pci(dev, 0, 0);  //具体内容看下面

of_irq_parse_and_map_pci	//-----(2.2)
	ret = of_irq_parse_pci(dev, &oirq);
				rc = pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pin);

                out_irq->np = ppnode;
                out_irq->args_count = 1;
                out_irq->args[0] = pin;
                laddr[0] = cpu_to_be32((pdev->bus->number << 16) | (pdev->devfn << 8));
                laddr[1] = laddr[2] = cpu_to_be32(0);
                rc = of_irq_parse_raw(laddr, out_irq);				
	
	return irq_create_of_mapping(&oirq);  //------(3)

这个流程实际上是描述了 PCIe 设备初始化时的中断号分配过程。在这个过程中,系统会扫描挂接到 PCIe 控制器的设备,并为每个设备分配中断号。流程大致如下:

  1. 设备扫描与初始化:

    • 调用 pci_scan_root_bus 和相关函数递归扫描并初始化挂接在 PCIe 总线上的所有设备。
    • pci_scan_single_device 负责扫描单个 PCIe 设备,通过 pci_setup_device 设置其硬件资源,并通过 pci_device_add 添加设备。
  2. 解析设备中断信息:

    • pci_device_add 中,调用 pcibios_add_device,最终调用 of_irq_parse_and_map_pci 来解析设备的中断信息。 ------(2.1)
    • 映射的过程 发生在调用 of_irq_parse_and_map_pci 及其后续调用的 **of_irq_parse_raw** 函数时。此时,设备的 PCIe 配置空间中的中断引脚号(INTx)会通过 interrupt-map 的定义映射到虚拟中断控制器(如 pcie0_intc),并得到一个实际的中断号。-----(2.2)
    • 比如 interrupt-map = <0 0 0 1 &pcie0_intc 0>,,当设备配置空间中的 interrupt pin1 时(即使用 INTA# 中断),映射到 &pcie0_intc 0,并得到相应的中断号。
  3. 分配虚拟中断号:

    • irq_create_of_mapping 最终为该设备创建一个虚拟中断号,并将其存储在 pci_dev->irq 中。此时,PCIe 设备的中断号已经完成映射。(然后就可以通过request_irq函数,使用这个pci_dev->irq来为该驱动设置其中断处理函数handler)

rockchip_pcie_init_irq_domain 的作用是为 PCIe 控制器创建一个域,供后续设备映射中断号使用。这是一个准备工作,域的创建并不代表已经完成了映射,而是为 PCIe 设备的中断号分配提供了基础。

映射真正发生在 of_irq_parse_and_map_pci 函数中,它解析设备树的 interrupt-map 并将 PCIe 设备的中断号与虚拟中断控制器 pcie0_intc 进行关联,最终得到PCIe设备具体的硬件中断号。

相关推荐
不能只会打代码31 分钟前
32单片机从入门到精通之软件编程——初始化设置(八)
单片机·嵌入式硬件·32单片机
就叫飞六吧32 分钟前
单片机端口操作和独立引脚操作
单片机·嵌入式硬件
蓑衣客VS索尼克2 小时前
嵌入式硬件设计的基本流程
嵌入式硬件
wit_yuan2 小时前
openbmc sdk09.03 适配(一)
linux·服务器·嵌入式硬件
GCSXP4 小时前
PT8026 六触控六输出IC
单片机·嵌入式硬件
aloneboyooo8 小时前
SPI通信-(STM32)
stm32·单片机·嵌入式硬件
爱学电子的刻刻帝10 小时前
STM32传感器系列:GPS定位模块
stm32·单片机·嵌入式硬件·gps
lucy1530275107911 小时前
DC-DC 降压转换器设计提示和技巧
单片机·嵌入式硬件·智能手机·便携式视盘播放器·cd-rom
沐欣工作室_lvyiyi11 小时前
基于单片机的核辐射探测系统设计(论文+源码)
stm32·单片机·嵌入式硬件·物联网·智能家居
就叫飞六吧12 小时前
STC单片机内部常见寄存器及其作用
单片机·嵌入式硬件