pci设备枚举流程

概念

PCI设备:遵循PCI规范,工作在PCI局部总线环境下的设备。PCI局部总线规范指出,每个PCI设备可以包含最多8个PCI功能,每个PCI功能是一个逻辑设备

PCI桥设备:由于电子负载限制,每条PCI总线上可以挂载的设备数目是有限的因此使用了一种特殊的设备,即PCI-PCI桥设备将两条独立的PCI总线连接起来,PCI-PCI桥设备简称PCI桥

主桥设备:和CPU以及内存连在一起的Host-PCI桥设备为主桥设备,主桥设备引出的总线也称为PCI根总线。

通讯:PCI设备也有自己内存空间和IO空间,这些空间被映射到CPU的内存空间和IO空间,在映射之后,PCI设备上的物理资源“变成”了CPU的本地资源

配置

每个PCI桥设备在接收到配置事务后,判断配置目标是否在它的下游总线。若不是,则忽略该事务;若在它引出的总线上,则在这条局部总线上广播事务,否则向下游传播。而每个PCI事务决定是否认领这个配置事务,通常最终会有一个PCI设备会对这个配置事务做出响应

 配置事务的一般布局

 通过在IO地址空间特定寄存器写总线,设备号,功能,字节号,数据

static int falcon_pcie_hw_wr_cfg(struct falcon_pcie_port *port, u32 bus, u32 devfn,int where, int size, u32 *val)
{int ret;u32 value;mutex_lock(&port->lock);if (PCI_FUNC(devfn) == 0) {if (bus == 1) {if ((where != CFG_BAR0_REG) && (where != CFG_BAR1_REG)) {value = readl(port->base + PCIE_CFGNUM);writel((value|(0x1<<8)), port->base + PCIE_CFGNUM);ret = cfg_write(port->base + FALCON_PCIE_CONFIG_OFFSET+ (where & ~0x3), where, size, val);}} else if (bus == 0){/* avoid CFG_BAR0_REG/CFG_BAR1_REG to be overwritten later */if ((where != CFG_BAR0_REG) && (where != CFG_BAR1_REG)) {value = readl(port->base + PCIE_CFGNUM);writel((value&(~(0x1<<8))), port->base + PCIE_CFGNUM);ret = cfg_write(port->base + FALCON_PCIE_CONFIG_OFFSET+ (where & ~0x3), where, size, val);}}}mutex_unlock(&port->lock);return ret;
}

linux的通用配置接口位于drivers/pci/access.c

#define PCI_OP_READ(size, type, len) \
int noinline pci_bus_read_config_##size \(struct pci_bus *bus, unsigned int devfn, int pos, type *value) \
{                                                                       \int res;                                                        \unsigned long flags;                                            \u32 data = 0;                                                   \if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER;       \pci_lock_config(flags);                                         \res = bus->ops->read(bus, devfn, pos, len, &data);              \*value = (type)data;                                            \pci_unlock_config(flags);                                       \return res;                                                     \
}#define PCI_OP_WRITE(size, type, len) \
int noinline pci_bus_write_config_##size \(struct pci_bus *bus, unsigned int devfn, int pos, type value)  \
{                                                                       \int res;                                                        \unsigned long flags;                                            \if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER;       \pci_lock_config(flags);                                         \res = bus->ops->write(bus, devfn, pos, len, value);             \pci_unlock_config(flags);                                       \return res;                                                     \
}PCI_OP_READ(byte, u8, 1)
PCI_OP_READ(word, u16, 2)
PCI_OP_READ(dword, u32, 4)
PCI_OP_WRITE(byte, u8, 1)
PCI_OP_WRITE(word, u16, 2)
PCI_OP_WRITE(dword, u32, 4)EXPORT_SYMBOL(pci_bus_read_config_byte);
EXPORT_SYMBOL(pci_bus_read_config_word);
EXPORT_SYMBOL(pci_bus_read_config_dword);
EXPORT_SYMBOL(pci_bus_write_config_byte);
EXPORT_SYMBOL(pci_bus_write_config_word);
EXPORT_SYMBOL(pci_bus_write_config_dword);

主机驱动

探测函数

直接看探测函数的主要功能如下:

pci_host_bridge_priv将平台相关数据,填充到主机桥的private成员;

platform_set_drvdata再将平台相关数据,填充到device的driver_data成员

devm_pinctrl_get_select_default设置pinctrl为默认状态的设备树节点

pm_qos_add_request设定该控制器对性能的期望

