Synopsys DesignWare Core SuperSpeed USB 3.0 控制器

作者:

Felipe Balbi <felipe.balbi@linux.intel.com>

日期:

2017 年 4 月

简介

_Synopsys DesignWare Core SuperSpeed USB 3.0 控制器_(以下简称 _DWC3_)是一款符合 USB SuperSpeed 标准的控制器,可以配置为以下 4 种方式之一

  1. 仅限外设配置

  2. 仅限主机配置

  3. 双重角色配置

  4. 集线器配置

Linux 目前支持此控制器的多个版本。 在所有可能性中,您的 SoC 中的版本已被支持。 在撰写本文时,已知的经过测试的版本范围从 2.02a 到 3.10a。 根据经验,高于 2.02a 的任何版本都应能可靠地工作。

目前,我们有很多已知的此驱动程序的用户。 按字母顺序排列

  1. Cavium

  2. 英特尔公司

  3. 高通

  4. 瑞芯微

  5. ST

  6. 三星

  7. 德州仪器

  8. 赛灵思

功能概述

有关 DWC3 版本的支持的功能的详细信息,请咨询您的 IP 团队和/或 _Synopsys DesignWare Core SuperSpeed USB 3.0 控制器数据手册_。 以下是撰写本文时驱动程序支持的功能列表

  1. 最多 16 个双向端点(包括控制管道 - ep0)

  2. 灵活的端点配置

  3. 同时支持 IN 和 OUT 传输

  4. 分散/聚集列表支持

  5. 每个端点最多 256 个 TRB [1]

  6. 支持所有传输类型(_控制_、_批量_、_中断_和_同步_)

  7. SuperSpeed 批量流

  8. 链路电源管理

  9. 用于调试的跟踪事件

  10. DebugFS [3] 接口

这些功能已通过许多树内小工具驱动程序进行了测试。 我们已经验证了 ConfigFS [4] 和旧版小工具驱动程序。

驱动程序设计

DWC3 驱动程序位于 _drivers/usb/dwc3/_ 目录中。 与此驱动程序相关的所有文件都在这一个目录中。 这使得新手可以轻松阅读代码并了解其行为方式。

由于 DWC3 的配置灵活性,驱动程序在某些地方有点复杂,但应该很容易理解。

驱动程序的最大部分是指小工具 API。

已知限制

与其他任何硬件一样,DWC3 也有其自身的局限性。 为了避免不断地询问此类问题,我们决定在此处记录它们,并拥有一个可以指向用户的单一位置。

OUT 传输大小要求

根据 Synopsys 数据手册,所有 OUT 传输 TRB [1] 必须将其 _size_ 字段设置为整数,该整数可被端点的 _wMaxPacketSize_ 整除。 这意味着,_例如_,为了接收大容量存储 _CBW_ [5],req->length 必须设置为可被 _wMaxPacketSize_ 整除的值(在 SuperSpeed 上为 1024,在 HighSpeed 上为 512,等等),或者 DWC3 驱动程序必须添加一个链接的 TRB,指向剩余长度的抛弃型缓冲区。 没有这个,OUT 传输将不会启动。

请注意,截至撰写本文时,这不会成为问题,因为 DWC3 完全能够为剩余长度附加一个链接的 TRB,并从小工具驱动程序中完全隐藏此细节。 仍然值得一提,因为这似乎是关于 DWC3 和 _无法正常传输_ 的查询的最大来源。

TRB 环大小限制

我们目前对每个端点有 256 个 TRB [1] 的硬性限制,最后一个 TRB 是一个链接 TRB [2],指回第一个。 此限制是任意的,但它的好处是总计正好 4096 字节,或 1 页。

DWC3 驱动程序将尽最大努力处理超过 255 个请求,并且在大多数情况下,它应该正常工作。 但是,这并不是经常进行的。 如果您遇到任何问题,请参阅下面的报告错误部分。

报告错误

每当您遇到 DWC3 问题时,首先也是最重要的,您应该确保

  1. 您正在运行来自 Linus’ tree 的最新标签

  2. 您可以在没有任何对 DWC3 的树外更改的情况下重现该错误

  3. 您已检查过它不是主机上的故障

在验证所有这些之后,以下是如何捕获足够的信息以便我们为您提供任何帮助。

所需信息

DWC3 专门依赖于跟踪事件进行调试。 一切都暴露在那里,一些额外的位暴露给 DebugFS [3]

为了捕获 DWC3 的跟踪事件,您应该在将 USB 电缆插入主机之前运行以下命令

# mkdir -p /d
# mkdir -p /t
# mount -t debugfs none /d
# mount -t tracefs none /t
# echo 81920 > /t/buffer_size_kb
# echo 1 > /t/events/dwc3/enable

完成此操作后,您可以连接 USB 电缆并重现该问题。 重现故障后,请复制文件 traceregdump,如下所示

# cp /t/trace /root/trace.txt
# cat /d/*dwc3*/regdump > /root/regdump.txt

确保将 trace.txtregdump.txt 压缩到 tarball 中,并通过电子邮件发送给 ,并在抄送中包含 linux-usb。 如果您想格外确保我会帮助您,请按以下格式编写您的主题行

[BUG REPORT] usb: dwc3: Bug while doing XYZ

在电子邮件正文中,请务必详细说明您正在做什么,您正在使用哪个小工具驱动程序,如何重现该问题,您正在使用哪个 SoC,哪个操作系统(及其版本)正在主机上运行。

有了所有这些信息,我们应该能够了解发生了什么并为您提供帮助。

调试

首先也是最重要的免责声明

DISCLAIMER: The information available on DebugFS and/or TraceFS can
change at any time at any Major Linux Kernel Release. If writing
scripts, do **NOT** assume information to be available in the
current format.

消除了这一点,让我们继续。

如果您愿意调试自己的问题,您应该得到热烈的掌声 :-)

无论如何,除了跟踪事件对于找出 DWC3 的问题非常有帮助之外,这里没有什么可说的。 此外,在这种情况下,访问 Synopsys 数据手册将非常有价值。

USB Sniffer 有时会有所帮助,但并非完全必需,无需查看电线即可理解很多内容。

如果您需要任何帮助,请随时通过电子邮件发送给 ,并在抄送中包含 linux-usb

DebugFS

DebugFS 非常适合收集有关 DWC3 和/或任何端点正在发生的事情的快照。

在 DWC3 的 DebugFS 目录中,您将找到以下文件和目录

ep[0..15]{in,out}/ link_state regdump testmode

regdump

文件名是不言自明的。 读取时,regdump 将打印出 DWC3 的寄存器转储。 请注意,可以 grep 此文件以查找您想要的信息。

testmode

读取时,testmode 将打印出指定的 USB 2.0 测试模式(test_jtest_ktest_se0_naktest_packettest_force_enable)之一的名称,或者在当前未执行任何测试时打印字符串 no test

为了启动这些测试模式中的任何一种,可以将相同的字符串写入文件中,DWC3 将进入请求的测试模式。

ep[0..15]{in,out}

对于每个端点,我们都遵循命名约定 ep$num$dir (ep0in, ep0out, ep1in, ...) 公开一个目录。 在每个这些目录中,您将找到以下文件

descriptor_fetch_queue event_queue rx_fifo_queue rx_info_queue rx_request_queue transfer_type trb_ring tx_fifo_queue tx_request_queue

通过访问 Synopsys 数据手册,您可以解码其中的信息。

transfer_type

读取时,transfer_type 将打印出 controlbulkinterruptisochronous 之一,具体取决于端点描述符的内容。 如果尚未启用端点,它将打印 --

trb_ring

读取时,trb_ring 将打印出有关环上所有 TRB 的详细信息。 它还将告诉您我们的入队和出队指针位于环中的位置

