当前位置: 首页 > news >正文

PCI 总线学习笔记(五)

PCI 总线学习系列,参考自
技术大牛博客: PCIe 扫盲系列博文连载目录篇
书籍:王齐老师的《PCI Express 体系结构导读》


下面的文章中加入了自己的一些理解和实际使用中遇到的一些场景,供日后查询和回忆使用

PCI 总线定义了两类配置请求, 一类是 Type 00h 配置请求, 另一类是 Type 01h 配置请求。 PCI 总线使用这些配置请求访问 PCI 总线树上的设备配置空间, 包括 PCI 桥和 PCI Agent 设备的配置空间。

  • Type 00h 配置请求:用于访问与 HOST 主桥或者 PCI 桥直接相连的 PCI Agent 设备或者 PCI 桥(仅能传递给目标设备,而不会被进一步转发)
  • Type 01h 配置请求: HOST 主桥或者 PCI 桥使用 Type 01h 配置请求, 需要至少穿越一个 PCI 桥, 访问没有与其直接相连的 PCI Agent 设备或者 PCI 桥(配置请求可以被进一步转发)

1、Type 01h 和Type 00h 配置请求

  在 PCI 总线中, 只有 PCI 桥能够接收 Type 01h 配置请求。Type 01h 配置请求不能直接发向最终的 PCI Agent 设备, 而只能由 PCI 桥将其转换为 Type 01h 继续发向其他 PCI 桥, 或者转换为 Type 00h 配置请求发向 PCI Agent 设备。

  以 x86 系统为例,在地址周期中, HOST 主桥使用配置读写总线事务, 将 CONFIG_ADDRESS 寄存器的内容复制到 PCI 总线的 AD [31∶0] 信号线中。 CONFIG_ADDRESS 寄存器与 Type 01h 配置请求的对应关系如下图所示
在这里插入图片描述

  从上图中可以发现, CONFIG_ADDRESS 寄存器的内容基本上是原封不动地复制到 PCI 总线的AD [31∶0] 信号线上的。 其中 CONFIG_ADDRESS 的 Enable 位不被复制, 而 AD 总线的第 0 位必须为 1, 表示当前配置请求是 Type 01h。

  当 PCI 总线接收到 Type01 配置请求时, 将寻找合适的 PCI 桥接收这个配置信息。 如果这个配置请求是直接发向 PCI 桥下的与之直接相连的 PCI 设备时, PCI 桥将接收这个 Type 01 配置请求,并将其转换为 Type 00h 配置请求; 否则 PCI 桥将当前 Type 01h 配置请求原封不动地传递给下一级 PCI 总线。

  如果 HOST 主桥或者 PCI 桥发起的是 Type 00h 配置请求, CONFIG_ADDRESS 寄存器与 AD [31∶0] 的转换如下图所示:
在这里插入图片描述

  此时处理器对 CONFIG_DATA 寄存器进行读写时, 处理器将 CONFIG_ADDRESS 寄存器中的 Function Number 和 Register Number 字段复制到 PCI 的 AD 总线的第10 ~2 位; 将 AD 总线的第 1~0 位赋值为 0b00。 PCI 总线在配置请求总线事务的地址周期根据 AD [1∶0] 判断当前配置请求是 Type 00h 还是 Type 01h。

如果 AD [1∶0] 等于 0b 00 表示是 Type 00h 配置请求, 如果 AD [1∶0] 等于 0b 01 表示是 Type 01h 配置请求

  而 AD [31∶11] 与 CONFIG_ADDRESS 的 Device Number 字段有关, 在 Type 00h 配置请求的地址周期中, AD [31∶11] 位有且只有一位为 1, 其中 AD [31∶11] 的每一位选通一个 PCI 设备的配置空间。 PCI 设备配置空间的片选信号是 IDSEL, 因此 AD[31∶ 11] 将与 PCI 设备的 IDSEL 信号对应相连