device_init_wakeup将该设备设置成唤醒源,休眠的时候,会将该设备的中断使能唤醒功能

pci_host_probe注册pci主机

device_create_file给设备创建属性文件

static int pcie_probe(struct platform_device *pdev)
{struct device *dev = &pdev->dev;struct falcon_pcie *pcie;struct pci_host_bridge *host;int err;host = devm_pci_alloc_host_bridge(dev, sizeof(*pcie));if (!host)return -ENOMEM;pcie = pci_host_bridge_priv(host);pcie->dev = dev;pcie->soc = of_device_get_match_data(dev);devm_pinctrl_get_select_default(dev);err = falcon_pcie_setup(pcie);if (err)return -ENODEV;platform_set_drvdata(pdev, pcie);host->busnr = pcie->busnr;host->dev.parent = pcie->dev;host->ops = pcie->soc->ops;host->map_irq = of_irq_parse_and_map_pci;host->swizzle_irq = pci_common_swizzle;host->sysdata = pcie;pcie->host = host;pm_qos_add_request(&pcie->qos_idle, PM_QOS_CPUIDLE_BLOCK,PM_QOS_CPUIDLE_BLOCK_DEFAULT_VALUE);pcie->qos_idle.name = pdev->name;device_init_wakeup(&pdev->dev, 1);err = pci_host_probe(host);pm_qos_update_request(&pcie->qos_idle, pcie->port->lpm_qos);device_create_file(&pdev->dev, &dev_attr_pwr_ctrl);if (err)goto put_resources;return 0;put_resources:falcon_pcie_put_resources(pcie);return err;
}static struct platform_driver pcie_driver = {.probe = falcon_pcie_probe,.remove = falcon_pcie_remove,.driver = {.name = "pcie-test",.of_match_table = pcie_ids,.suppress_bind_attrs = true,.pm = &falcon_pcie_pm_ops,},
};/* Falcon PCIe driver does not allow module unload */
static int __init falcon_pcie_init(void)
{return platform_driver_probe(&falcon_pcie_driver, falcon_pcie_probe);
}
device_initcall_sync(falcon_pcie_init);//module_platform_driver(falcon_pcie_driver);

platform_driver_probe

看下面注释和代码:设备注册要先于驱动注册;只做一次探测,不支持延迟探测;一般用于soc的控制器驱动

/*** __platform_driver_probe - register driver for non-hotpluggable device* @drv: platform driver structure* @probe: the driver probe routine, probably from an __init section* @module: module which will be the owner of the driver** Use this instead of platform_driver_register() when you know the device* is not hotpluggable and has already been registered, and you want to* remove its run-once probe() infrastructure from memory after the driver* has bound to the device.** One typical use for this would be with drivers for controllers integrated* into system-on-chip processors, where the controller devices have been* configured as part of board setup.** Note that this is incompatible with deferred probing.** Returns zero if the driver registered and bound to a device, else returns* a negative error code and with the driver not registered.*/
int __init_or_module __platform_driver_probe(struct platform_driver *drv,int (*probe)(struct platform_device *), struct module *module)
{int retval, code;if (drv->driver.probe_type == PROBE_PREFER_ASYNCHRONOUS) {pr_err("%s: drivers registered with %s can not be probed asynchronously\n",drv->driver.name, __func__);return -EINVAL;}/** We have to run our probes synchronously because we check if* we find any devices to bind to and exit with error if there* are any.*/drv->driver.probe_type = PROBE_FORCE_SYNCHRONOUS;/** Prevent driver from requesting probe deferral to avoid further* futile probe attempts.*/drv->prevent_deferred_probe = true;/* make sure driver won't have bind/unbind attributes */drv->driver.suppress_bind_attrs = true;/* temporary section violation during probe() */drv->probe = probe;retval = code = __platform_driver_register(drv, module);if (retval)return retval;/** Fixup that section violation, being paranoid about code scanning* the list of drivers in order to probe new devices.  Check to see* if the probe was successful, and make sure any forced probes of* new devices fail.*/spin_lock(&drv->driver.bus->p->klist_drivers.k_lock);drv->probe = NULL;if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list))retval = -ENODEV;drv->driver.probe = platform_drv_probe_fail;spin_unlock(&drv->driver.bus->p->klist_drivers.k_lock);if (code != retval)platform_driver_unregister(drv);return retval;
}
EXPORT_SYMBOL_GPL(__platform_driver_probe);

pci_host_probe

主机去注册一个主机桥设备和bus 0;然后从这个bus递归扫描设备

