Linux PCI驱动框架分析(三)

505次阅读  |  发布于3年以前

背 景

说明:

  1. Kernel版本:4.14
  2. ARM64处理器
  3. 使用工具:Source Insight 3.5, Visio

1.概述

先回顾一下PCIe的架构图:

  1. 流程分析

那么问题来了,platform_device是在什么时候创建的呢?那就不得不提到Device Tree设备树了。

2.1 Device Tree

我们看看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>;
 };
};

关键字段描述如下:

2.2 probe流程

看一下nwl_pcie_probe函数:

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

2.3 中断处理

PCIe控制器,通过PCIe总线连接各种设备,因此它本身充当一个中断控制器,级联到上一层的中断控制器(比如GIC),如下图:

  1. Legacy Interrupt:总线提供INTA#, INTB#, INTC#, INTD#四根中断信号,PCI设备借助这四根信号使用电平触发方式提交中断请求;
  2. MSI(Message Signaled Interrupt) Interrupt:基于消息机制的中断,也就是往一个指定地址写入特定消息,从而触发一个中断;

针对两种处理方式,NWL PCIe驱动中,实现了两个irq_chip,也就是两种方式的中断控制器:

再来看一下nwl_pcie_enable_msi函数:

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

  1. 设备连接在PCI总线上,触发中断时,通过PCIe控制器充当的中断控制器路由到上一级控制器,最终路由到CPU;
  2. CPU在处理PCIe控制器的中断时,调用它的中断处理函数,也就是上文中提到过的nwl_pcie_leg_handlernwl_pcie_msi_handler_high,和nwl_pcie_leg_handler_low
  3. 在级联的中断处理函数中,调用chained_irq_enter进入中断级联处理;
  4. 调用irq_find_mapping找到具体的PCIe设备的中断号;
  5. 调用generic_handle_irq触发具体的PCIe设备的中断处理函数执行;
  6. 调用chained_irq_exit退出中断级联的处理;

2.4 总结

参考

Documentation/devicetree/bindings/pci/xlinx-nwl-pcie.txt

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8