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 超高速标准的控制器,可以通过以下 4 种方式之一进行配置

  1. 仅限外围设备配置

  2. 仅限主机配置

  3. 双重角色配置

  4. 集线器配置

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

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

  1. Cavium

  2. 英特尔公司

  3. 高通

  4. 瑞芯微

  5. 意法半导体

  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. 超高速批量流

  8. 链路电源管理

  9. 用于调试的跟踪事件

  10. DebugFS [3] 接口

这些功能都已通过许多 树内 设备驱动程序进行过测试。 我们已验证 ConfigFS [4] 和旧版设备驱动程序。

驱动程序设计

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

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

驱动程序的最大部分涉及 Gadget API。

已知限制

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

OUT 传输大小要求

根据 Synopsys 数据手册,所有 OUT 传输 TRB [1]size 字段必须设置为可被端点的 wMaxPacketSize 整除的值。 这意味着,例如,为了接收大容量存储 CBW [5],req->length 必须设置为可被 wMaxPacketSize 整除的值(超高速为 1024,高速为 512,等等),否则 DWC3 驱动程序必须添加一个指向剩余长度的抛弃缓冲区的链式 TRB。 如果不这样做,OUT 传输将 会启动。

请注意,在撰写本文时,这不会成为问题,因为 DWC3 完全能够为剩余长度附加一个链式 TRB,并完全向设备驱动程序隐藏此细节。 仍然值得一提,因为这似乎是关于 DWC3 和非工作传输的最大查询来源。

TRB 环大小限制

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

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

报告错误

每当您遇到 DWC3 的问题时,首先应确保

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

  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 添加到抄送列表中。 如果您想格外确保我会帮助您,请按以下格式编写您的主题行

[错误报告] usb:dwc3:在执行 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 嗅探器有时可能会有帮助,但并非完全必要,即使不看连接线,也可以理解很多内容。

如果您需要任何帮助,请随时通过电子邮件发送给 并抄送 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 Databook,您可以解码它们上的信息。

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 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_FIRST_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 端点

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 测试启动传输命令的状态

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      *sg;
    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;
    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;
};

成员

drd_work

用于角色切换的工作队列

ep0_trb

用于 ctrl_req 的 trb

bounce

反弹缓冲区的地址

setup_buf

在处理标准 USB 请求时使用

ep0_trb_addr

ep0_trb 的 dma 地址

bounce_addr

bounce 的 dma 地址

ep0_usb_req

处理标准 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

设备速度(超速、高速、全速、低速)

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

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

hsphy_interface

“utmi” 或 “ulpi”

connected

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

softconnect

当调用 gadget 连接时为 true,当断开连接运行时为 false

delayed_status

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

ep0_bounced

当我们使用反弹缓冲区时为 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

如果我们为 U2/SS Inactive 启用 P3 OK,则设置

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

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

parkmode_disable_hs_quirk

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

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 ep 数。

last_fifo_depth

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

num_ep_resized

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

debug_root

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

gsbuscfg0_reqinfo

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

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->下溢,OUT->溢出) 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(USB 重置) 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(保留位 15-12)

保留,未使用

event_info(事件信息)

关于此事件的信息

reserved31_25(保留位 31-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(保留位 31-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

命令参数

描述

调用者应负责锁定。向 dwc 发送 cmd 命令以及给定的 param 参数,并等待其完成。

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

命令的参数

描述

调用者应负责锁定。此函数将向 dep 发送 cmd 命令以及给定的 params 参数,并等待其完成。

根据编程指南,如果链路状态为 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 是否应链接到下一个 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

指示这是否不是第一个条目(仅用于等时传输)

描述

返回已准备好的 TRB 的数量。

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

停止当前活动的传输

参数

struct dwc3_ep *dep

等时端点

bool force

在命令中设置 forcerm 位

bool interrupt

结束传输命令后的命令完成中断

描述

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

int dwc3_gadget_start_isoc_quirk(struct dwc3_ep *dep)

解决无效帧号问题

参数

struct dwc3_ep *dep

等时端点

描述

此函数测试从 XferNotReady 事件报告的 16 位微帧号的 BIT[15:14] 的正确组合,以获取启动等时传输的未来帧号。

在 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 个成功的 START COMMAND 状态和 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(RxFIFO 所在的位置)的 MDWIDTH 深度

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

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

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

给定 RxFIFO 大小,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。