从这里可以知道, PCI 协议中的设备号,是由 PCI 设备的 IDSEL 信号线,与 PCI 总线上的地址线 AD[0 : 31] 的硬件连接关系确定的

1.1、总结

  上面讲解的东西,更多的是为了理解 PCI 协议,真正在 PCI 总线驱动开发上用到的不多。比较常用的就是配置 HOST 主桥发出的到底是 Type 00h 还是 Type 01h 配置请求。

  有些板卡,硬件上已经配置好 HOST 发出的到底是 Type 00h 还是 Type 01h 配置请求,我们无需关心。有些板卡更灵活,需要我们手动在软件上去配置,例如:当访问的 bus 号为当前 PCI 控制器起始 bus 号 + 1 时,使用 Type 00h 配置请求;否则就是 Type 01h 配置请求。了解了底层的原理,这里我们具体场景具体分析就行,不必拘泥。

1.2 代码实例

以 rk3568 为例:

static void __iomem *rk_pcie_ecam_map_bus(struct pci_bus *bus, unsigned int devfn, int where)
{
....../*  如果访问的是 root bus,使用 Type 00h,不需要转发;否则使用  Type 01h*/if (pci_is_root_bus(bus->parent))atu_type = PCIE_ATU_TYPE_CFG0;elseatu_type = PCIE_ATU_TYPE_CFG1;
......
}

以 Linux 源码中,dw IP 核代码为例:

static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,u32 devfn, int where, int size, u32 *val)
{
......if (bus->parent->number == pp->root_bus_nr) {type = PCIE_ATU_TYPE_CFG0;cpu_addr = pp->cfg0_base;cfg_size = pp->cfg0_size;va_cfg_base = pp->va_cfg0_base;} else {type = PCIE_ATU_TYPE_CFG1;cpu_addr = pp->cfg1_base;cfg_size = pp->cfg1_size;va_cfg_base = pp->va_cfg1_base;}
......
}

2、PCI 总线配置请求的转换原则

  当 CONFIG_ADDRESS 寄存器的 Enable 位为 1, 系统软件访问 CONFIG_DATA 寄存器时,HOST 主桥可以产生两类 PCI 总线配置读写总线事务, 分别为 Type 00h 和 Type 01h 配置读写总线事务。 在配置读写总线事务的地址周期和数据周期中,CONFIG_ADDRESS 和 CONFIG_DATA 寄存器中的数据将被放置到 PCI 总线的 AD 总线上。 其中 Type 00h 和 Type 01h 配置读写总线事务映射到 AD 总线的数据并不相同。

  其中 Type 00h 配置请求可以直接读取 PCI Agent 设备的配置空间, 而 Type 01h 配置请求在通过 PCI 桥时, 最终将被转换为 Type 00h 配置请求, 并读取 PCI Agent 设备的配置寄存器。 本节重点讲述 PCI 桥如何将 Type 01h 配置请求转换为 Type 00h 配置请求。

  首先 Type 00h 配置请求不会被转换成 Type 01h 配置请求, 因为 Type 00h 配置请求是发向最终 PCI Agent 设备, 这些 PCI Agent 设备不会转发这些配置请求。当 CONFIG_ADDRESS 寄存器的 Bus Number 字段为 0 时, 处理器对 CONFIG_DATA 寄存器操作时, HOST 主桥将直接产生 Type 00h 配置请求, 挂接在 PCI 总线 0 上的某个设备将通过 ID 译码接收这个 Type 00h 配置请求, 并对配置寄存器进行读写操作。 如果 PCI 总线上没有设备接收这个 Type 00h 配置请求, 将引发 Master Abort, 详情见 PCI 总线规范, 本节对此不做进一步说明。

  如果 CONFIG_ADDRESS 寄存器的 Bus Number 字段为 n ( n≠ 0), 即访问的 PCI 设备不是直接挂接在 PCI 总线 0 上的, 此时 HOST 主桥对 CONFIG_DATA 寄存器操作时, 将产生Type 01h 配置请求, PCI 总线 0 将遍历所有在这条总线上的 PCI 桥, 确定由哪个 PCI 桥接收这个 Type 01h 配置请求。如果 n 大于或等于某个 PCI 桥的 Secondary Bus Number 寄存器, 而且小于或等于 Subordinate Bus number 寄存器, 那么这个 PCI 桥将接收在当前 PCI 总线上的 Type 01 配置请求,并采用以下规则进行递归处理:

  1. 开始。
  2. 遍历当前 PCI 总线的所有 PCI 桥。
  3. 如果 n 等于某个 PCI 桥的 Secondary Bus Number 寄存器, 说明这个 Type 01 配置请求的目标设备直接连接在该 PCI 桥的 Secondary bus 上。 此时 PCI 桥将 Type 01 配置请求转换为 Type 00h 配置请求, 并将这个配置请求发送到 PCI 桥的 Secondary Bus 上, Secondary Bus 上的某个设备将响应这个 Type 00h 配置请求, 并与 HOST 主桥进行配置信息的交换,转 (5) 。
  4. 如果 n 大于 PCI 桥的 Secondary Bus Number 寄存器, 而且小于或等于 PCI 桥的 Subordinate Bus number 寄存器, 说明这个 Type 01 配置请求的目标设备不与该 PCI 桥的 Secondary Bus 直接相连, 但是由这个 PCI 桥下游总线上的某个 PCI 桥管理。 此时 PCI 桥将首先认领这个 Type 01 配置请求, 并将其转发到 Secondary Bus, 转 (2)。
  5. 结束。

