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

  CRS全称是configuration retry status,单纯从名称上看应该是和配置访问有一定的关系,感觉又是在retry。那CRS到底是用来做什么的?其实很简单,当pcie设备还没有准备好响应配置请求时(比如自己的FW还在初始化中),如果其他设备(host)对该设备发起配置访问,将会收到状态CRS的completion包。如果此时抓trace的话,将会发现completion 包的status就是010的。
在这里插入图片描述
在这里插入图片描述
  既然设备还没有准备好,返回了CRS的completion包,那么芯片和软件应该怎么处理这种情况呢?协议有下面的说明
  (1)当CRS software visibility 没有使能的情况下,(即这种情况是需要硬件(RC)重发配置请求):
RC需要重发一个新的配置请求(一般芯片有一些芯片特有的reg,可以配置硬件进行重发的时间间隔和重发次数)。
  (2)当CRS software visibility使能的情况,(即这种情况是需要软件(linux host driver)重发配置请求):
  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,软件会进行怎么样的操作呢,下面是linux kernel对于CRS的处理:

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;
}
  • 6
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

linjiasen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值