【37】linux kernel 对于PCIe CRS的处理

CRS全称是configuration retry status,单纯从名称上看应该是和配置访问有一定的关系,感觉又是在retry。那CRS到底是用来做什么的?其实很简单,当pcie设备还没有准备好响应配置请求时(比如自己的FW还在初始化中),如果对该设备发起配置访问,将会收到状态CRS的completion包。如果此时抓trace的话,将会发现completion 包的status就是010的。
在这里插入图片描述
在这里插入图片描述
既然设备还没有准备好,返回了CRS的completion包,那么芯片和软件应该怎么处理这种情况呢?协议有下面的说明
(1)当CRS software visibility 没有使能的情况下,(即CRS这种情况是需要硬件重发配置请求):
RC需要重发一个新的配置请求(一般芯片有一些特殊的reg,可以配置硬件进行重发的时间间隔和重发次数)。
(2)当CRS software visibility使能的情况,(即CRS这种情况是需要软件重发配置请求):
a.如果是对配置空间的VendorID字段进行的配置读请求,对于Vendorid字段,RC需要返回0001h的的返回值,对于其他字段需要返回全1。
b.对于配置写请求或者配置读请求,RC必须重新发送新的请求(这个就要求软件要重发了)。
在这里插入图片描述
既然协议规定了可以把CRS的处理给软件,那么哪些reg可以通知芯片,软件要处理CRS请求了,不需要硬件重发配置请求?答案就是配置空间的CRS software visibility enable bit。
配置空间的root control reg的CRS software visibility enable bit为1时,会把CRS的completion包的处理给软件。
在这里插入图片描述
在这里插入图片描述
linux kernel会把根据是否支持CRS Software Visibility这种cap来使能CRS Software Visibility bit。
在这里插入图片描述
那么如果使能了CRS Software Visibility,软件会进行怎么样的操作呢

bool pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *l,
				int crs_timeout)
{
	int delay = 1;

	if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, l))
		return false;
--------(1)读取配置空间的vendorid和deviceid
	/* some broken boards return 0 or ~0 if a slot is empty: */
	if (*l == 0xffffffff || *l == 0x00000000 ||
	    *l == 0x0000ffff || *l == 0xffff0000)
		return false;
--------(2)判断寄存器是否是全1或者全0,低16bit是vendorid,高16bit是deviceid,如果是全1或者0,可能是slot下面没有接东西
	/*
	 * Configuration Request Retry Status.  Some root ports return the
	 * actual device ID instead of the synthetic ID (0xFFFF) required
	 * by the PCIe spec.  Ignore the device ID and only check for
	 * (vendor id == 1).
	 */
	while ((*l & 0xffff) == 0x0001) {  -------------(3)判断vendorid是否0x0001,如果为0x0001则对端设备返回了CRS的completion
		if (!crs_timeout)
			return false;

		msleep(delay);-------(4)延时1ms
		delay *= 2;-------(5)每次返回CRS的completion包后,延时时间会变成2倍。
		if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, l))--------(5)重发配置读请求访问vendorid
			return false;
		/* Card hasn't responded in 60 seconds?  Must be stuck. */
		if (delay > crs_timeout) {
			printk(KERN_WARNING "pci %04x:%02x:%02x.%d: not responding\n",
			       pci_domain_nr(bus), bus->number, PCI_SLOT(devfn),
			       PCI_FUNC(devfn));
			return false;
		}
	}

	return true;
}
发布了33 篇原创文章 · 获赞 8 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/linjiasen/article/details/101057823