buffer_addr,size,type,ioc,isp_imi,csp,chn,lst,hwo
000000002c754000,481,normal,1,0,1,0,0,0
000000002c75c000,481,normal,1,0,1,0,0,0
000000002c780000,481,normal,1,0,1,0,0,0
000000002c788000,481,normal,1,0,1,0,0,0
000000002c78c000,481,normal,1,0,1,0,0,0
000000002c754000,481,normal,1,0,1,0,0,0
000000002c75c000,481,normal,1,0,1,0,0,0
000000002c784000,481,normal,1,0,1,0,0,0
000000002c788000,481,normal,1,0,1,0,0,0
000000002c78c000,481,normal,1,0,1,0,0,0
000000002c790000,481,normal,1,0,1,0,0,0
000000002c758000,481,normal,1,0,1,0,0,0
000000002c780000,481,normal,1,0,1,0,0,0
000000002c788000,481,normal,1,0,1,0,0,0
000000002c790000,481,normal,1,0,1,0,0,0
000000002c758000,481,normal,1,0,1,0,0,0
000000002c780000,481,normal,1,0,1,0,0,0
000000002c784000,481,normal,1,0,1,0,0,0
000000002c788000,481,normal,1,0,1,0,0,0
000000002c78c000,481,normal,1,0,1,0,0,0
000000002c754000,481,normal,1,0,1,0,0,0
000000002c758000,481,normal,1,0,1,0,0,0
000000002c780000,481,normal,1,0,1,0,0,0
000000002c784000,481,normal,1,0,1,0,0,0
000000002c78c000,481,normal,1,0,1,0,0,0
000000002c790000,481,normal,1,0,1,0,0,0
000000002c758000,481,normal,1,0,1,0,0,0
000000002c780000,481,normal,1,0,1,0,0,0
000000002c788000,481,normal,1,0,1,0,0,0
000000002c790000,481,normal,1,0,1,0,0,0
000000002c758000,481,normal,1,0,1,0,0,0
000000002c780000,481,normal,1,0,1,0,0,0
000000002c788000,481,normal,1,0,1,0,0,0
000000002c790000,481,normal,1,0,1,0,0,0
000000002c758000,481,normal,1,0,1,0,0,0
000000002c780000,481,normal,1,0,1,0,0,0
000000002c788000,481,normal,1,0,1,0,0,0
000000002c790000,481,normal,1,0,1,0,0,0
000000002c758000,481,normal,1,0,1,0,0,0
000000002c780000,481,normal,1,0,1,0,0,0
000000002c788000,481,normal,1,0,1,0,0,0
000000002c790000,481,normal,1,0,1,0,0,0
000000002c758000,481,normal,1,0,1,0,0,0
000000002c780000,481,normal,1,0,1,0,0,0
000000002c788000,481,normal,1,0,1,0,0,0
000000002c790000,481,normal,1,0,1,0,0,0
000000002c758000,481,normal,1,0,1,0,0,0
000000002c780000,481,normal,1,0,1,0,0,0
000000002c788000,481,normal,1,0,1,0,0,0
000000002c790000,481,normal,1,0,1,0,0,0
000000002c758000,481,normal,1,0,1,0,0,0
000000002c780000,481,normal,1,0,1,0,0,0
000000002c788000,481,normal,1,0,1,0,0,0
000000002c790000,481,normal,1,0,1,0,0,0
000000002c758000,481,normal,1,0,1,0,0,0
000000002c780000,481,normal,1,0,1,0,0,0
000000002c78c000,481,normal,1,0,1,0,0,0
000000002c784000,481,normal,1,0,1,0,0,0
000000002c788000,481,normal,1,0,1,0,0,0
000000002c78c000,481,normal,1,0,1,0,0,0
000000002c754000,481,normal,1,0,1,0,0,0
000000002c758000,481,normal,1,0,1,0,0,0
000000002c780000,481,normal,1,0,1,0,0,0
000000002c788000,481,normal,1,0,1,0,0,0
000000002c790000,481,normal,1,0,1,0,0,0
000000002c758000,481,normal,1,0,1,0,0,0
000000002c780000,481,normal,1,0,1,0,0,0
000000002c758000,481,normal,1,0,1,0,0,0
000000002c780000,481,normal,1,0,1,0,0,0
000000002c78c000,481,normal,1,0,1,0,0,0
000000002c75c000,481,normal,1,0,1,0,0,0
000000002c78c000,481,normal,1,0,1,0,0,0
000000002c780000,481,normal,1,0,1,0,0,0
000000002c754000,481,normal,1,0,1,0,0,0
000000002c788000,481,normal,1,0,1,0,0,0
000000002c754000,481,normal,1,0,1,0,0,0
000000002c780000,481,normal,1,0,1,0,0,0
000000002c788000,481,normal,1,0,1,0,0,0
000000002c78c000,481,normal,1,0,1,0,0,0
000000002c790000,481,normal,1,0,1,0,0,0
000000002c754000,481,normal,1,0,1,0,0,0
000000002c758000,481,normal,1,0,1,0,0,0
000000002c75c000,481,normal,1,0,1,0,0,0
000000002c780000,481,normal,1,0,1,0,0,0
000000002c784000,481,normal,1,0,1,0,0,0
000000002c788000,481,normal,1,0,1,0,0,0
000000002c78c000,481,normal,1,0,1,0,0,0
000000002c790000,481,normal,1,0,1,0,0,0
000000002c754000,481,normal,1,0,1,0,0,0
000000002c758000,481,normal,1,0,1,0,0,0
000000002c75c000,512,normal,1,0,1,0,0,1        D
0000000000000000,0,UNKNOWN,0,0,0,0,0,0       E
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
0000000000000000,0,UNKNOWN,0,0,0,0,0,0
00000000381ab000,0,link,0,0,0,0,0,1

跟踪事件

DWC3 还提供了几个跟踪事件,这些事件可帮助我们收集有关驱动程序在运行时行为的信息。

为了使用这些事件,您必须在内核配置中启用 CONFIG_FTRACE

有关如何启用 DWC3 事件的详细信息,请参阅报告错误部分。

以下小节将详细介绍每个事件类和 DWC3 定义的每个事件。

MMIO

在寻找错误时,查看每个 MMIO 访问有时很有用。 因此,DWC3 提供了两个跟踪事件(一个用于 dwc3_readl(),一个用于 dwc3_writel())。 TP_printk 如下

TP_printk("addr %p value %08x", __entry->base + __entry->offset,
              __entry->value)

中断事件

每个 IRQ 事件都可以记录并解码为人类可读的字符串。 因为每个事件都不同,所以我们没有给出除使用的 TP_printk 格式之外的示例

TP_printk("event (%08x): %s", __entry->event,
              dwc3_decode_event(__entry->event, __entry->ep0state))

控制请求

每个 USB 控制请求都可以记录到跟踪缓冲区中。 输出格式为

TP_printk("%s", dwc3_decode_ctrl(__entry->bRequestType,
                              __entry->bRequest, __entry->wValue,
                              __entry->wIndex, __entry->wLength)
)

请注意,标准控制请求将被解码为带有其各自参数的人类可读的字符串。 类和供应商请求将以十六进制格式打印出 8 个字节的序列。

struct usb_request 的生命周期

可以在跟踪缓冲区上跟踪 struct usb_request 的整个生命周期。 我们为每个分配、释放、排队、出队和归还都准备了一个事件。 输出格式为

TP_printk("%s: req %p length %u/%u %s%s%s ==> %d",
      __get_str(name), __entry->req, __entry->actual, __entry->length,
      __entry->zero ? "Z" : "z",
      __entry->short_not_ok ? "S" : "s",
      __entry->no_interrupt ? "i" : "I",
      __entry->status
)

通用命令

我们可以记录和解码每个带有其完成代码的通用命令。 格式为

TP_printk("cmd '%s' [%x] param %08x --> status: %s",
      dwc3_gadget_generic_cmd_string(__entry->cmd),
      __entry->cmd, __entry->param,
      dwc3_gadget_generic_cmd_status_string(__entry->status)
)

端点命令

端点命令也可以与完成代码一起记录。 格式为