pci_host_probe(bridge)pci_scan_root_bus_bridgepci_register_host_bridgepci_alloc_busdevice_add(&bridge->dev); 	// 添加device(host bridge)pcibios_add_bus(bus)  		// 添加bus (local bus 0)pci_scan_child_bus/pci_scan_child_bus_extend(bus,0)bus = bridge->bus;pci_bus_add_devices(bus);

pci_scan_child_bus_extend

先扫描普通设备,扫描就根据设备的配置空间来配置和添加设备;

再扫描桥,扫描到就添加总线。然后继续递归扫描。

pci_scan_child_bus_extendfor (devfn = 0; devfn < 256; devfn += 8)  // 针对每个devicenr_devs = pci_scan_slot(bus, devfn);for (fn = 1; fn < 8; fn++) { // 针对每个functionpci_scan_single_device(bus, devfn + fn); // 对一个function 枚举struct pci_dev *dev = pci_scan_device  // 通过配置空间来枚举设备struct pci_dev *dev = pci_alloc_dev(bus);dev->devfn = devfn;pci_setup_device(dev)   // 修改基址、数据寄存器,实际下发配置修改pci_device_add(dev)			// 添加 device(pci bridge或者普通pci设备)pci_scan_bridge_extendpci_add_new_bus						// 添加 pci buspci_scan_child_bus_extend

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1421715.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

什么是.faust勒索病毒?应该如何防御?

faust勒索病毒详细介绍 faust勒索病毒是一种新型的勒索软件&#xff0c;最早出现在2018年。该病毒通过加密计算机系统中的文件并要求支付赎金来解锁文件&#xff0c;从而获取经济利益。与传统的勒索软件相比&#xff0c;faust勒索病毒采用了更加先进的加密算法和隐藏技术&#…

国标GB28181协议EasyGBS视频监控云平台端口正常却不能播放,是什么原因?

国标视频云服务EasyGBS支持设备/平台通过国标GB28181协议注册接入&#xff0c;并能实现视频的实时监控直播、录像、检索与回看、语音对讲、云存储、告警、平台级联等功能。平台部署简单、可拓展性强&#xff0c;支持将接入的视频流进行全终端、全平台分发&#xff0c;分发的视频…

IDEA buid一直不能完成,无法运行

问题如下所示&#xff1a; 解决方案 output 路径不对&#xff0c;正确路径&#xff1a;项目目录\target\classes

难以重现的 Bug如何处理

对很多测试人员&#xff08;尤其是对新手来说&#xff09;在工作过程中最不愿遇到的一件事情就是&#xff1a;在测试过 程中发现了一个问题&#xff0c;觉得是 bug&#xff0c;再试的时候又正常了。 碰到这样的事情&#xff0c;职业素养和测试人员长期养成的死磕的习性会让她…

【数据分析面试】42.用户流失预测模型搭建(资料数据分享)

题目 保持高的客户留存率可以稳定和提到企业的收入。因此&#xff0c;预测和防止客户流失是在业务中常见的一项数据分析任务。这次分享的数据集包括了电信行业、银行、人力资源和电商行业&#xff0c;涵盖了不同业务背景下的流失预测数据。 后台回复暗号&#xff08;在本文末…

Nios-II编程

文章目录 一硬件部分设计1Qsys2Quartus 二软件1Nios-II Eclipse 三运行项目及效果1配置 FPGA 一硬件部分设计 1Qsys 1创建一个项目 2点击 Tools 下拉菜单下的 Platform Designer 工具&#xff0c;启动 Platform Designer 后&#xff0c;点击 File-save&#xff0c;在文件名中…

用命令运行Java程序

1、创建一个类 2、在类文件路径下执行命令(编译)&#xff0c;生成.class javac 类名.java 3、运行.class文件 java 类名

使用 Docker 部署 WebTop 运行 Linux 系统

1&#xff09;项目介绍 GitHub&#xff1a;https://github.com/linuxserver/docker-webtop WebTop 它是一个基于 Linux &#xff08; Ubuntu 和 Alpine 两种版本&#xff09;的轻量级容器&#xff0c;具有在浏览器中运行的完整桌面环境&#xff0c;具有基本的窗口管理器、像素…

持续集成-Git

