pcie 驱动程序分析
来源:互联网 发布:bae 数据库 编辑:程序博客网 时间:2024/06/07 18:43
<<Linux那些事儿之我是PCI>> 已经告诉我们如何从do_initcalls找到找到PCI 驱动的入口
postcore_initcall(pcibus_class_init);
postcore_initcall(pci_driver_init);
文件
函数
入口
内存位置
arch/i386/pci/acpi.c
pci_acpi_init
subsys_initcall
.initcall4.init
arch/i386/pci/common.c
pcibios_init
subsys_initcall
.initcall4.init
arch/i386/pci/i386.c
pcibios_assign_resources
fs_initcall
.initcall5.init
arch/i386/pci/legacy.c
pci_legacy_init
drivers/pci/pci-acpi.c
acpi_pci_init
arch_initcall
.initcall3.init
drivers/pci/pci- driver.c
pci_driver_init
postcore_initcall
.initcall2.init
drivers/pci/pci- sysfs.c
pci_sysfs_init
late_initcall
.initcall7.init
drivers/pci/pci.c
pci_init
device_initcall
.initcall6.init
drivers/pci/probe.c
pcibus_class_init
postcore_initcall
.initcall2.init
drivers/pci/proc.c
pci_proc_init
__initcall
.initcall6.init
arch/i386/pci/init.c
pci_access_init
arch_initcall
.initcall3.init
我们这里是海思3536 arm系统稍微修改一下:
文件
函数
入口
内存位置
drivers/pci/hipcie/pcie.c
acpi_pci_init
subsys_initcall
.initcall4.init
drivers/pci/pci- driver.c
pci_driver_init
postcore_initcall
.initcall2.init
drivers/pci/pci- sysfs.c
pci_sysfs_init
late_initcall
.initcall7.init
drivers/pci/pci.c
pci_init
device_initcall
.initcall6.init
drivers/pci/probe.c
pcibus_class_init
postcore_initcall
.initcall2.init
drivers/pci/proc.c
pci_proc_init
__initcall
.initcall6.init
上述函数注册了PCI class和总线驱动,总线级别的驱动早已经被那些技术大牛们开发好了,我们不用太关注其PCI总线驱动的实现细节,我们从hisi_pcie_init看看驱动程序是如何工作的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
来自CODE的代码片snippet_file_0.txt
函数分析static int __init hisi_pcie_init(void)
1. 注册device和driver
ret = platform_device_register(&hisi_pcie_platform_device); //注册设备
ret = platform_driver_register(&hisi_pcie_platform_driver); //注册驱动
2.pcie_init();//hisi平台硬件寄存器相关基地址及寄存器配置;重点看这里哦!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
来自CODE的代码片snippet_file_0.txt
1.__arch_pcie_info_setup(pcie_info, &pcie_controllers_nr)
2.__arch_pcie_sys_init(pcie_info)
3.pci_common_init(&hipcie);
我们一个个来看:
__arch_pcie_info_setup 完成重要的MEM/IO基地址映射
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
来自CODE的代码片snippet_file_0.txt
Reset=>PCIE RC work mode=>Enable clk=>Set PCIE controller class code to be PCI-PCI bridge device=>Enable controller
pci_common_init(&hipcie);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
来自CODE的代码片snippet_file_0.txt
函数分析:
struct hw_pci 是关键,PCIE host驱动的开发,主要是填充该数据结构,把函数一个个实现,我们跟着代码来看一看
1. pcibios_init_hw(hw, &head);该函数初始化每一个controller,并且递归枚举它的子总线
1.1 ret = hw->setup(nr, sys);
1.2 ret = pcibios_init_resources(nr, sys);
1.3 sys->bus = hw->scan(nr, sys);
调用.setup即调用pcie_setup,这里关注两个函数:ret = request_pcie_res(info->controller, sys);
__arch_config_iatu_tbl(info, sys); 只有执行此config后,PCIE才能实现CFG_TYPE0 和CFG_TYPE1的配置事务访问(寄存器的具体配置请结合datasheet ATU地址转换)
调用.scan即调用pcie_scan_bus,它从主总线开始扫描总线上的PCI设备。一旦发现PCI-PCI桥,就初始化一条子总线,并且继续扫描子总线上的设备。这里注意
bus = pci_scan_root_bus(NULL, sys->busnr, &pcie_ops, sys, &sys->resources);
其中pcie_ops的定义:
static struct pci_ops pcie_ops = {
.read = pcie_read_conf,
.write = pcie_write_conf,
};
看到这里大家有点熟悉了没有PCIE设备驱动开发中常见的一组函数:
int pci_read_config_byte(struct pci_dev *pdev, int where, u8 *val);
int pci_read_config_word(struct pci_dev *pdev, int where, u8 *val);
int pci_read_config_dword(struct pci_dev *pdev, int where, u8 *val);
int pci_write_config_byte(struct pci_dev *pdev, int where, u8 *val);int pci_write_config_word(struct pci_dev *pdev, int where, u8 *val);int pci_write_config_dword(struct pci_dev *pdev, int where, u8 *val);
这组配置空间的读写函数,其实现就是pcie_ops,只有实现了该函数才能对PCIE设备读写,也只有实现了该函数pcie_scan_bus 才能完成总线上设备的扫描。
pci_scan_root_bus=>
pci_create_root_bus=>
pci_scan_child_bus(b);=>
pci_bus_add_devices(b); 完成扫描!!!
现在我们来看看pcie_ops 的read/write函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
来自CODE的代码片snippet_file_0.txt
配置事务读写就这样被实现了,从此我们可以轻松的访问PCIE配置空间:
- pcie 驱动程序分析
- pcie 驱动程序分析
- uboot中PCIe驱动程序说明
- uboot中PCIe驱动程序说明
- PCIE-rapidio-ethernet分析
- pcie
- pcie
- PCIE
- PCIE
- PCIE
- 从PCIe trace中分析NVMe
- PCI/PCIe接口卡Windows驱动程序(4)- 驱动程序代码(源文件)
- 基于WDF的PCI/PCIe接口卡Windows驱动程序(3)- 驱动程序代码(头文件)
- 基于WDF的PCI/PCIe接口卡Windows驱动程序(4)- 驱动程序代码(源文件)
- 驱动程序的分析技巧
- RTL8139网卡驱动程序分析
- piaoxue/feixue驱动程序分析
- IIS音频驱动程序分析
- 二叉树的各种操作(遍历/深度/距离/转换)
- ORB-SLAM(六)回环检测
- zoj 3509
- 最长公共子串与最长公共子序列
- FreeImage 3.17.0 在VS2015下编译及遇到问题解决
- pcie 驱动程序分析
- JAVA选择排序
- js日历控件
- struts2粗略总结
- select函数详解及其在I|O复用模型中的应用
- 1048. 数字加密(20)
- 计算机进制转换
- 基于vue-cli及express模拟Ajax获取服务器数据
- Spring学习之Bean的装配