TP_printk("%s: cmd '%s' [%d] params %08x %08x %08x --> status: %s",
      __get_str(name), dwc3_gadget_ep_cmd_string(__entry->cmd),
      __entry->cmd, __entry->param0,
      __entry->param1, __entry->param2,
      dwc3_ep_cmd_status_string(__entry->cmd_status)
)

TRB 的生命周期

TRB 的生命周期很简单。 我们要么准备一个 TRB,要么完成它。 通过这两个事件,我们可以看到 TRB 如何随时间变化。 格式为

TP_printk("%s: %d/%d trb %p buf %08x%08x size %s%d ctrl %08x (%c%c%c%c:%c%c:%s)",
      __get_str(name), __entry->queued, __entry->allocated,
      __entry->trb, __entry->bph, __entry->bpl,
      ({char *s;
      int pcm = ((__entry->size >> 24) & 3) + 1;
      switch (__entry->type) {
      case USB_ENDPOINT_XFER_INT:
      case USB_ENDPOINT_XFER_ISOC:
              switch (pcm) {
              case 1:
                      s = "1x ";
                      break;
              case 2:
                      s = "2x ";
                      break;
              case 3:
                      s = "3x ";
                      break;
              }
      default:
              s = "";
      } s; }),
      DWC3_TRB_SIZE_LENGTH(__entry->size), __entry->ctrl,
      __entry->ctrl & DWC3_TRB_CTRL_HWO ? 'H' : 'h',
      __entry->ctrl & DWC3_TRB_CTRL_LST ? 'L' : 'l',
      __entry->ctrl & DWC3_TRB_CTRL_CHN ? 'C' : 'c',
      __entry->ctrl & DWC3_TRB_CTRL_CSP ? 'S' : 's',
      __entry->ctrl & DWC3_TRB_CTRL_ISP_IMI ? 'S' : 's',
      __entry->ctrl & DWC3_TRB_CTRL_IOC ? 'C' : 'c',
    dwc3_trb_type_string(DWC3_TRBCTL_TYPE(__entry->ctrl))
)

端点的生命周期

端点的生命周期概括为启用和禁用操作,两者都可以跟踪。 格式为

TP_printk("%s: mps %d/%d streams %d burst %d ring %d/%d flags %c:%c%c%c%c%c:%c:%c",
      __get_str(name), __entry->maxpacket,
      __entry->maxpacket_limit, __entry->max_streams,
      __entry->maxburst, __entry->trb_enqueue,
      __entry->trb_dequeue,
      __entry->flags & DWC3_EP_ENABLED ? 'E' : 'e',
      __entry->flags & DWC3_EP_STALL ? 'S' : 's',
      __entry->flags & DWC3_EP_WEDGE ? 'W' : 'w',
      __entry->flags & DWC3_EP_TRANSFER_STARTED ? 'B' : 'b',
      __entry->flags & DWC3_EP_PENDING_REQUEST ? 'P' : 'p',
      __entry->flags & DWC3_EP_END_TRANSFER_PENDING ? 'E' : 'e',
      __entry->direction ? '<' : '>'
)

结构、方法和定义

struct dwc3_event_buffer

软件事件缓冲区表示

定义:

struct dwc3_event_buffer {
    void *buf;
    void *cache;
    unsigned int            length;
    unsigned int            lpos;
    unsigned int            count;
    unsigned int            flags;
#define DWC3_EVENT_PENDING      BIT(0);
    dma_addr_t dma;
    struct dwc3             *dwc;
};

成员

buf

_THE_ 缓冲区

cache

线程化中断中使用的缓冲区缓存

length

此缓冲区的大小

lpos

事件偏移量

count

上次读取事件计数寄存器的缓存

flags

与此事件缓冲区相关的标志

dma

dma_addr_t

dwc

指向 DWC 控制器的指针

struct dwc3_ep

设备侧端点表示

定义:

struct dwc3_ep {
    struct usb_ep           endpoint;
    struct delayed_work     nostream_work;
    struct list_head        cancelled_list;
    struct list_head        pending_list;
    struct list_head        started_list;
    void __iomem            *regs;
    struct dwc3_trb         *trb_pool;
    dma_addr_t trb_pool_dma;
    struct dwc3             *dwc;
    u32 saved_state;
    unsigned int            flags;
#define DWC3_EP_ENABLED                 BIT(0);
#define DWC3_EP_STALL                   BIT(1);
#define DWC3_EP_WEDGE                   BIT(2);
#define DWC3_EP_TRANSFER_STARTED        BIT(3);
#define DWC3_EP_END_TRANSFER_PENDING    BIT(4);
#define DWC3_EP_PENDING_REQUEST         BIT(5);
#define DWC3_EP_DELAY_START             BIT(6);
#define DWC3_EP_WAIT_TRANSFER_COMPLETE  BIT(7);
#define DWC3_EP_IGNORE_NEXT_NOSTREAM    BIT(8);
#define DWC3_EP_FORCE_RESTART_STREAM    BIT(9);
#define DWC3_EP_STREAM_PRIMED           BIT(10);
#define DWC3_EP_PENDING_CLEAR_STALL     BIT(11);
#define DWC3_EP_TXFIFO_RESIZED          BIT(12);
#define DWC3_EP_DELAY_STOP             BIT(13);
#define DWC3_EP_RESOURCE_ALLOCATED      BIT(14);
#define DWC3_EP0_DIR_IN                 BIT(31);
    u8 trb_enqueue;
    u8 trb_dequeue;
    u8 number;
    u8 type;
    u8 resource_index;
    u32 frame_number;
    u32 interval;
    char name[20];
    unsigned direction:1;
    unsigned stream_capable:1;
    u8 combo_num;
    int start_cmd_status;
};

成员

endpoint

usb 端点

nostream_work

用于处理批量 NoStream 的工作

cancelled_list

此端点已取消的请求的列表

pending_list

此端点的挂起请求的列表

started_list

此端点上已启动的请求的列表

regs

指向第一个端点寄存器的指针

trb_pool

事务缓冲区数组

trb_pool_dma

trb_pool 的 DMA 地址

dwc

指向 DWC 控制器的指针

saved_state

休眠期间保存的 ep 状态

flags

端点标志(楔入、停止...)

trb_enqueue

TRB 数组中的入队“指针”

trb_dequeue

TRB 数组中的出队“指针”

number

端点号 (1 - 15)

type

设置为 bmAttributes & USB_ENDPOINT_XFERTYPE_MASK

resource_index

资源传输索引

frame_number

设置为我们希望此传输开始的帧号 (ISOC)

interval

启动 ISOC 传输的间隔

name

人类可读的名称,例如 ep1out-bulk

direction

对于 TX 为真,对于 RX 为假

stream_capable

启用流时为真

combo_num

帧号的测试组合 BIT[15:14],用于测试同步启动传输命令故障解决方法

start_cmd_status

combo_num = ‘b00 测试 START TRANSFER 命令的状态

struct dwc3_trb

传输请求块(硬件格式)

定义:

struct dwc3_trb {
    u32 bpl;
    u32 bph;
    u32 size;
    u32 ctrl;
};

成员

bpl

DW0-3

bph

DW4-7

size

DW8-B

ctrl

DWC-F

struct dwc3_hwparams

HWPARAMS 寄存器的副本

定义:

struct dwc3_hwparams {
    u32 hwparams0;
    u32 hwparams1;
    u32 hwparams2;
    u32 hwparams3;
    u32 hwparams4;
    u32 hwparams5;
    u32 hwparams6;
    u32 hwparams7;
    u32 hwparams8;
    u32 hwparams9;
};

成员

hwparams0

GHWPARAMS0

hwparams1

GHWPARAMS1

hwparams2

GHWPARAMS2

hwparams3

GHWPARAMS3

hwparams4

GHWPARAMS4

hwparams5

GHWPARAMS5

hwparams6

GHWPARAMS6

hwparams7

GHWPARAMS7

hwparams8

GHWPARAMS8

hwparams9

GHWPARAMS9

struct dwc3_request

传输请求的表示

定义:

