0%

模块复位的基本逻辑

设备复位的功能,需要软硬件一起联合起来考虑。本文试图梳理下要给一个linux设备驱动
加上复位功能需要考虑的基本逻辑。本文只从逻辑的层面给出我的认识,不涉及具体的
硬件和软件驱动。

首先我们对这个设备做出一些基本的假设。这个设备是一个PCIe设备,这个设备有多个PF,
一个PF又有多个附带的VF。每个function上又有很多可以独立工作的部件,比如很多队列。
这个设备可以工作在内核态,也可以工作在用户态, 也可以工作在虚拟机的内核态。

复位可以是整个设备的复位,我们称之为全局复位。全局复位发生的时候,这个设备上的
PF和VF都要被复位。复位也可以是function级别的,比如一个PF或者VF单独复位,其他
function的功能不受到影响, 我们把这种复位叫function复位,因为我们讨论的是PCIe
设备,这里也就是FLR。当然逻辑上,我们还有function里独立工作部件的复位,比如队列
的复位。

我们现在对复位做更清楚的定义。一般, 复位是对设备回归初始状态的操作,但它回归到的
状态不是刚刚上电的状态。用户在使用设备的时候,一般会先做一些初始的配置,比如,
enable几个VF, 配置一些队列的资源。这些配置在上下电或者驱动加卸载的时候要清除。
但是,在复位的时候,我们希望保留这些配置。一般需要复位的时候为系统发生了错误,无
法继续运行,复位只是叫系统回复之前可以运行的状态,清除用户之前的配置是不合适的。

所以,各种复位首先要考虑的问题是,是否需要保留用户配置,怎么保留,在复位完成后
怎么恢复这些配置。

我们还需要考虑带流量复位的问题,需要复位的时候,设备上可能还有部件在工作。冒然
做复位可能导致异常出现。一般的做法是要先把工作的部件停下来,再进行复位操作。

考虑到了以上两点,剩下的就是具体结合硬件提供的功能,写代码完成功能了。下面我们
再近一步说明以上两点。

一般,设备的全局配置保存在设备全局寄存器或者是PF里。所以,设备全局复位或者PF FLR
需要考虑配置保存,恢复相关的东西。全局复位中,如果硬件没有复位PCIe SRIOV相关的配置,
PCIe VF是一直保持的,设备驱动需要保留恢复设备业务相关的配置。但是PF的FLR,PCIe
协议规定VF要被disable,这也就意味着PF FLR会触发VF消失。不过,设备驱动并不需要在
复位完成后enable相应的VF,这是因为在PF FLR的流程里,PCIe总线驱动会保留VF数目的
配置,在PF FLR后enable相关VF(不过,全盘考虑这个问题,如果PF FLR的时候,VF在虚拟机
里正在使用,重新enable的VF在虚拟机里是否还可以继续使用,这里还不清楚)。

带流量复位的问题,可能是复位里最复杂的了。我们考虑全局复位的情况,一般,全局复位
的操作发生PF的驱动里, 我们可以在复位的时候先检查PF, 把PF的工作停下来再复位。但是,
我们怎么才能停下来正在虚拟机里工作的VF?这就需要PF和VF之间有硬件上的通知机制, PF
要进行全局复位的时候,先用相关的通知机制通知VF, VF收到通知后把它自己的工作停下
来,然后VF可以通知PF它已经停下工作,PF可以进行全局复位了。这个是一个合理的带流量
复位应该做的基本的软硬件配合的考虑。

如果,硬件没有PF/VF之间的通知机制,软件上可以做些什么来补救? 其实,补救的办法也
是要依赖硬件的行为。比如,如果全局复位的时候,VF不响应软件的请求(写入都丢弃,读
到的都是全1), 我们就可以在软件发送请求的时候加定时器,如果超时还没有完成,就猜测
发生了全局复位。但是,这样的补救一般运气的成分大,一不留神就有给你惊喜的地方。
比如,VF读到全1就有可能引起软件的误判, 超时之后VF怎么了解到是发生了全局复位,VF
又怎么判断全局复位完成了…