赞
踩
PCIe的建链问题比较常见,由于各种厂商定位PCIe的方式方法不同,这里我们只介绍协议的方式 如何判断当前链路状态。在介绍建链前需要补充一下PCIe设备如何查看ID。Linux系统下通过以下命令,可以查到当前 PCIe 的拓扑图。
lspci –vt
下图是执行该命令后某个编译服务器的部分拓扑截图。关键信息是各个设备的ID即DBDF(Domain,Bus,Deivce,Function)号,识别到ID后才能针对某个设备做精确的查询和控制。
图1
图中有个IEP设备就是0000:00:00.0, 这里的几个域的含义是第一个0000是domain域基本上都是0,第二个00是Bus总线号,第三个00是Device 设备号,第四个0是Function 功能号。这个RCiEP(Root Complex Integrated Endpoint)设备是Intel CPU自带的内部的模块,我们不需要关注,我们需要关注的是RP(Root Port)和EP(Endpoint),这里是借这个设备说明一下如何查看PCIe 设备的DBDF号,图中红字也有说明。
这个图里面能看到有3 RP,即00:01.0, 00:02.0, 00:03.0。同时也能看到00:02.0下挂了一个EP,但这个EP有两个PF(Physical Function),一个是02:00.0 WX7100 一个是02:00.1 RX580。同时00:03.0 下挂了一个EP,这个EP只有一个PF 03:00.0 NVMe SSD
自此,该拓扑解析完成,目前看到有3个RP 2个EP,且有个EP有2个PF,还有1个RCiEP。
注:绝大部分场景下,设备都在一个domain域内,所以lspci工具使用时通常会省略domain域,即domain默认值为0。
当我们已经知道拓扑后,我们就知道哪个设备挂载哪个RP下了。假设我们有个设备挂载上图的0:01.0 这个RP上,但是没有看到EP设备怎么办。这时需要确认RP的建链状态
使用命令查看当前RP设备的配置空间解析,用于查看当前RP状态
sudo lspci -vvs 0:1.0
执行结果如下图所示
图2
其中红框中的DLActive- 就代表该Port并未建链。
如果出现无法建链的情况需要优先排查下列三种情况
如果这三点都排查了,都工作正常,那有可能就是从RP到EP的链路质量不好。需要硬件先测一下眼图,看看是否真的信号质量太差。如果确实信号质量差,那就要按照协议调整PCIe的一些硬件参数。如果是自研芯片或者能看到寄存器信息的芯片,则可以通过读取芯片PCIe的状态机状态来判断是在那个阶段就出现问题了。还可以排查一些PCIe的配置,比如时钟来源等等。
建链的问题较多,这里只是给了一些思路,具体还要根据实际的场景实际分析。
注:可能有些BIOS/UBOOT在启动阶段如果不能建链, BIOS/UBOOT就会关闭对应RP用于节能。如果实在调试EP设备,需要注意启动时间与BIOS对应。
如图3 所示DLActive状态正常,红框中的代表当前建链的状态即与对端协商到的带宽和速率是多少。蓝框中的表示当前我这个设备支持的单宽和速率是多少。
图3
图3是EP的配置空间,如果这里红框中的speed和蓝框中speed需要对应的话,那这会儿的建链是有问题的,需要确认为什么speed明明支持到8G/s(GEN3)但是当前只建链到2.5Gb/s(GEN1)。这里需要先确认RP的配置空间是否支持到8G/s(GEN3),如果RP只支持则建链到2.5Gb/s(GEN1)是符合协议的。
图4
从图4中能看到RP是支持8G/s(GEN3),这里就需要确认为什么链路只建链到2.5Gb/s(GEN1)。当然这里的原因是因为显卡根据负载会自动切换速率,当前我们没用显卡,所以显卡驱动时为了省电故意将速率切换到2.5Gb/s(GEN1)。但如果我们对接的卡并不支持动态切换速率的话,就需要检查为什么不能建链到更高速度。一般的原因还是因为信号质量不好,尝试切速的时候误码过多,无法recovery 成功,所以速率无法上去。
当然还有些是width 与预期不匹配,一般原因仍然是跟物理通路有关,可能某条通路不通或者信号质量太差,但是其他部分通路是通的,则有可能建链到与预期不匹配的带宽上。
枚举问题一般比较少。一般我理解的枚举问题就是,上面那个例子中,RP的DLActive+ 但是仍然看不到对接的EP设备,可以尝试用以下命令重新枚举设备。
echo 1 > /sys/bus/pci/rescan
注意老的Linux版本如果当前设备有其他PCI设备在正常运行,可能会受影响。如果不放心可以指定某个RP进行rescan如下命令
echo 1 > /sys/bus/pci/devices/0000\:00\:01.0/rescan
执行命令后如果能看到设备,那么很有可能就是EP启动较慢,导致在HOST BIOS建链枚举阶段并未真正枚举到。在OS启动阶段也就看不到对应设备了。但在HOST启动OS后又建链了,可能才会出现这种现象。
当然如果上面的命令做了以后还是无法看到设备,可能需要怀疑EP设备是否能正常工作了,因为这个枚举动作实际上也是逻辑在参与,如果枚举不到大概率还是EP芯片逻辑出问题了。
AER (Advanced Error Reporting) 是PCIe设备的高级功能,PCIe设备如果出现问题可以通过这个机制上报给系统,然后系统来处理异常。
AER里面主要分为三种类型的故障,分别是:CE(Correctable Error), UE(Uncorrectable Error),UE中根据Severity寄存器又分为NFE(Non-Fatal Error), FE(Fatal Error)。一般来说CE 不会上报OS,PCIe设备自己处理,UE会上报OS。如果HOST为x86可能也不会管NEF,因为NFE的默认处理是断链,然后重新建链,但X86不只是热插拔,所以NEF要么不处理,要么不上报。FE的处理一般都是复位系统。
这里笔者列出较常见的故障有哪些,并说明一下出错原因。没有列出的,笔者暂时没有遇到过,还不太清楚问题出现原因,就不单独描述了。如果对这个AER有兴趣可以看PCIe协议。
1、NCB-PCI_Express_Base_4.0r1.0_September-27-2017
AER 即 Advanced Error Reporting高级错误报告,是PCIe高级特性,用于报告PCIe 错误信息,是PCIe RAS特性最重要的部分,本文从PCIe AER协议、固件、linux内核实现讲述PCIe AER知识。
分为可纠正错误和不可纠正错误 , Correctable errors and Uncorrectable errors
不可纠正错误分为ERR_FATAL和ERR_NONFATAL。
Correctable Errors可纠正错误是指错误发生后,硬件可以自动恢复。
Uncorrectable errors错误发生后,影响设备功能,硬件不能自动恢复。
ERR_FATAL错误是致命错误,此错误类型影响了PCIe link链路。
ERR_NONFATAL错误是指影响了设备功能,但是PCIe link还是稳定的。
2. AER寄存器
包含了AER 状态、掩码、级别等寄存器。
3.错误控制上报路径
这里最终有两条路径: MSI/INTx中断上报给OS AER驱动程序,还有一个系统错误的中断上报给固件firmware。
PCIe AER驱动属于PCIe port driver, 其绑定的是PCIe root port。
- drivers/pci/pcie/aer.c
- static struct pcie_port_service_driver aerdriver = {
- .name = "aer",
- .port_type = PCIE_ANY_PORT,
- .service = PCIE_PORT_SERVICE_AER,
-
- .probe = aer_probe,
- .remove = aer_remove,
- };
-
- /**
- * pcie_aer_init - register AER root service driver
- *
- * Invoked when AER root service driver is loaded.
- */
- int __init pcie_aer_init(void)
- {
- if (!pci_aer_available())
- return -ENXIO;
- return pcie_port_service_register(&aerdriver);
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
注:port_type = PCIE_ANY_PORT, AER绑定的不是ROOT PORT么,怎么是PCIE_ANY_PORT,这个澄清内核增加了PCIE RCEC支持,除了ROOT PORT针对RCEC设备也可以AER处理。
- /**
- * aer_probe - initialize resources
- * @dev: pointer to the pcie_dev data structure
- *
- * Invoked when PCI Express bus loads AER service driver.
- */
- static int aer_probe(struct pcie_device *dev)
- {
- int status;
- struct aer_rpc *rpc;
- struct device *device = &dev->device;
- struct pci_dev *port = dev->port;
-
- /* Limit to Root Ports or Root Complex Event Collectors */
- if ((pci_pcie_type(port) != PCI_EXP_TYPE_RC_EC) &&
- (pci_pcie_type(port) != PCI_EXP_TYPE_ROOT_PORT))
- return -ENODEV;
- ...
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
PCIe AER错误上报流程。
EP设备发生AER错误,通过error msg上报到root port, root port上报中断给CPU处理。
PCIe Correctable Errors处理流程
1)、获取出错的设备和清状态
2)、读取设备详细错误信息。
- Error Severity : Corrected
- PCIE Bus Error type : Physical Layer
- Receiver Error : Multiple
- Receiver ID : 0020
- VendorID=8086h, DeviceID=3597h, Bus=00h, Device=04h,
- Function=00h
PCIe NON-FATAL Errors处理流程
1)、获取出错的设备和清状态
2)、读取设备详细错误信息。
3) 、错误恢复处理
- Error Severity : Uncorrected (Non-Fatal)
- PCIE Bus Error type : Transaction Layer
- Completion Timeout : Multiple
- Requester ID : 0018
- VendorID=8086h, DeviceID=3596h, Bus=00h, Device=03h,
- Function=00h
PCIe FATAL Errors处理流程
FATAL错误处理流程大体类似non-fatal,只是错误恢复的时候有差异,fatal错误影响pcie link链路,会做链路的恢复。
- Error Severity : Uncorrected (Fatal)
- PCIE Bus Error type : Transaction Layer
- Unsupported Request : First
- Requester ID : 0200
- VendorID=8086h, DeviceID=0329h, Bus=02h, Device=00h,
- Function=00h
- TLB Header:
- 04000001 00180003 02040000 00020400
关键结构
设备支持AER错误恢复,需要设备驱动注册pci_error_handlers
- struct pci_error_handlers
- {
- int (*error_detected)(struct pci_dev *dev, pci_channel_state_t);
- int (*mmio_enabled)(struct pci_dev *dev);
- int (*slot_reset)(struct pci_dev *dev);
- void (*resume)(struct pci_dev *dev);
- };
- The possible channel states are:
-
- typedef enum {
- pci_channel_io_normal, /* I/O channel is in normal state */
- pci_channel_io_frozen, /* I/O to channel is blocked */
- pci_channel_io_perm_failure, /* PCI card is dead */
- } pci_channel_state_t;
- Possible return values are:
-
- enum pci_ers_result {
- PCI_ERS_RESULT_NONE, /* no result/none/not supported in device driver */
- PCI_ERS_RESULT_CAN_RECOVER, /* Device driver can recover without slot reset */
- PCI_ERS_RESULT_NEED_RESET, /* Device driver wants slot to be reset. */
- PCI_ERS_RESULT_DISCONNECT, /* Device has completely failed, is unrecoverable */
- PCI_ERS_RESULT_RECOVERED, /* Device driver is fully recovered and operational */
- };
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
nvme驱动nvme_err_handler注册
drivers/nvme/host/pci.c
- static const struct pci_error_handlers nvme_err_handler = {
- .error_detected = nvme_error_detected,
- .slot_reset = nvme_slot_reset,
- .resume = nvme_error_resume,
- .reset_prepare = nvme_reset_prepare,
- .reset_done = nvme_reset_done,
- };
- ......
-
- static struct pci_driver nvme_driver = {
- .name = "nvme",
- .id_table = nvme_id_table,
- .probe = nvme_probe,
- .remove = nvme_remove,
- .shutdown = nvme_shutdown,
- #ifdef CONFIG_PM_SLEEP
- .driver = {
- .pm = &nvme_dev_pm_ops,
- },
- #endif
- .sriov_configure = pci_sriov_configure_simple,
- .err_handler = &nvme_err_handler,
- };
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
PCIe AER硬件错误较难触发,如何调试AER软件处理的正确,提供了AER注错工具aer-inject
本文主要介绍下PCIe AER知识,从协议、linux内核软件实现原理、和固件关系,错误注入工具介绍,能够对PCIe AER知识有个系统性认识。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。