struct dwc3_request {
    struct usb_request      request;
    struct list_head        list;
    struct dwc3_ep          *dep;
    struct scatterlist      *start_sg;
    unsigned int            num_pending_sgs;
    unsigned int            remaining;
    unsigned int            status;
#define DWC3_REQUEST_STATUS_QUEUED              0;
#define DWC3_REQUEST_STATUS_STARTED             1;
#define DWC3_REQUEST_STATUS_DISCONNECTED        2;
#define DWC3_REQUEST_STATUS_DEQUEUED            3;
#define DWC3_REQUEST_STATUS_STALLED             4;
#define DWC3_REQUEST_STATUS_COMPLETED           5;
#define DWC3_REQUEST_STATUS_UNKNOWN             -1;
    u8 epnum;
    struct dwc3_trb         *trb;
    dma_addr_t trb_dma;
    unsigned int            num_trbs;
    unsigned int            direction:1;
    unsigned int            mapped:1;
};

成员

request

要传输的 struct usb_request

list

用于请求排队的 list_head

dep

拥有此请求的 struct dwc3_ep

start_sg

指向接下来应排队的 sg 的指针

num_pending_sgs

待处理 sg 的计数器

remaining

剩余数据量

status

内部 dwc3 请求状态跟踪

epnum

此请求引用的端点号

trb

指向 struct dwc3_trb 的指针

trb_dma

trb 的 DMA 地址

num_trbs

此请求使用的 TRB 数量

direction

IN 或 OUT 方向标志

mapped

请求已被 dma 映射时为 true

struct dwc3

我们控制器的表示

定义:

struct dwc3 {
    struct work_struct      drd_work;
    struct dwc3_trb         *ep0_trb;
    void *bounce;
    u8 *setup_buf;
    dma_addr_t ep0_trb_addr;
    dma_addr_t bounce_addr;
    struct dwc3_request     ep0_usb_req;
    struct completion       ep0_in_setup;
    spinlock_t lock;
    struct mutex            mutex;
    struct device           *dev;
    struct device           *sysdev;
    struct platform_device  *xhci;
    struct resource         xhci_resources[DWC3_XHCI_RESOURCES_NUM];
    struct dwc3_event_buffer *ev_buf;
    struct dwc3_ep          *eps[DWC3_ENDPOINTS_NUM];
    struct usb_gadget       *gadget;
    struct usb_gadget_driver *gadget_driver;
    struct clk              *bus_clk;
    struct clk              *ref_clk;
    struct clk              *susp_clk;
    struct clk              *utmi_clk;
    struct clk              *pipe_clk;
    struct reset_control    *reset;
    struct usb_phy          *usb2_phy;
    struct usb_phy          *usb3_phy;
    struct phy              *usb2_generic_phy[DWC3_USB2_MAX_PORTS];
    struct phy              *usb3_generic_phy[DWC3_USB3_MAX_PORTS];
    u8 num_usb2_ports;
    u8 num_usb3_ports;
    bool phys_ready;
    struct ulpi             *ulpi;
    bool ulpi_ready;
    void __iomem            *regs;
    size_t regs_size;
    enum usb_dr_mode        dr_mode;
    u32 current_dr_role;
    u32 desired_dr_role;
    struct extcon_dev       *edev;
    struct notifier_block   edev_nb;
    enum usb_phy_interface  hsphy_mode;
    struct usb_role_switch  *role_sw;
    enum usb_dr_mode        role_switch_default_mode;
    struct power_supply     *usb_psy;
    u32 fladj;
    u32 ref_clk_per;
    u32 irq_gadget;
    u32 otg_irq;
    u32 current_otg_role;
    u32 desired_otg_role;
    bool otg_restart_host;
    u32 u1u2;
    u32 maximum_speed;
    u32 gadget_max_speed;
    enum usb_ssp_rate       max_ssp_rate;
    enum usb_ssp_rate       gadget_ssp_rate;
    u32 ip;
#define DWC3_IP                 0x5533;
#define DWC31_IP                0x3331;
#define DWC32_IP                0x3332;
    u32 revision;
#define DWC3_REVISION_ANY       0x0;
#define DWC3_REVISION_173A      0x5533173a;
#define DWC3_REVISION_175A      0x5533175a;
#define DWC3_REVISION_180A      0x5533180a;
#define DWC3_REVISION_183A      0x5533183a;
#define DWC3_REVISION_185A      0x5533185a;
#define DWC3_REVISION_187A      0x5533187a;
#define DWC3_REVISION_188A      0x5533188a;
#define DWC3_REVISION_190A      0x5533190a;
#define DWC3_REVISION_194A      0x5533194a;
#define DWC3_REVISION_200A      0x5533200a;
#define DWC3_REVISION_202A      0x5533202a;
#define DWC3_REVISION_210A      0x5533210a;
#define DWC3_REVISION_220A      0x5533220a;
#define DWC3_REVISION_230A      0x5533230a;
#define DWC3_REVISION_240A      0x5533240a;
#define DWC3_REVISION_250A      0x5533250a;
#define DWC3_REVISION_260A      0x5533260a;
#define DWC3_REVISION_270A      0x5533270a;
#define DWC3_REVISION_280A      0x5533280a;
#define DWC3_REVISION_290A      0x5533290a;
#define DWC3_REVISION_300A      0x5533300a;
#define DWC3_REVISION_310A      0x5533310a;
#define DWC3_REVISION_320A      0x5533320a;
#define DWC3_REVISION_330A      0x5533330a;
#define DWC31_REVISION_ANY      0x0;
#define DWC31_REVISION_110A     0x3131302a;
#define DWC31_REVISION_120A     0x3132302a;
#define DWC31_REVISION_160A     0x3136302a;
#define DWC31_REVISION_170A     0x3137302a;
#define DWC31_REVISION_180A     0x3138302a;
#define DWC31_REVISION_190A     0x3139302a;
#define DWC31_REVISION_200A     0x3230302a;
#define DWC32_REVISION_ANY      0x0;
#define DWC32_REVISION_100A     0x3130302a;
    u32 version_type;
#define DWC31_VERSIONTYPE_ANY           0x0;
#define DWC31_VERSIONTYPE_EA01          0x65613031;
#define DWC31_VERSIONTYPE_EA02          0x65613032;
#define DWC31_VERSIONTYPE_EA03          0x65613033;
#define DWC31_VERSIONTYPE_EA04          0x65613034;
#define DWC31_VERSIONTYPE_EA05          0x65613035;
#define DWC31_VERSIONTYPE_EA06          0x65613036;
    enum dwc3_ep0_next      ep0_next_event;
    enum dwc3_ep0_state     ep0state;
    enum dwc3_link_state    link_state;
    u16 u2sel;
    u16 u2pel;
    u8 u1sel;
    u8 u1pel;
    u8 speed;
    u8 num_eps;
    struct dwc3_hwparams    hwparams;
    struct debugfs_regset32 *regset;
    u32 dbg_lsp_select;
    u8 test_mode;
    u8 test_mode_nr;
    u8 lpm_nyet_threshold;
    u8 hird_threshold;
    u8 rx_thr_num_pkt;
    u8 rx_max_burst;
    u8 tx_thr_num_pkt;
    u8 tx_max_burst;
    u8 rx_thr_num_pkt_prd;
    u8 rx_max_burst_prd;
    u8 tx_thr_num_pkt_prd;
    u8 tx_max_burst_prd;
    u8 tx_fifo_resize_max_num;
    u8 clear_stall_protocol;
    u16 num_hc_interrupters;
    const char              *hsphy_interface;
    unsigned connected:1;
    unsigned softconnect:1;
    unsigned delayed_status:1;
    unsigned ep0_bounced:1;
    unsigned ep0_expect_in:1;
    unsigned sysdev_is_parent:1;
    unsigned has_lpm_erratum:1;
    unsigned is_utmi_l1_suspend:1;
    unsigned is_fpga:1;
    unsigned pending_events:1;
    unsigned do_fifo_resize:1;
    unsigned pullups_connected:1;
    unsigned setup_packet_pending:1;
    unsigned three_stage_setup:1;
    unsigned dis_start_transfer_quirk:1;
    unsigned usb3_lpm_capable:1;
    unsigned usb2_lpm_disable:1;
    unsigned usb2_gadget_lpm_disable:1;
    unsigned disable_scramble_quirk:1;
    unsigned u2exit_lfps_quirk:1;
    unsigned u2ss_inp3_quirk:1;
    unsigned req_p1p2p3_quirk:1;
    unsigned del_p1p2p3_quirk:1;
    unsigned del_phy_power_chg_quirk:1;
    unsigned lfps_filter_quirk:1;
    unsigned rx_detect_poll_quirk:1;
    unsigned dis_u3_susphy_quirk:1;
    unsigned dis_u2_susphy_quirk:1;
    unsigned dis_enblslpm_quirk:1;
    unsigned dis_u1_entry_quirk:1;
    unsigned dis_u2_entry_quirk:1;
    unsigned dis_rxdet_inp3_quirk:1;
    unsigned dis_u2_freeclk_exists_quirk:1;
    unsigned dis_del_phy_power_chg_quirk:1;
    unsigned dis_tx_ipgap_linecheck_quirk:1;
    unsigned resume_hs_terminations:1;
    unsigned ulpi_ext_vbus_drv:1;
    unsigned parkmode_disable_ss_quirk:1;
    unsigned parkmode_disable_hs_quirk:1;
    unsigned gfladj_refclk_lpm_sel:1;
    unsigned tx_de_emphasis_quirk:1;
    unsigned tx_de_emphasis:2;
    unsigned dis_metastability_quirk:1;
    unsigned dis_split_quirk:1;
    unsigned async_callbacks:1;
    unsigned sys_wakeup:1;
    unsigned wakeup_configured:1;
    unsigned suspended:1;
    unsigned susphy_state:1;
    u16 imod_interval;
    int max_cfg_eps;
    int last_fifo_depth;
    int num_ep_resized;
    struct dentry           *debug_root;
    u32 gsbuscfg0_reqinfo;
    u32 wakeup_pending_funcs;
};