3、PCI 总线树 Bus 号的初始化

参考 PCI 总线学习笔记(三)

4、PCI 总线 Device 号的分配

  一条 PCI 总线会挂接各种各样的 PCI 设备, 而每一个 PCI 设备在 PCI 总线下具有唯一的设备号。 系统软件通过总线号和设备号定位一个 PCI 设备之后, 才能访问这个 PCI 设备的配置寄存器。

  PCI 设备的 IDSEL 信号与 PCI 总线的 AD [31∶ 0] 信号的连接关系决定了该设备在这条 PCI 总线的设备号。 如上文所述, 每一个 PCI 设备都使用独立的 IDSEL 信号, 该信号将与 PCI 总线的 AD [31∶ 0] 信号连接, IDSEL 信号的含义见第 PCI 总线学习笔记(一)。

  在此我们简要回顾 PCI 的配置读写事务使用的时序。 如下图所示, PCI 总线事务由一个地址周期加若干个数据周期组成。 在进行配置读写请求总线事务时, C / BE# 信号线的值在地址周期中为 0x1010 或者为 0x1011, 表示当前总线事务为配置读或者配置写请求。 此时出现在 AD [31∶ 0] 总线上的值并不是目标设备的 PCI 总线地址, 而是目标设备的 ID 号, 这与 PCI 总线进行 I / O 或者存储器请求时不同, 因为 PCI 总线使用 ID 号而不是 PCI 总线地址对配置空间进行访问。
在这里插入图片描述
  如图 2-12 所示, 在配置读写总线事务的地址周期中, AD [10∶ 0] 信号已经被 Function Number 和 Register Number 使用, 因此 PCI 设备的 IDSEL 只能与 AD [31∶ 11] 信号连接。认真的读者一定可以发现在 CONFIG_ADDRESS 寄存器中 Device Number 字段一共有 5 位可以表示 32 个设备, 而 AD [31∶ 11] 只有 21 位, 显然在这两者之间无法建立一一对应的映射关系。 因此在一条 PCI 总线上如果有 21 个以上的 PCI 设备, 那么总是有几个设备无法与 AD [31∶ 11] 信号线连接, 从而 PCI 总线无法访问这些设备。 因为 PCI 总线在配置请求的地址周期中, 只能使用第 31 ~ 11 这些 AD 信号, 所以在一条总线上最多也只能挂接 21 个 PCI 设备。 这 21 个设备可能是从 0 到 20, 也可能是从 11 到 31 排列。 从而系统软件在遍历 PCI 总线时, 还是需要从 0 到 31 遍历整条 PCI 总线。

