Note
此文件的目的是为让中文读者更容易阅读和理解,而不是作为一个分支。 因此, 如果您对此文件有任何意见或更新,请先尝试更新原始英文文件。 如果您发现本文档与原始文件有任何不同或者有翻译问题,请发建议或者补丁给 该文件的译者,或者请求中文文档维护者和审阅者的帮助。
- Original:
- 翻译:
白钶凡 Kefan Bai <baikefan@leap-io-kernel.com>
- 校译:
EHCI 驱动¶
2002 年 12 月 27 日
EHCI 驱动用于借助支持 USB 2.0 的主机控制器,与高速 USB 2.0 设备通信。USB 2.0 向下兼容 USB 1.1,并定义了三种传输速率:
“高速”(High Speed)480 Mbit/sec(60 MByte/sec)
“全速”(Full Speed)12 Mbit/sec(1.5 MByte/sec)
“低速”(Low Speed)1.5 Mbit/sec
USB 1.1 仅支持全速与低速。高速设备可以在 USB 1.1 系统上使用,但速度会 降到 USB 1.1 的速率。
USB 1.1 设备也可以在 USB 2.0 系统上使用。当它们插入 EHCI 控制器时,会交给 USB 1.1 的伴随(companion)控制器处理,该控制器通常是 OHCI 或 UHCI。
当 USB 1.1 设备插入 USB 2.0 集线器时,它们会通过集线器里的事务转换器 (Transaction Translator,TT)与 EHCI 控制器通信。该转换器会把低速或全 速事务转换为高速分割事务,从而避免浪费传输带宽。
截至本文撰写时,该驱动已在以下 EHCI 实现上成功运行(按字母顺序): Intel、NEC、Philips 和 VIA。随着其他供应商的 EHCI 实现陆续问世,预计该 驱动在那些实现上也能正常运行。
自 2001 年年中起,usb-storage 设备就已可用(在 2.4 版该驱动上速度表现相当 不错),集线器则直到 2001 年底才开始可用。其他类型的高速设备似乎要等到 更多系统内置 USB 2.0 后才会出现。这类新系统从 2002 年初开始上市,并在 2002 年下半年变得更加常见。
注意,USB 2.0 的支持并不只靠 EHCI 本身。它还需要对 Linux-USB 核心 API
做其他修改,包括 hub 驱动;不过这些修改并不需要真正改变向 USB 设备驱动
暴露的基本 usbcore API。
David Brownell <dbrownell@users.sourceforge.net>
功能¶
该驱动长期在 x86 硬件上接受测试,也在 PPC 平台上使用过,因此大小端问题应 该都已解决。再加上各种必要的 PCI 细节都已处理妥当,即便在 DMA 映射较特 殊的系统上,I/O 也应能正常工作。
传输类型¶
截至本文撰写时,该驱动应当已经能够稳定处理所有控制传输、批量传输和中断传 输,包括经由 USB 2.0 集线器里的事务转换器访问 USB 1.1 设备;不过仍可能 存在 bug。
高速等时(ISO)传输支持也已可用,不过截至本文撰写时,还没有 Linux 驱动真 正使用它。
目前尚不支持通过事务转换器实现全速等时传输。需要注意,ISO 传输的分割 事务支持与高速 ISO 传输几乎无法共用代码,因为 EHCI 用不同的数据结构表示 它们。因此,目前大多数 USB 音频和视频设备还无法在高速总线上使用。
驱动行为¶
所有类型的传输都可以排队提交。这意味着某个接口驱动发出的控制传输(或经由 usbfs 提交的控制传输)不会干扰其他驱动的控制传输,而中断传输可以按 1 帧 周期运行,不必担心中断处理开销导致数据丢失。
EHCI 根集线器代码会将 USB 1.1 设备交给其伴随控制器处理。该驱动无需了解 那些驱动的任何细节;一个原本就能正常工作的 OHCI 或 UHCI 驱动,也不会因为 EHCI 驱动存在而需要修改。
电源管理方面仍有一些问题;当前挂起/恢复行为还不完全正确。
此外,在调度周期性事务(中断和等时传输)时还采取了一些简化处理。这些 简化会限制可调度的周期性事务数量,并且无法使用小于一帧的轮询间隔。
使用方式¶
假设系统中有一个 EHCI 控制器(位于 PCI 卡或主板上),并且此驱动是以模块形 式编译的,那么可以这样加载:
# modprobe ehci-hcd
卸载方式:
# rmmod ehci-hcd
还应加载一个伴随控制器驱动,例如 ohci-hcd 或 uhci-hcd。如果 EHCI
驱动出了问题,只要卸载它的模块,伴随控制器驱动就会接管此前由 EHCI 驱动处
理的全部设备(只是速度会降低)。
模块参数(传给 modprobe)包括:
- log2_irq_thresh(默认值 0):
默认中断延迟的 log2 值,单位为微帧。默认值 0 表示 1 个微帧 (125 微秒),最大值 6 表示 2^6 = 64 个微帧。 该值控制 EHCI 控制器发出中断的频率。
如果你在 2.5 内核上使用此驱动,并且启用了 USB 调试支持,那么任一 EHCI 控
制器对应的 sysfs 目录下都会看到三个文件:
async转储异步调度,用于控制传输和批量传输。它会显示每个活动的
qh以及待处理的qtd,通常每个urb对应一个qtd。 (可以在usb-storage执行磁盘 I/O 时查看;也可顺便观察请求队列。)periodic转储周期性调度,用于中断传输和等时传输。不显示
qtd。registers显示控制器寄存器状态。
这些文件的内容有助于定位驱动问题。
设备驱动通常不需要关心自己是否运行在 EHCI 之上,但有时可能会想检查
usb_device->speed == USB_SPEED_HIGH。高速设备能做到全速(或低速)设备
做不到的事,例如高带宽的周期性传输(中断或 ISO 传输)。另外,设备描述符
中的某些值(例如周期性传输的轮询间隔)在高速模式下使用不同的编码方式。
不过,设备驱动一定要在 USB 2.0 集线器后面测一遍。使用事务转换器时,这些 集线器报告某些故障(例如断开连接)的方式会有所不同;已经见过一些驱动在 遇到与 OHCI 或 UHCI 不同的故障时表现不佳。
性能¶
USB 2.0 的吞吐量主要受两个因素制约:主机控制器处理请求的速度,以及设备响 应这些请求的速度。480 Mbit/sec 的“原始传输率”对所有设备都一样,但整体吞 吐量还会受到诸如高速包之间的间隔、驱动实现是否足够高效以及系统总体负载等 因素影响。延迟同样是需要考虑的性能指标。
批量传输通常用于看重吞吐量的场景。需要记住的是,批量传输总是以 512 字节包 为单位,而一个 USB 2.0 微帧中最多只能容纳 13 个这样的包。8 个 USB 2.0 微 帧构成一个 USB 1.1 帧,因此一个微帧的时长就是 125 微秒。
因此,只要硬件和驱动实现都足够成熟,批量传输就可以提供 50 MByte/sec 以上 的带宽。周期性传输模式(等时和中断)允许使用更大的包大小,从而可以逼近所 宣称的 480 Mbit/sec 传输率。
硬件性能¶
截至本文撰写时,单个 USB 2.0 设备的最大传输速率通常约为 20 MByte/sec。 这种情况当然会随时间变化:有些设备现在更快,有些则更慢。
第一代 NEC EHCI 实现似乎存在大约 28 MByte/sec 的硬件瓶颈。虽然这对单个 20 MByte/sec 的设备显然已经够用,但把三个这样的设备挂到同一总线上,并不 能得到 60 MByte/sec。问题似乎在于控制器硬件无法并发进行 USB 与 PCI 访问, 因此它每个微帧只会尝试 6 次(也许是 7 次)USB 事务,而不是 13 次。 (对一款比其他产品早上市一年的芯片来说,这样的取舍也算合理。)
预计较新的实现会在这方面做得更好,通过投入更多芯片面积来解决这个问题, 使新的主板芯片组更接近 60 MByte/sec 的目标。这既包括 NEC 的更新实现,也 包括其他厂商的芯片。
主机从 EHCI 控制器收到“请求已完成”中断的最小延迟为一个微帧
(125 微秒)。该延迟可以调节;驱动提供了一个模块选项。
默认情况下,ehci-hcd 使用最小延迟,这意味着发出控制或批量请求后,通
常不到 250 微秒就能得知它已经完成(具体取决于传输大小)。
软件性能¶
即便只是要达到 20 MByte/sec 的传输速率,Linux-USB 设备驱动也必须让 EHCI 队列始终保持满载。这意味着要发出较大的请求,或者在需要发出一连串小请求 时使用批量请求排队。如果驱动做不到这一点,性能就会明显受影响。
在典型场景下,如果使用 usb_bulk_msg() 以 4 KB 块循环写出,会浪费超过
一半的 USB 2.0 带宽。I/O 完成与驱动发出下一次请求之间的空档,往往比一次
I/O 本身耗时还长。如果同样的循环改用 16 KB 块,情况会好一些;若使用一连串
128 KB 块,则浪费会少得多。
但与其依赖这么大的 I/O 缓冲区来提升同步 I/O 的效率,不如直接向主机控制器 排队提交多个(批量)请求,然后等待它们全部完成(或在出错时取消)。这种 URB 排队方式对所有 USB 1.1 主机控制器驱动同样适用。
在 Linux 2.5 内核中,定义了新的 usb_sg_*() API;它们会把 scatterlist
中的所有缓冲区都排入队列。它们还使用 scatterlist 的 DMA 映射(其中可能
应用 IOMMU)并减少中断次数,这些都有助于让高速传输尽可能快地运行。
- 待办:
中断传输和等时(ISO)传输的性能问题。 这些周期性传输都是完全调度的,因此主要问题可能在于如何触发高带宽模式。
- 待办:
通过
sysfs中的uframe_periodic_max参数,可以分配超过标准 80% 的周期性带宽。 后续将对此进行说明。