成员

drd_work

用于角色切换的工作队列

ep0_trb

用于 ctrl_req 的 trb

bounce

bounce 缓冲区的地址

setup_buf

在处理 STD USB 请求时使用

ep0_trb_addr

ep0_trb 的 dma 地址

bounce_addr

bounce 的 dma 地址

ep0_usb_req

处理 STD USB 请求时使用的虚拟请求

ep0_in_setup

一个控制传输已完成并进入设置阶段

lock

用于同步

mutex

用于模式切换

dev

指向我们的 struct device 的指针

sysdev

指向支持 DMA 的设备的指针

xhci

指向我们的 xHCI 子设备的指针

xhci_resources

我们的 xhci 子设备的结构资源

ev_buf

struct dwc3_event_buffer 指针

eps

端点数组

gadget

外围控制器的设备端表示

gadget_driver

指向 gadget 驱动程序的指针

bus_clk

用于访问寄存器的时钟

ref_clk

参考时钟

susp_clk

当 SS phy 处于低功耗 (S3) 状态时使用的时钟

utmi_clk

用于 USB2 PHY 通信的时钟

pipe_clk

用于 USB3 PHY 通信的时钟

reset

重置控制

usb2_phy

指向 USB2 PHY 的指针

usb3_phy

指向 USB3 PHY 的指针

usb2_generic_phy

指向 USB2 PHY 数组的指针

usb3_generic_phy

指向 USB3 PHY 数组的指针

num_usb2_ports

USB2 端口的数量

num_usb3_ports

USB3 端口的数量

phys_ready

指示 PHY 已准备就绪的标志

ulpi

指向 ulpi 接口的指针

ulpi_ready

指示 ULPI 已初始化的标志

regs

我们寄存器的基本地址

regs_size

地址空间大小

dr_mode

请求的操作模式

current_dr_role

处于双角色模式时的当前操作角色

desired_dr_role

处于双角色模式时所需的操作角色

edev

extcon 句柄

edev_nb

extcon 通知器

hsphy_mode

UTMI phy 模式,以下之一: - USBPHY_INTERFACE_MODE_UTMI - USBPHY_INTERFACE_MODE_UTMIW

role_sw

usb_role_switch 句柄

role_switch_default_mode

当 usb 角色为 USB_ROLE_NONE 时,控制器的默认操作模式。

usb_psy

指向电源接口的指针。

fladj

帧长度调整

ref_clk_per

参考时钟周期配置

irq_gadget

外围控制器的 IRQ 号

otg_irq

OTG IRQ 的 IRQ 号

current_otg_role

使用 OTG 块时的当前操作角色

desired_otg_role

使用 OTG 块时所需的操作角色

otg_restart_host

OTG 控制器需要重新启动主机的标志

u1u2

仅用于修订版 <1.83a 以进行解决方法

maximum_speed

请求的最大速度(主要用于测试目的)

gadget_max_speed

请求的最大 gadget 速度

max_ssp_rate

SuperSpeed Plus 最大信令速率和通道数

gadget_ssp_rate

Gadget 驱动程序支持的最大 SuperSpeed Plus 信令速率和通道数。

ip

控制器的 ID

revision

IP 控制器的版本

version_type

VERSIONTYPE 寄存器内容,修订版的子版本

ep0_next_event

保存下一个预期事件

ep0state

端点零的状态

link_state

链路状态

u2sel

来自 Set SEL 请求的参数。

u2pel

来自 Set SEL 请求的参数。

u1sel

来自 Set SEL 请求的参数。

u1pel

来自 Set SEL 请求的参数。

speed

设备速度(super、high、full、low)

num_eps

端点数

hwparams

hwparams 寄存器的副本

regset

指向 regdump 文件的 debugfs 指针

dbg_lsp_select

当前调试 lsp 多路复用器寄存器选择

test_mode

当我们进入 USB 测试模式时为 true

test_mode_nr

测试功能选择器

lpm_nyet_threshold

LPM NYET 响应阈值

hird_threshold

HIRD 阈值

rx_thr_num_pkt

USB 接收数据包计数

rx_max_burst

最大 USB 接收突发大小

tx_thr_num_pkt

USB 传输数据包计数

tx_max_burst

最大 USB 传输突发大小

rx_thr_num_pkt_prd

周期性 ESS 接收数据包计数

rx_max_burst_prd

最大周期性 ESS 接收突发大小

tx_thr_num_pkt_prd

周期性 ESS 传输数据包计数

tx_max_burst_prd

最大周期性 ESS 传输突发大小

tx_fifo_resize_max_num

txfifo 大小调整期间分配的最大 fifo 数量

clear_stall_protocol

需要延迟状态阶段的端点号

num_hc_interrupters

主机控制器中断器的数量

hsphy_interface

“utmi” 或 “ulpi”

connected

当我们连接到主机时为 true,否则为 false

softconnect

调用 gadget connect 时为 true,运行 disconnect 时为 false

delayed_status

当 gadget 驱动程序请求延迟状态时为 true

ep0_bounced

当我们使用 bounce 缓冲区时为 true

ep0_expect_in

当我们期望 DATA IN 传输时为 true

sysdev_is_parent

当 dwc3 设备具有父驱动程序时为 true

has_lpm_erratum

当核心配置了 LPM 勘误时为 true。请注意,软件现在无法在运行时检测到这一点。

is_utmi_l1_suspend

核心断言输出信号 0 - utmi_sleep_n 1 - utmi_l1_suspend_n

is_fpga

当我们使用 FPGA 板时为 true

pending_events

当我们有待处理的 IRQ 要处理时为 true

do_fifo_resize

当为 dwc3 端点启用 txfifo 大小调整时为 true

pullups_connected

设置 Run/Stop 位时为 true

setup_packet_pending

当 FIFO 中存在 Setup 数据包时为 true。解决方法

three_stage_setup

如果我们执行三阶段设置,则设置

dis_start_transfer_quirk

如果 DWC_usb31 版本 1.70a-ea06 及更低版本不需要 start_transfer 失败 SW 解决方法,则设置

