Linux PCI驱动框架分析(三)

本文详细解析了PCIeHost在设备树中的配置,包括compatible字段、MSI控制器、中断处理等关键信息。介绍了PCIeHost驱动的probe流程,涉及设备初始化、中断注册以及PCI总线枚举。同时,阐述了PCIe的Legacy Interrupt和MSI Interrupt两种中断处理方式,并分析了中断处理流程。
摘要由CSDN通过智能技术生成

我们看看PCIe Host的设备树内容:

pcie: pcie@fd0e0000 {
compatible = “xlnx,nwl-pcie-2.11”;
status = “disabled”;
#address-cells = <3>;
#size-cells = <2>;
#interrupt-cells = <1>;
msi-controller;
device_type = “pci”;

interrupt-parent = <&gic>;
interrupts = <0 118 4>,
	     <0 117 4>,
	     <0 116 4>,
	     <0 115 4>,	/* MSI_1 [63...32] */
	     <0 114 4>;	/* MSI_0 [31...0] */
interrupt-names = "misc", "dummy", "intx", "msi1", "msi0";
msi-parent = <&pcie>;

reg = <0x0 0xfd0e0000 0x0 0x1000>,
      <0x0 0xfd480000 0x0 0x1000>,
      <0x80 0x00000000 0x0 0x1000000>;
reg-names = "breg", "pcireg", "cfg";
ranges = <0x02000000 0x00000000 0xe0000000 0x00000000 0xe0000000 0x00000000 0x10000000	/* non-prefetchable memory */
	  0x43000000 0x00000006 0x00000000 0x00000006 0x00000000 0x00000002 0x00000000>;/* prefetchable memory */
bus-range = <0x00 0xff>;

interrupt-map-mask = <0x0 0x0 0x0 0x7>;
interrupt-map =     <0x0 0x0 0x0 0x1 &pcie_intc 0x1>,
		    <0x0 0x0 0x0 0x2 &pcie_intc 0x2>,
		    <0x0 0x0 0x0 0x3 &pcie_intc 0x3>,
		    <0x0 0x0 0x0 0x4 &pcie_intc 0x4>;

pcie_intc: legacy-interrupt-controller {
	interrupt-controller;
	#address-cells = <0>;
	#interrupt-cells = <1>;
};

};
关键字段描述如下:

compatible:用于匹配PCIe Host驱动;
msi-controller:表示是一个MSI(Message Signaled Interrupt)控制器节点,这里需要注意的是,有的SoC中断控制器使用的是GICv2版本,而GICv2并不支持MSI,所以会导致该功能的缺失;
device-type:必须是"pci";
interrupts:包含NWL PCIe控制器的中断号;
interrupts-name:msi1, msi0用于MSI中断,intx用于旧式中断,与interrupts中的中断号对应;
reg:包含用于访问PCIe控制器操作的寄存器物理地址和大小;
reg-name:分别表示Bridge registers,PCIe Controller registers, Configuration space region,与reg中的值对应;
ranges:PCIe地址空间转换到CPU的地址空间中的范围;
bus-range:PCIe总线的起始范围;
interrupt-map-mask和interrupt-map:标准PCI属性,用于定义PCI接口到中断号的映射;
legacy-interrupt-controller:旧式的中断控制器;
2.2 probe流程
系统会根据dtb文件创建对应的platform_device并进行注册;
当驱动与设备通过compatible字段匹配上后,会调用probe函数,也就是nwl_pcie_probe;

看一下nwl_pcie_probe函数:

通常probe函数都是进行一些初始化操作和注册操作:
初始化包括:数据结构的初始化以及设备的初始化等,设备的初始化则需要获取硬件的信息(比如寄存器基地址,长度,中断号等),这些信息都从DTS而来;
注册操作主要是包含中断处理函数的注册,以及通常的设备文件注册等;

针对PCI控制器的驱动,核心的流程是需要分配并初始化一个pci_host_bridge结构,最终通过这个bridge去枚举PCI总线上的所有设备;
devm_pci_alloc_host_bridge:分配并初始化一个基础的pci_hsot_bridge结构;
nwl_pcie_parse_dt:获取DTS中的寄存器信息及中断信息,并通过irq_set_chained_handler_and_data设置intx中断号对应的中断处理函数,该处理函数用于中断的级联;
nwl_pcie_bridge_init:硬件的Controller一堆设置,这部分需要去查阅Spec,了解硬件工作的细节。此外,通过devm_request_irq注册misc中断号对应的中断处理函数,该处理函数用于控制器自身状态的处理;
pci_parse_request_of_pci_ranges:用于解析PCI总线的总线范围和总线上的地址范围,也就是CPU能看到的地址区域;
nwl_pcie_init_irq_domain和mwl_pcie_enable_msi与中断级联相关,下个小节介绍;
pci_scan_root_bus_bridge:对总线上的设备进行扫描枚举,这个流程在Linux PCI驱动框架分析(二)中分析过。brdige结构体中的pci_ops字段,用于指向PCI的读写操作函数集,当具体扫描到设备要读写配置空间时,调用的就是这个函数,由具体的Controller驱动实现;
2.3 中断处理
PCIe控制器,通过PCIe总线连接各种设备,因此它本身充当一个中断控制器,级联到上一层的中断控制器(比如GIC),如下图:

PCIe总线支持两种中断的处理方式:
Legacy Interrupt:总线提供INTA#, INTB#, INTC#, INTD#四根中断信号,PCI设备借助这四根信号使用电平触发方式提交中断请求;
MSI(Message Signaled Interrupt) Interrupt:基于消息机制的中断,也就是往一个指定地址写入特定消息,从而触发一个中断;
针对两种处理方式,NWL PCIe驱动中,实现了两个irq_chip,也就是两种方式的中断控制器:

irq_domain对应一个中断控制器(irq_chip),irq_domain负责将硬件中断号映射到虚拟中断号上;
来一张旧图吧,具体文章可以去参考中断子系统相关文章;

再来看一下nwl_pcie_enable_msi函数:

在该函数中主要完成的工作就是设置级联的中断处理函数,级联的中断处理函数中最终会去调用具体的设备的中断处理函数;

所以,稍微汇总一下,作为两种不同的中断处理方式,套路都是一样的,都是创建irq_chip中断控制器,为该中断控制器添加irq_domain,具体设备的中断响应流程如下:

设备连接在PCI总线上,触发中断时,通过PCIe控制器充当的中断控制器路由到上一级控制器,最终路由到CPU;
CPU在处理PCIe控制器的中断时,调用它的中断处理函数,也就是上文中提到过的nwl_pcie_leg_handler,nwl_pcie_msi_handler_high,和nwl_pcie_leg_handler_low;
在级联的中断处理函数中,调用chained_irq_enter进入中断级联处理;
调用irq_find_mapping找到具体的PCIe设备的中断号;
调用generic_handle_irq触发具体的PCIe设备的中断处理函数执行;
调用chained_irq_exit退出中断级联的处理;
USB Microphone https://www.soft-voice.com/
Wooden Speakers https://www.zeshuiplatform.com/
亚马逊测评 www.yisuping.cn
深圳网站建设www.sz886.com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值