在这里插入图片描述

  在实际的应用中, 一条 PCI 总线能够挂接 21 个设备已经足够了, 实际上由于 PCI 总线的负载能力有限, 即便在总线频率为 33 MHz 的情况下, 在一条 PCI 总线中最多也只能挂接 10 个负载, 一条 PCI 总线所能挂接的负载详见表 1-1。 AD 信号线与 PCI 设备 IDSEL 线的连接关系如图 2-14 所示
在这里插入图片描述

  PCI 总线推荐了一种 Device Number 字段与 AD [31∶ 16] 之间的映射关系。 其中 PCI 设备 0 与 Device Number 字段的 0b00000 对应; PCI 设备 1 与 Device Number 字段的 0b00001 对应, 并以此类推, PCI 设备 15 与 Device Number 字段的 0b01111 对应。

  在这种映射关系之下, 一条 PCI 总线中, 与信号线 AD16 相连的 PCI 设备的设备号为 0;与信号线 AD17 相连的 PCI 设备的设备号为 1; 以此类推, 与信号线 AD31 相连的 PCI 设备的设备号为 15。 在 Type 00h 配置请求中, 设备号并没有像 Function Number 和 Register Number 那样以编码的形式出现在 AD 总线上, 而是与 AD 信号一一对应, 如图 2-12 所示。

  这里有一个原则需要读者注意, 就是对 PCI 设备的配置寄存器进行访问时, 一定要有确定的 Bus Number、 Device Number、 Function Number 和 Register Number, 这 “四元组” 缺一不可。 在 Type 00h 配置请求中, Device Number 由 AD [31∶ 11] 信号线与 PCI 设备 IDSEL 信号的连接关系确定; Function Number 保存在 AD [10∶ 8] 字段中; 而 Register Number 保存在 AD [7∶ 2] 字段中; 在 Type 01h 配置请求中, 也有完整的四元组信息。


http://www.mrgr.cn/news/100186.html

相关文章:

  • 蜜罐管理和数据收集服务器:Modern Honey Network (MHN)
  • 高效使用DeepSeek对“情境+ 对象 +问题“型课题进行开题!
  • ClickHouse 中`MergeTree` 和 `ReplicatedMergeTree`表引擎区别
  • C++23中if consteval / if not consteval (P1938R3) 详解
  • 图解YOLO(You Only Look Once)目标检测(v1-v5)
  • windows作业job介绍
  • 【音视频】⾳频处理基本概念及⾳频重采样
  • Virtuoso ADE采用Spectre仿真中出现MOS管最小长宽比满足要求依然报错的情况解决方法
  • 解读《数据资产质量评估实施规则》:企业数据资产认证落地的关键指南
  • 语音合成之六端到端TTS模型的演进
  • 第1讲|R语言绘图体系总览(Base、ggplot2、ComplexHeatmap等)
  • 《R语言SCI期刊论文绘图专题计划》大纲
  • 【kafka初学】启动执行命令
  • HDRnet——双边滤波和仿射变换的摇身一变
  • CSRF请求伪造
  • 【服务器操作指南】从 Hugging Face 上下载文件 | 从某一个网址上下载文件到 Linux 服务器的指定目录
  • nacos设置权重进行负载均衡不生效
  • LSTM+KNN - 多元数据异常检测 !
  • pcd2pgm的launch文件实现
  • [原创](现代Delphi 12指南):[macOS 64bit App开发]:如何使用CFStringRef类型字符串?