usb3_lpm_capable

如果硬件支持链路电源管理,则设置

usb2_lpm_disable

设置为禁用主机的 usb2 lpm

usb2_gadget_lpm_disable

设置为禁用 gadget 的 usb2 lpm

disable_scramble_quirk

如果启用禁用加扰怪癖,则设置

u2exit_lfps_quirk

如果启用 u2exit lfps 怪癖,则设置

u2ss_inp3_quirk

如果启用 P3 OK for U2/SS Inactive 怪癖,则设置

req_p1p2p3_quirk

如果启用请求 p1p2p3 怪癖,则设置

del_p1p2p3_quirk

如果启用延迟 p1p2p3 怪癖,则设置

del_phy_power_chg_quirk

如果启用延迟 phy 电源更改怪癖,则设置

lfps_filter_quirk

如果启用 LFPS 过滤器怪癖,则设置

rx_detect_poll_quirk

如果启用 rx_detect 以轮询 lfps 怪癖,则设置

dis_u3_susphy_quirk

如果禁用 usb3 挂起 phy,则设置

dis_u2_susphy_quirk

如果禁用 usb2 挂起 phy,则设置

dis_enblslpm_quirk

如果清除 GUSB2PHYCFG 中的 enblslpm,禁用到 PHY 的挂起信号,则设置。

dis_u1_entry_quirk

如果需要禁用链路进入 U1 状态,则设置。

dis_u2_entry_quirk

如果需要禁用链路进入 U2 状态,则设置。

dis_rxdet_inp3_quirk

如果禁用 P3 中的 Rx.Detect,则设置

dis_u2_freeclk_exists_quirk

如果清除 GUSB2PHYCFG 中的 u2_freeclk_exists,指定 USB2 PHY 不提供自由运行的 PHY 时钟,则设置。

dis_del_phy_power_chg_quirk

如果禁用延迟 phy 电源更改怪癖,则设置。

dis_tx_ipgap_linecheck_quirk

如果禁用 HS 传输期间的 u2mac 线路状态检查,则设置。

resume_hs_terminations

如果启用在从挂起恢复后修复不正确的 crc 生成的怪癖,则设置。

ulpi_ext_vbus_drv

设置为配置 upli 芯片以使用外部电源驱动 CPEN 引脚 VBUS。

parkmode_disable_ss_quirk

如果我们需要禁用 park 模式下的所有 SuperSpeed 实例,则设置。

parkmode_disable_hs_quirk

如果我们需要禁用 park 模式下的所有 HishSpeed 实例,则设置。

gfladj_refclk_lpm_sel

如果我们需要启用基于 ref_clk 运行的 SOF/ITP 计数器,则设置

tx_de_emphasis_quirk

如果启用 Tx 去加重怪癖,则设置

tx_de_emphasis

Tx 去加重值 0 - -6dB 去加重 1 - -3.5dB 去加重 2 - 无去加重 3 - 保留

dis_metastability_quirk

设置为禁用亚稳态怪癖。

dis_split_quirk

设置为禁用拆分边界。

async_callbacks

如果设置,指示将使用异步回调。

sys_wakeup

如果设备可以执行系统唤醒,则设置。

wakeup_configured

如果设备配置为远程唤醒,则设置。

suspended

设置为跟踪由于 U3/L2 导致的挂起事件。

susphy_state

PM 挂起之前 DWC3_GUSB2PHYCFG_SUSPHY + DWC3_GUSB3PIPECTL_SUSPHY 的状态。

imod_interval

以 250ns 增量设置中断调节间隔,或设置为 0 以禁用。

max_cfg_eps

所有 USB 配置中使用的当前最大 IN 端点数。

last_fifo_depth

用于确定下一个 fifo ram 起始地址的最后一个 fifo 深度。

num_ep_resized

携带当前已调整其 tx fifo 大小的端点数。

debug_root

此设备的根 debugfs 目录,用于放置其文件。

gsbuscfg0_reqinfo

存储从 glue 驱动程序传递的 GSBUSCFG0.DATRDREQINFO、DESRDREQINFO、DATWRREQINFO 和 DESWRREQINFO 值。

wakeup_pending_funcs

指示是否任何接口已请求以位图格式进行函数唤醒,其中位位置表示 interface_id。

struct dwc3_event_depevt

设备端点事件

定义:

struct dwc3_event_depevt {
    u32 one_bit:1;
    u32 endpoint_number:5;
    u32 endpoint_event:4;
    u32 reserved11_10:2;
    u32 status:4;
#define DEPEVT_STATUS_TRANSFER_ACTIVE   BIT(3);
#define DEPEVT_STATUS_BUSERR    BIT(0);
#define DEPEVT_STATUS_SHORT     BIT(1);
#define DEPEVT_STATUS_IOC       BIT(2);
#define DEPEVT_STATUS_LST       BIT(3) ;
#define DEPEVT_STATUS_MISSED_ISOC BIT(3) ;
#define DEPEVT_STREAMEVT_FOUND          1;
#define DEPEVT_STREAMEVT_NOTFOUND       2;
#define DEPEVT_STREAM_PRIME             0xfffe;
#define DEPEVT_STREAM_NOSTREAM          0x0;
#define DEPEVT_STATUS_CONTROL_DATA      1;
#define DEPEVT_STATUS_CONTROL_STATUS    2;
#define DEPEVT_STATUS_CONTROL_PHASE(n)  ((n) & 3);
#define DEPEVT_TRANSFER_NO_RESOURCE     1;
#define DEPEVT_TRANSFER_BUS_EXPIRY      2;
    u32 parameters:16;
#define DEPEVT_PARAMETER_CMD(n) (((n) & (0xf << 8)) >> 8);
};

成员

one_bit

指示这是一个端点事件(未使用)

endpoint_number

端点号

endpoint_event

我们拥有的事件: 0x00 - 保留 0x01 - XferComplete 0x02 - XferInProgress 0x03 - XferNotReady 0x04 - RxTxFifoEvt (IN->Underrun, OUT->Overrun) 0x05 - 保留 0x06 - StreamEvt 0x07 - EPCmdCmplt

reserved11_10

保留,请勿使用。

status

指示事件的状态。有关更多信息,请参阅数据手册。

parameters

当前事件的参数。有关更多信息,请参阅数据手册。

struct dwc3_event_devt

设备事件

定义:

struct dwc3_event_devt {
    u32 one_bit:1;
    u32 device_event:7;
    u32 type:4;
    u32 reserved15_12:4;
    u32 event_info:9;
    u32 reserved31_25:7;
};

成员

one_bit

指示这是一个非端点事件(未使用)

device_event

指示这是一个设备事件。应读取为 0x00

type

指示设备事件的类型。0 - DisconnEvt 1 - USBRst 2 - ConnectDone 3 - ULStChng 4 - WkUpEvt 5 - 保留 6 - Suspend (修订版 2.10a 及更早版本上的 EOPF) 7 - SOF 8 - 保留 9 - ErrticErr 10 - CmdCmplt 11 - EvntOverflow 12 - VndrDevTstRcved

reserved15_12

保留,未使用

event_info

有关此事件的信息

reserved31_25

保留,未使用

struct dwc3_event_gevt

其他核心事件

定义:

struct dwc3_event_gevt {
    u32 one_bit:1;
    u32 device_event:7;
    u32 phy_port_number:4;
    u32 reserved31_12:20;
};

成员

one_bit

指示这是一个非端点事件(未使用)

device_event

指示它是 (0x03) Carkit 或 (0x04) I2C 事件。

phy_port_number

不言自明

reserved31_12

保留,未使用。

union dwc3_event

事件缓冲区内容的表示

定义:

union dwc3_event {
    u32 raw;
    struct dwc3_event_type          type;
    struct dwc3_event_depevt        depevt;
    struct dwc3_event_devt          devt;
    struct dwc3_event_gevt          gevt;
};

成员

raw

原始 32 位事件

type

事件的类型

depevt

设备端点事件

