1 驱动shutdown顺序
系统关机或重启的过程中,会调用设备驱动的shutdown函数来完成设备的关闭操作,有需要的设备可以在驱动中定义该函数。其调用流程如下:
kernel_restart
->
kernel_restart_prepare
->
device_shutdown // 逆向遍历devices_kset->list所有device
->
dev->driver->shutdown
由此可见,各个驱动shutdown的顺序由设备在链表中的位置决定,后添加的先调用。设备添加到链表中的流程如下:
device_initialize
device_add
->
kobject_add
->
kobj_kset_join
->
list_add_tail(&kobj->entry, &kobj->kset->list)
由此可见,设备注册时,会把节点添加到devices_kset->list末尾。因此驱动的shutdown顺序是设备注册的逆序,而在通过dts创建设备的系统中,设备的注册顺序是设备节点在dts中的前后顺序。
2 USB-RuntimePM
2.1 XHCI USB 2.0 LPM
L0:means ON
L1:means SLEEP
L2:traditional USB 2.0 suspend
L3:means OFF
2.2 XHCI USB 3.0 LPM
U0: normal work
U1/U2: 一般都不支持的,Linux DT直接禁止了,因为绝大部分的USB3的U1/U2都是有问题的。
U3: suspend
2.3 Gadget Runtime-PM APIs
@ include/linux/usb/gadget.h
static inline int usb_gadget_autopm_get(struct usb_gadget *gadget);
static inline void usb_gadget_autopm_put(struct usb_gadget *gadget);
3 USB-EHCI-PM-Call-Flow
suspend usb_device时,先suspend usb interface,再挂起整个设备,也就是调用generic.c(类似于Windows CCGP)驱动的generic_suspend();
resume usb_device时,先唤醒整个设备,也就是调用generic.c(类似于Windows CCGP)驱动的generic_resume(),再resume usb interface。
4 USB Suspend and Resume Flow
4.1 LS/FS/HS Early Suspend Interrupt
DWC2 databook indicates if the core sets "ErlySusp" bit, an idle state has been detected on the USB for 3 ms. This situation can be occurred when waiting a request from user daemon. So, we should keep the connection between udc and gadget even though this interrupt is occurred.
4.2 External Hub reset-resume Issue
hub_port_connect_change()
usb_detect_quirks(), which will set“udev->persist_enabled = 1”
hub_activate(), which checks“udev->persist_enabled == 1”,
then sets “udev->reset_resume = 1; ”the“reset_resume”flag will cause EHCI stack calls
usb_port_resume() to reset the external hub when the system exits suspend-to-RAM.
HS Device Suspend Flow:
1. 高速设备在收到挂起信号(3ms空闲)后,应在0.125ms内切换到全速状态,也就是说要把下拉终端电阻45Ω移除,并在D+数据线上重新挂上1.5k上拉电阻。
2. 设备在随后的100-875μs内检测数据线上的状态。如果该状态是一个Full speed J,那么说明host发下来的是一个挂起信号;如果此时该状态是SE0,说明是host drive数据线D+/D-到0,这是一个复位信号(复位信号会持续至少10ms时间)。
HS Device Resume Flow:
因为设备挂起时处于全速状态,当host需要设备退出suspend状态时,先发送一个持续时间超过20ms的Fulll Speed K状态,设备看到K状态结束的1.3us(持续2个 LS bit位时间)内醒过来,而host需要在3ms内发送uSOF信号以维持正常的高速信号模式,否则设备又将进入suspend。
4.3 USB3 Resume
1)LTSSM处于U3状态;
2)PHY收到LFPS WAKEUP信号,通知Link层LTSSM,LTSSM指导PHY也发送LFPS给对端设备;
3)LTSSM进入Recovery状态,包括TS1,TS2,IDLE训练;
4)持续发送TS1直到成功接收到对端发送的8个TS1,然后进入TS2阶段;在TS2阶段,需要接收到对端发送的至少8个TS2,并且自己给对端至少也发送了16个TS2,此时TS1,TS2训练成功;
5)确认TS1和TS2训练是否成功,如果TS1和TS2都成功,转入下一步;否则,如果TS1或者TS2训练失败,转入SS.Inactive;
6)LTSSM指导PHY进行IDLE训练,接收到对端发送的至少8个空闲符号时,确保自己也同时至少发送了16个IDLE符号给对端;
7)确认上一步是否成功,如果成功,转入U0;否则转入SS.Inactive。
注意:
LFPS和IDLE都是PIPE(PHY Interface for PCI Express)接口PHY实施的;
而TS1,TS2训练序列是LTSSM生成的数据;
LGOOD_0 to LGOOD_7的发送表示Link层已成功收到对端发送的数据(CRC校验正确);
LCRD_A to LCRD_D(CRD means Credit)的发送表示Link层已成功将接收的数据push入protocol层,说明Link层LCRD_X对应的buffer可用了(USB3协议实施时,Link层最多可缓存接收到的4个packets)。
5 Abbreviations
CCGP:Windows USB Common Class Generic Parent,Linux内核类似的驱动就是usb_generic_driver