从设备树到驱动:手把手拆解Linux内核如何为PCIe设备分配IRQ和内存资源

张开发
2026/6/14 20:16:14 15 分钟阅读
从设备树到驱动:手把手拆解Linux内核如何为PCIe设备分配IRQ和内存资源
Linux PCIe设备资源分配全链路解析从设备树到驱动实战在嵌入式Linux开发中为PCIe设备正确分配IRQ和内存资源是驱动开发的关键环节。本文将深入剖析从设备树定义到驱动获取资源的完整链路结合代码实例揭示内核如何完成这一复杂转换过程。1. 设备树中的资源定义艺术PCIe设备在设备树中的资源定义是驱动开发的起点。一个典型的PCIe控制器节点包含三类核心属性pcie0: pcie0xd4288000 { #address-cells 3; #size-cells 2; reg 0xd4210000 0x800, /* PHY寄存器 */ 0xd4288000 0x1000; /* 配置空间 */ reg-names pciephy, pciectrl; interrupts 18; ranges 0x81000000 0 0 0xE0010000 0 0x00010000 /* I/O空间 */ 0x82000000 0 0xE0020000 0xE0020000 0 0x04000000; /* 内存空间 */ };reg属性采用起始地址 长度的格式定义物理寄存器区域。实际开发中需注意地址和长度值使用大端格式存储多段寄存器区域需保持地址对齐要求reg-names为每段区域提供可读标识interrupts属性定义中断信号连接其数值需与中断控制器定义匹配。复杂设备可能定义多个中断源interrupts 0 120 4, /* 中断号120电平触发 */ 0 121 1; /* 中断号121边沿触发 */ranges属性是PCIe特有的复杂结构其格式为PCI地址空间类型 PCI地址 CPU地址 长度其中地址空间类型决定了资源类型0x81000000I/O空间0x82000000内存空间0x83000000预取内存空间2. 内核启动时的资源转换机制内核在启动阶段通过of_platform系列函数完成设备树到设备资源的转换。这个过程主要涉及三个关键步骤2.1 平台设备创建流程of_platform_bus_create() → of_platform_device_create_pdata() → of_device_alloc()在of_device_alloc()中资源转换的核心代码如下for (i 0; i num_reg; i, res) { rc of_address_to_resource(np, i, res); WARN_ON(rc); } if (of_irq_to_resource_table(np, res, num_irq) ! num_irq) pr_debug(not all IRQ resources mapped for %s\n, np-name);2.2 地址资源转换细节of_address_to_resource()完成物理地址到resource结构的转换int of_address_to_resource(struct device_node *dev, int index, struct resource *r) { const __be32 *addrp; u64 size; unsigned int flags; addrp of_get_address(dev, index, size, flags); if (!addrp) return -EINVAL; return __of_address_to_resource(dev, addrp, size, flags, NULL, r); }转换过程中会处理以下关键信息地址大小端转换资源标志位设置IORESOURCE_MEM/IORESOURCE_IO地址空间映射检查2.3 中断资源特殊处理与内存资源不同中断号需要经过额外映射int of_irq_to_resource(struct device_node *dev, int index, struct resource *r) { int irq of_irq_get(dev, index); if (irq 0) return irq; r-start r-end irq; r-flags IORESOURCE_IRQ | irqd_get_trigger_type( irq_get_irq_data(irq)); return irq; }中断映射过程中需注意可能涉及硬件中断号到Linux软件中断号的转换中断触发类型边沿/电平的自动获取中断控制器级联情况下的多级映射3. 驱动中的资源获取实践驱动开发者主要通过以下API获取预处理好的资源3.1 内存资源获取struct resource *regs platform_get_resource_byname(pdev, IORESOURCE_MEM, pciectrl); port-base devm_ioremap_resource(dev, regs);典型开发模式包括通过名称或索引获取resource结构使用devm_ioremap_resource完成内存映射检查映射结果IS_ERR3.2 中断资源处理int irq platform_get_irq(pdev, 0); ret devm_request_irq(dev, irq, handler, flags, name, dev);中断处理需注意共享中断需设置IRQF_SHARED标志中断处理函数的上下文限制中断线程化处理方案3.3 PCIe特殊资源解析对于PCIe Host控制器需要特殊处理ranges属性struct of_pci_range_parser parser; struct of_pci_range range; of_pci_range_parser_init(parser, np); for_each_of_pci_range(parser, range) { if (range.flags IORESOURCE_IO) { /* 处理I/O空间 */ } if (range.flags IORESOURCE_MEM) { /* 处理内存空间 */ } }PCIe资源解析关键点区分不同类型地址空间处理CPU与PCI地址的转换考虑64位地址支持4. 实战案例ASR1803平台PCIe驱动分析以ASR1803平台为例完整展示资源传递链路4.1 设备树定义pcie0: pcie0xd4288000 { reg 0xd4210000 0x800, 0xd4288000 0x1000; reg-names pciephy, pciectrl; interrupts 18; ranges 0x81000000 0 0 0xE0010000 0 0x00010000 0x82000000 0 0xE0020000 0xE0020000 0 0x04000000; };4.2 驱动资源获取static int xxx_pcie_parse_port(struct falcon_pcie *pcie, struct device_node *node, int slot) { struct platform_device *pdev to_platform_device(pcie-dev); /* 获取PHY寄存器区域 */ regs platform_get_resource_byname(pdev, IORESOURCE_MEM, pciephy); port-phy_base (void __iomem *)regs-start; /* 获取控制寄存器区域 */ regs platform_get_resource_byname(pdev, IORESOURCE_MEM, pciectrl); port-base devm_ioremap_resource(pdev-dev, regs); /* 获取中断资源 */ ret of_property_read_u32(node, interrupts, port-irq); ret devm_request_irq(pdev-dev, port-irq16, falcon_pcie_irq_handler, 0, falcon-pcie, port); }4.3 Host控制器初始化int __init xxx_pcie_host_init(struct falcon_pcie_port *pp) { struct of_pci_range_parser parser; struct of_pci_range range; of_pci_range_parser_init(parser, np); for_each_of_pci_range(parser, range) { if (range.flags IORESOURCE_IO) { pp-io.start range.pci_addr; pp-io.end range.pci_addr range.size - 1; } if (range.flags IORESOURCE_MEM) { pp-mem.start range.cpu_addr; pp-mem.end range.cpu_addr range.size - 1; } } }在调试这类驱动时可以通过以下命令检查资源分配情况cat /proc/iomem | grep pcie cat /proc/interrupts | grep pcie通过本文的深度剖析开发者可以系统掌握Linux PCIe设备资源分配的完整链路在实际项目中快速定位和解决资源相关问题。

更多文章