devt

设备事件

gevt

全局事件

struct dwc3_gadget_ep_cmd_params

端点命令参数的表示

定义:

struct dwc3_gadget_ep_cmd_params {
    u32 param2;
    u32 param1;
    u32 param0;
};

成员

param2

第三个参数

param1

第二个参数

param0

第一个参数

u32 dwc3_mdwidth(struct dwc3 *dwc)

以位为单位获取 MDWIDTH 值

参数

struct dwc3 *dwc

指向上下文结构的指针

描述

以位为单位返回 MDWIDTH 配置值。

struct dwc3_request *next_request(struct list_head *list)

获取给定列表中的下一个请求

参数

struct list_head *list

要操作的请求列表

描述

调用者应注意锁定。此函数返回 NULL 或 **list** 上的第一个可用请求。

void dwc3_gadget_move_started_request(struct dwc3_request *req)

将 **req** 移动到 started_list

参数

struct dwc3_request *req

要移动的请求

描述

调用者应注意锁定。此函数会将 **req** 从其当前列表移动到端点的 started_list。

void dwc3_gadget_move_cancelled_request(struct dwc3_request *req, unsigned int reason)

将 **req** 移动到 cancelled_list

参数

struct dwc3_request *req

要移动的请求

unsigned int reason

dwc3 请求的取消原因

描述

调用者应注意锁定。此函数会将 **req** 从其当前列表移动到端点的 cancelled_list。

void dwc3_gadget_ep_get_transfer_index(struct dwc3_ep *dep)

从硬件获取传输索引

参数

struct dwc3_ep *dep

dwc3 端点

描述

调用者应注意锁定。 返回给定端点的传输资源索引。

void dwc3_gadget_dctl_write_safe(struct dwc3 *dwc, u32 value)

安全地写入 DCTL,防止链路状态更改

参数

struct dwc3 *dwc

指向上下文结构的指针

u32 value

要写入 DCTL 的值

描述

在对 DCTL 进行读取-修改-写入时使用此函数。它不会发送链路状态更改请求。

int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode)

启用 usb2 测试模式

参数

struct dwc3 *dwc

指向上下文结构的指针

int mode

要设置的模式(J、K SE0 NAK、强制启用)

描述

调用者应注意锁定。 如果传递了错误的测试选择器,此函数将返回 0 表示成功,否则返回 -EINVAL。

获取 usb 链路的当前状态

参数

struct dwc3 *dwc

指向上下文结构的指针

描述

调用者应注意锁定。 此函数将在成功时返回链路状态(>= 0)或 -ETIMEDOUT。

将 usb 链路设置为特定状态

参数

struct dwc3 *dwc

指向上下文结构的指针

enum dwc3_link_state state

要将链路置于的状态

描述

调用者应注意锁定。 此函数将在成功时返回 0 或 -ETIMEDOUT。

void dwc3_ep_inc_trb(u8 *index)

递增 trb 索引。

参数

u8 *index

指向要递增的 TRB 索引的指针。

描述

索引永远不应指向链路 TRB。递增后,如果它指向链路 TRB,则环绕到开头。链路 TRB 始终位于最后一个 TRB 条目中。

void dwc3_ep_inc_enq(struct dwc3_ep *dep)

递增端点的入队指针

参数

struct dwc3_ep *dep

我们要递增其入队指针的端点

void dwc3_ep_inc_deq(struct dwc3_ep *dep)

递增端点的出队指针

参数

struct dwc3_ep *dep

我们要递增其入队指针的端点

void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, int status)

调用 struct usb_request 的 ->complete 回调

参数

struct dwc3_ep *dep

请求所属的端点

struct dwc3_request *req

我们要返回的请求

int status

请求的完成代码

描述

必须在持有控制器的锁并禁用中断的情况下调用。此函数将取消映射 **req** 并调用其 ->complete() 回调以通知上层它已完成。

int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned int cmd, u32 param)

为控制器发出通用命令

参数

struct dwc3 *dwc

指向控制器上下文的指针

unsigned int cmd

要发出的命令

u32 param

命令参数

描述

调用者应注意锁定。 将带有给定 **param** 的 **cmd** 发送到 **dwc** 并等待其完成。

int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd, struct dwc3_gadget_ep_cmd_params *params)

发出端点命令

参数

struct dwc3_ep *dep

命令将要发出的端点

unsigned int cmd

要发出的命令

struct dwc3_gadget_ep_cmd_params *params

命令的参数

描述

调用者应处理锁定。 此函数将带有给定 **params** 的 **cmd** 发送到 **dep** 并等待其完成。

根据编程指南,如果链路状态为 L1/L2/U3,则发送“启动传输”命令可能无法完成。 编程指南建议通过在发送命令之前执行远程唤醒来将链路状态恢复为 ON/U0。 但是,当用户/函数未通过唤醒操作发送唤醒请求时,请勿启动远程唤醒。 在允许时发送命令。

对于 L2 或 U3 链路状态,设备处于 USB 挂起状态。 发送“启动传输”命令时,应注意确保在 USB 恢复后完成该操作。

注释

对于 L1 链路状态,发出命令需要清除 GUSB2PHYCFG.SUSPENDUSB2,这会打开完成给定命令所需的信号(通常在 50us 内)。 这应在驱动程序设置的命令超时内发生。 无需其他步骤。

int dwc3_gadget_start_config(struct dwc3 *dwc, unsigned int resource_index)

重置端点资源

参数

struct dwc3 *dwc

指向 DWC3 上下文的指针

unsigned int resource_index

DEPSTARTCFG.XferRscIdx 值(必须为 0 或 2)

描述

设置 resource_index=0 以重置所有端点的资源分配。 作为开机/软重置初始化的一部分执行此操作。

设置 resource_index=2 以仅重置非控制端点的资源。 在收到 SET_CONFIGURATION 请求或休眠恢复时执行此操作。

int dwc3_gadget_calc_tx_fifo_size(struct dwc3 *dwc, int mult)

计算 txfifo 大小值

参数

struct dwc3 *dwc

指向 DWC3 上下文的指针

int mult

计算 fifo_size 时要使用的乘数

描述

根据以下公式计算大小值

DWC3 修订版 280A 及更早版本:fifo_size = mult * (max_packet / mdwidth) + 1;

DWC3 修订版 290A 及更高版本:fifo_size = mult * ((max_packet + mdwidth)/mdwidth + 1) + 1

最大数据包大小设置为 1024,因为 txfifo 要求主要适用于超高速 USB 用例。 但是,对于其他情况(即高速 USB),安全起见可以高估 fifo 分配。

int dwc3_gadget_calc_ram_depth(struct dwc3 *dwc)

计算 txfifo 的 ram 深度

参数

struct dwc3 *dwc

指向 DWC3 上下文的指针

void dwc3_gadget_clear_tx_fifos(struct dwc3 *dwc)

清除 txfifo 分配

参数

struct dwc3 *dwc

指向 DWC3 上下文的指针

描述

迭代所有端点寄存器并清除之前的 txfifo 分配。

int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, unsigned int action)

初始化硬件端点

参数

struct dwc3_ep *dep

要初始化的端点

unsigned int action

INIT、MODIFY 或 RESTORE 之一

描述

调用者应注意锁定。 执行所有必要的命令来初始化硬件端点,以便小工具驱动程序可以使用它。

int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)

禁用硬件端点

参数

struct dwc3_ep *dep

要禁用的端点

描述

此函数撤消 __dwc3_gadget_ep_enable 所做的工作,并删除当前由硬件处理的请求和尚未调度的请求。

调用者应注意锁定。

struct dwc3_trb *dwc3_ep_prev_trb(struct dwc3_ep *dep, u8 index)

返回环中的上一个 TRB

参数

struct dwc3_ep *dep

带有 TRB 环的端点

u8 index

环中当前 TRB 的索引

描述

返回索引所指向的 TRB 之前的 TRB。如果索引为 0,我们将向后环绕,跳过链接 TRB,然后返回它之前的 TRB。