重要步骤命令 git init (初始化一个仓库) git add [文件名] (添加新的文件) git commit -m [关于本次提交的相关说明] (提交) git status (查看文件状态) git diff (如果文件改变&#xff0c;比较两个文件内容) git add[文件名] || git commit -a -m [关于本次提交的相关说…

天诚AIoT无线联网智能门锁即将亮相成都安博会、永康门博会

5月上旬&#xff0c;对于江苏新巢天诚智能技术有限公司&#xff08;以下简称“天诚”&#xff09;而言&#xff0c;依旧忙得如火如荼。随着各地人才公寓、公租房、智慧校园类智慧通行与租住新项目的实施、落地与服务&#xff0c;天诚也不忘初心&#xff0c;携全新升级的AIoT全场…

百亿补贴为什么用 H5?H5 未来会如何发展?

百亿补贴为什么用 H5&#xff1f;H5 未来会如何发展&#xff1f; 本人有一些分析预测。当然&#xff0c;这些分析预测只是个人观点&#xff0c;如果你有不同的意见&#xff0c;欢迎在评论区讨论交流。 百亿补贴为什么用 H5 我们先看两张图&#xff0c;在 Android 手机开发者…

Redis-详解(基础)

文章目录 什么是Redis&#xff1f;用Redis的特点&#xff1f;用Redis可以实现哪些功能&#xff1f;Redis的常用数据类型有哪些?Redis的常用框架有哪些?本篇小结 更多相关内容可查看 什么是Redis&#xff1f; Redis&#xff08;Remote DictionaryServer&#xff09;是一个开源…

vue3.0(八) 监听器(watch),高级监听器(watchEffect)

文章目录 watch1 watch的用法2 watch的高级用法3 watch性能优化 watchEffect1 停止监听2 侦听多个状态3 懒执行 watch和watchEffect的区别watch和computed的区别 watch watch特性进行了一些改变和优化。与computed不同&#xff0c;watch通常用于监听数据的变化&#xff0c;并执…

设计模式-工厂模式设计与详解

一、设计模式介绍 设计模式是我们开发中常常需要面对的核心概念&#xff0c;它们是解决特定问题的模板或者说是经验的总结。这些模式被设计出来是为了让软件设计更加清晰、代码更加可维护且能应对未来的变化。良好的设计模式不仅能解决重复代码的问题&#xff0c;还能使团队中…

object.key()用法

object.key(obj) 一、概念&#xff1a;返回一个由一个给定对象的自身可枚举属性组成的数组。 二、用法&#xff1a; 1、参数为对象&#xff1a;则返回为 对象属性名组成的数组。 let obj {日期&#xff1a;date,姓名&#xff1a;userName,地址:address}console.log(Object.k…

作业帮重启k12,保底年薪150万。。。

作业帮 近期&#xff0c;一位学而思前员工在脉脉上爆料发问&#xff1a; 收到猎头电话&#xff0c;说作业帮重启 K12&#xff0c;K12 主讲无责保底年薪 150W&#xff0c;base 北京。 楼下评论区一位新东方在职员工表示&#xff0c;似乎有这事儿&#xff1a; 而另外一个网友则表…

WordPress/Typecho 站点使用 CloudFlare 后优化加速方法以及注意事项

目前很多 WordPress 站长都盲目的认为使用了 CloudFlare 后,站点速度明显感觉慢了很多,加上一些别有用心的人(有些人就是这么不喜欢 CloudFlare,你品,你细品!) 再制作一个使用 CloudFlare 站点的测速结果截图,让很多 WordPress 新手站长们谈 CloudFlare 色变。其实大家…

Android Studio开发之路(十)app中使用aar以及报错记录

书接上文&#xff1a;Android Studio开发之路&#xff08;九&#xff09;创建android library以及生成aar文件 五、app中使用aar文件的方法 先复制一下上面生成的aar文件。然后在你要添加到的app左上角选择“project”模式&#xff0c;然后找到libs文件夹&#xff0c;点击右键…

#初阶模板

目录 1.泛型编程 2.模板 &#xff08;1&#xff09;函数模板 &#xff08;2&#xff09;举个栗子&#xff08;模板的使用&#xff09; 1.模板的声明有两种形式 2.函数模板的原理 &#xff08;3&#xff09;模板参数的匹配原则 &#xff08;4&#xff09;类模板 类模板…

探索免费静态IP海外的奥秘

在数字化时代&#xff0c;网络资源的获取和利用对于个人和企业都至关重要。其中&#xff0c;独立静态IP地址更是因其稳定性和安全性备受青睐。本文将带您深入了解“免费的独立静态IP海外”的奥秘&#xff0c;探讨其背后的原理、优势、获取途径以及使用场景。 一、独立静态IP的基…