void dwc3_prepare_one_trb(struct dwc3_ep *dep, struct dwc3_request *req, unsigned int trb_length, unsigned int chain, unsigned int node, bool use_bounce_buffer, bool must_interrupt)

从一个请求设置一个 TRB

参数

struct dwc3_ep *dep

为此请求准备的端点

struct dwc3_request *req

dwc3_request 指针

unsigned int trb_length

TRB 的缓冲区大小

unsigned int chain

此 TRB 是否应链接到下一个?

unsigned int node

仅适用于同步端点。第一个 TRB 需要不同的类型。

bool use_bounce_buffer

设置为使用反弹缓冲区

bool must_interrupt

设置为在 TRB 完成时中断

int dwc3_prepare_last_sg(struct dwc3_ep *dep, struct dwc3_request *req, unsigned int entry_length, unsigned int node)

为最后一个 SG 条目准备 TRB

参数

struct dwc3_ep *dep

请求所属的端点

struct dwc3_request *req

要准备的请求

unsigned int entry_length

最后一个 SG 条目大小

unsigned int node

指示这是否不是第一个条目(仅适用于 isoc)

描述

返回准备好的 TRB 的数量。

int __dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, bool interrupt)

停止当前活动传输

参数

struct dwc3_ep *dep

isoc 端点

bool force

在命令中设置 forcerm 位

bool interrupt

在结束传输命令后,命令完成中断

描述

设置 force 时,将设置 ForceRM 位。在这种情况下,控制器不会在命令完成时更新 TRB 进度。它也不会清除 TRB 中的 HWO 位。在这种情况下,该命令也不会立即完成。

int dwc3_gadget_start_isoc_quirk(struct dwc3_ep *dep)

解决无效帧号问题

参数

struct dwc3_ep *dep

isoc 端点

描述

此函数测试来自 XferNotReady 事件报告的 16 位微帧号的 BIT[15:14] 的正确组合,以用于启动 isoc 传输的未来帧号。

在 DWC_usb31 1.70a-ea06 及更早版本中,对于高速和全速同步 IN,XferNotReady 事件报告的 16 位微帧号的 BIT[15:14] 无效。驱动程序使用此号码来安排同步传输,并将其传递给 START TRANSFER 命令。因为此号码无效,所以命令可能会失败。如果 BIT[15:14] 与内部 16 位微帧匹配,则 START TRANSFER 命令将通过,传输将在计划的时间开始;如果相差 1,该命令仍将通过,但传输将在 2 秒后开始。对于所有其他情况,START TRANSFER 命令将因总线过期而失败。

为了解决这个问题,我们可以通过发送具有不同 BIT[15:14] 值的 START TRANSFER 命令来测试 BIT[15:14] 的正确组合:'b00、'b01、'b10 和 'b11。每个组合相隔 2^14 uframe(或 2 秒)。4 秒后的结果将是总线过期状态。因此,在 BIT[15:14] 的 4 种可能组合中,将有 2 个成功的和 2 个失败的 START COMMAND 状态。2 个成功的命令状态之一将导致延迟 2 秒的启动。较小的 BIT[15:14] 值是正确的组合。

由于只有 4 个结果并且结果是有序的,我们可以简单地测试 2 个具有 BIT[15:14] 组合 'b00 和 'b01 的 START TRANSFER 命令,以推断出较小的成功组合。

假设 test0 = 组合 'b00 的测试状态,test1 = BIT[15:14] 的 'b01 的测试状态。正确的组合如下

如果 test0 失败且 test1 通过,则 BIT[15:14] 为 'b01;如果 test0 失败且 test1 失败,则 BIT[15:14] 为 'b10;如果 test0 通过且 test1 失败,则 BIT[15:14] 为 'b11;如果 test0 通过且 test1 通过,则 BIT[15:14] 为 'b00

Synopsys STAR 9001202023:同步 IN 端点的微帧号错误。

void dwc3_gadget_setup_nump(struct dwc3 *dwc)

计算并初始化 DWC3_DCFG 的 NUMP 字段

参数

struct dwc3 *dwc

指向上下文结构的指针

描述

以下内容看起来很复杂,但实际上非常简单。为了计算我们可以在 OUT 传输上一次突发的数据包数量,我们将使用 RxFIFO 大小。

要计算 RxFIFO 大小,我们需要两个数字:MDWIDTH = 内部内存总线的大小(以位为单位)RAM2_DEPTH = 内部 RAM2 的深度(以 MDWIDTH 为单位)(RxFIFO 位于此处)

有了这两个数字,公式很简单

RxFIFO Size = (RAM2_DEPTH * MDWIDTH / 8) - 24 - 16;

24 字节用于 3x SETUP 数据包,16 字节是时钟域交叉容差

给定 RxFIFO Size,NUMP = RxFIFOSize / 1024;

int dwc3_gadget_check_config(struct usb_gadget *g)

确保 dwc3 可以支持 USB 配置

参数

struct usb_gadget *g

指向 USB gadget 的指针

描述

用于记录 USB 复合设备中使用的最大端点数。(跨所有配置)这将用于在调整各个端点的内部存储器大小以计算 TXFIFO 大小时。它将有助于确保调整大小逻辑至少为一个最大数据包保留足够的空间。

int dwc3_gadget_init(struct dwc3 *dwc)

初始化 gadget 相关寄存器

参数

struct dwc3 *dwc

指向我们的控制器上下文结构的指针

描述

成功返回 0,否则返回负 errno。

int dwc3_get_dr_mode(struct dwc3 *dwc)

验证并设置 dr_mode

参数

struct dwc3 *dwc

指向上下文结构的指针

int dwc3_core_soft_reset(struct dwc3 *dwc)

发出核心软复位和 PHY 复位

参数

struct dwc3 *dwc

指向上下文结构的指针

void dwc3_ref_clk_period(struct dwc3 *dwc)

参考时钟周期配置 默认参考时钟周期取决于硬件配置。对于参考时钟与默认值不同的系统,这将在 DWC3_GUCTL 寄存器中设置时钟周期。

参数

struct dwc3 *dwc

指向我们的控制器上下文结构的指针

void dwc3_free_one_event_buffer(struct dwc3 *dwc, struct dwc3_event_buffer *evt)

释放一个事件缓冲区

参数

struct dwc3 *dwc

指向我们的控制器上下文结构的指针

struct dwc3_event_buffer *evt

指向要释放的事件缓冲区的指针

struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc, unsigned int length)

分配一个事件缓冲区结构

参数

struct dwc3 *dwc

指向我们的控制器上下文结构的指针

unsigned int length

事件缓冲区的大小

描述

成功时返回指向已分配事件缓冲区结构的指针,否则返回 ERR_PTR(errno)。

void dwc3_free_event_buffers(struct dwc3 *dwc)

释放所有已分配的事件缓冲区

参数

struct dwc3 *dwc

指向我们的控制器上下文结构的指针

int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned int length)

分配大小为 lengthnum 个事件缓冲区

参数

struct dwc3 *dwc

指向我们的控制器上下文结构的指针

unsigned int length

事件缓冲区的大小

描述

成功返回 0,否则返回负 errno。在错误情况下,dwc 可能包含一些已分配但未全部请求的缓冲区。

int dwc3_event_buffers_setup(struct dwc3 *dwc)

设置我们分配的事件缓冲区

参数

struct dwc3 *dwc

指向我们的控制器上下文结构的指针

描述

成功返回 0,否则返回负 errno。

int dwc3_phy_setup(struct dwc3 *dwc)

配置 DWC3 核心的 USB PHY 接口

参数

struct dwc3 *dwc

指向我们的控制器上下文结构的指针

描述

成功返回 0。USB PHY 接口已配置但未初始化。PHY 接口和 PHY 与内核一起在 dwc3_core_init 中初始化。

int dwc3_core_init(struct dwc3 *dwc)

DWC3 核心的底层初始化

参数

struct dwc3 *dwc

指向我们的控制器上下文结构的指针

描述

成功返回 0,否则返回负 errno。