当前位置: 首页 > news >正文

MPC8641D PCIe控制器错误捕获与配置空间访问机制详解

1. 项目概述与核心价值

在嵌入式系统、服务器乃至个人电脑的硬件开发与驱动调试中,PCI Express(PCIe)总线是连接CPU与高速外设(如GPU、NVMe SSD、网卡)的生命线。然而,这条高速公路上一旦发生“交通事故”——比如数据包损坏、地址错误或配置冲突——如何快速、精准地定位现场,就成了工程师最头疼的问题。这不仅仅是读个状态码那么简单,你需要知道错误发生时的精确地址、事务类型、甚至数据包头部的完整快照。这正是PCIe控制器内部错误捕获机制的价值所在。

以飞思卡尔(现恩智浦)的MPC8641D这类集成处理器为例,其内置的PCIe控制器提供了PEX_ERR_CAP_R0R3等一系列错误捕获寄存器。当链路或事务层发生错误时,控制器能像“黑匣子”一样,瞬间冻结现场的关键信息。例如,对于一个导致错误的入站内存读请求,PEX_ERR_CAP_R2R3会联手记录下完整的64位目标地址和事务头。没有这个机制,调试就可能变成大海捞针,你只知道“有错”,却不知道“错在哪”。

与错误捕获相辅相成的,是PCIe设备的“身份证”和“控制面板”——配置空间。系统启动时,固件或操作系统必须通过访问这个空间,来识别设备(Vendor ID/Device ID)、分配内存/IO地址窗口(BAR)、设置中断路由,并决定设备以根复合体(Root Complex)还是端点(Endpoint)模式工作。MPC8641D提供了两种访问方式:传统的配置地址/数据寄存器(PEX_CONFIG_ADDR/DATA)和更灵活的ATMU(地址转换单元)窗口映射。理解这两种机制的细微差别,是编写稳定驱动和进行底层硬件初始化的基本功。

本文将深入MPC8641D参考手册的细节,拆解错误捕获寄存器的每个比特位含义,并厘清两种配置空间访问路径的完整流程与陷阱。无论你是在进行BSP(板级支持包)开发、驱动调试,还是单纯想理解PCIe硬件如何工作,这些内容都将提供直接的实践参考。

2. PCIe错误捕获机制深度解析

当PCIe链路上发生错误时,控制器需要记录足够的信息供软件分析。MPC8641D的错误捕获逻辑设计得非常细致,它将错误信息分散在多个寄存器中,并根据错误来源(内部发出还是外部传入)和事务类型,动态填充这些寄存器的内容。

2.1 错误捕获的状态机与控制逻辑

错误捕获并非持续进行,它遵循一个简单的状态机,由PEX_ERR_CAP_STAT寄存器控制。其中最关键的两个位是:

  • ECV (Error Capture Valid):该位为1时,表示捕获寄存器中已锁存了一次有效的错误信息。在此位被软件清除之前,控制器不会捕获新的错误,防止后续错误覆盖之前的现场。这是一个重要的设计,确保了调试信息的稳定性。
  • GSID (Global Source ID):这个字段指明了错误来源。对于MPC8641D的双控制器系统,0x02通常代表来自外部源(即链路上游或下游设备)的入站(Inbound)事务。非0x02的值(如0x00)则代表由处理器内部发起的出站(Outbound)事务。

这个设计非常实用。在复杂系统中,错误可能来自内部CPU发起的DMA操作,也可能来自外部设备的不合规请求。通过GSID,软件可以第一时间判断错误方向,缩小排查范围。

2.2 内存请求事务的错误现场还原

对于最常见的存储器读写请求错误,PEX_ERR_CAP_R2R3寄存器提供了关键的地址信息。这里有一个容易混淆的细节:PCIe事务头(TLP Header)有3 DW(双字,12字节)和4 DW(16字节)两种格式,分别对应32位地址和64位地址。

  • 对于3 DW头(32位地址):完整的32位地址被记录在PEX_ERR_CAP_R2寄存器的GH2字段中。此时PEX_ERR_CAP_R3的内容取决于错误方向(入站或出站),可能包含其他调试信息。
  • 对于4 DW头(64位地址):64位地址被拆分。高32位Address[63:32])存放在PEX_ERR_CAP_R2GH2字段,而低32位Address[31:0])则存放在PEX_ERR_CAP_R3GH3字段。

注意:地址对齐的细节在寄存器描述中,你会看到Address[7:2]这样的位域。这是因为PCIe地址总是按DWord(4字节)对齐的,最低两位(bit 1:0)恒为0。所以寄存器只捕获有意义的地址位,这节省了寄存器资源,也符合协议规范。软件在读取地址后,需要将低2位补零才能得到完整的字节地址。

表:PEX_ERR_CAP_R2/R3 在入站内存请求错误时的字段解析

寄存器位域名称描述(针对入站内存请求错误)
PEX_ERR_CAP_R231:24Address[31:24]Address[63:56]3 DW头时,为地址字节3;4 DW头时,为地址字节7。
23:16Address[23:16]Address[55:48]3 DW头时,为地址字节2;4 DW头时,为地址字节6。
15:8Address[15:8]Address[47:40]3 DW头时,为地址字节1;4 DW头时,为地址字节5。
7:6Reserved保留位,读取为0。
5:0Address[7:2]Address[39:32]关键!3 DW头时,为地址字节0的 bit7-2;4 DW头时,为地址字节4。
PEX_ERR_CAP_R331:0GH33 DW头时,含义由错误方向决定;4 DW头时,存储地址低32位 (Address[31:0])。

2.3 出站事务的错误信息捕获

当错误来源于内部发起的出站事务时(GSID != 0x02),PEX_ERR_CAP_R3的用途就变了。此时,它被定义为OD2字段,意为“内部平台事务信息”。手册中注明此字段“保留用于工厂调试”。在实际开发中,这个字段通常包含芯片内部总线(如CoreNet或AXI)的事务ID、属性等深度调试信息,对普通驱动开发者可能意义不大,但在芯片原厂进行硅后验证或分析复杂交互问题时至关重要。

2.4 错误捕获的实操流程与心得

  1. 错误检测:通常,你会通过中断或轮询PEX_ERR_DETECT等错误检测寄存器,发现错误发生。
  2. 现场保存:一旦检测到错误,应立即读取PEX_ERR_CAP_STATR0R1R2R3这一系列寄存器。R0通常包含错误类型和严重程度,R1可能包含请求者ID等信息。
  3. 判断来源:检查PEX_ERR_CAP_STAT[GSID],确定是内部还是外部错误。
  4. 解析事务头:根据R0中的FMTTYPE字段,判断错误事务的类型(如Memory Read/Write, Configuration, Message等)。
  5. 重组地址:如果是内存请求,根据FMT判断是3 DW还是4 DW头,然后从R2R3中提取并重组出完整地址。
  6. 清除状态:分析完毕后,向PEX_ERR_CAP_STAT[ECV]位写入0,解锁捕获逻辑,以便记录下一次错误。

实操心得:错误捕获的“一次性”务必理解“捕获-锁定-清除”这个循环。在一次错误被捕获后,如果你没有清除ECV位,那么后续发生的任何错误都不会更新这些捕获寄存器。这可能导致你错过真正的、最新的错误现场,而一直在分析一个“陈旧”的错误。在调试脚本或驱动中,好的实践是在读取错误信息后,立即清除ECV位(除非你有意保留现场进行多次分析)。

3. PCIe配置空间访问机制详解

配置空间是PCIe设备的灵魂,所有设备的发现、枚举和资源分配都依赖于它。MPC8641D的PCIe控制器支持两种访问配置空间的方法,适用于不同的场景和角色(RC或EP)。

3.1 配置访问寄存器机制(PEX_CONFIG_ADDR/DATA)

这是最经典、最直接的访问方式,模仿了x86架构上的PCI配置空间访问机制(通过0xCF8/0xCFC IO端口)。

1. 访问流程:

  • 设置地址:软件将目标配置空间的地址编码写入PEX_CONFIG_ADDR寄存器。编码格式通常为:[总线号 (8位) | 设备号 (5位) | 功能号 (3位) | 寄存器号 (6位) | 00b]
  • 触发读写:随后,对PEX_CONFIG_DATA寄存器进行读或写操作。这个读写操作会被控制器翻译成一次PCIe配置读写事务(Type 0 或 Type 1),发往链路。
  • 字节序处理:这里有一个关键点,MPC8641D作为Power架构处理器,默认采用大端字节序。而PCIe配置空间事务要求数据以小端字节序传输。因此,控制器内部需要完成字节序的转换。软件在写入PEX_CONFIG_DATA或从其读取数据时,需要以小端格式来理解数据。例如,你希望向某个设备的配置空间偏移0x00处写入0x12345678(Vendor ID/Device ID),那么在写入PEX_CONFIG_DATA时,实际写入的值应该是0x78563412

2. 事务类型判定逻辑:控制器根据PEX_CONFIG_ADDR中的总线号、设备号与自身配置空间(Type 1头)中的总线号进行比较,决定生成何种事务:

  • 内部配置访问:如果目标总线号、设备号与控制器自身的总线号、设备号匹配,且功能号为0,则访问的是控制器自身的配置寄存器。这是一个内部操作,不产生外部TLP。
  • Type 0 配置事务:如果目标总线号等于控制器的次级总线号(Secondary Bus Number),且设备号为0,则生成一个Type 0事务,发往直接连接的下游设备。
  • Type 1 配置事务:如果目标总线号不等于控制器自身总线号,也不等于次级总线号,但小于等于下属总线号(Subordinate Bus Number),则生成一个Type 1事务。下游的交换机会根据此事务继续转发,直到到达目标总线。
  • 无效访问:如果以上条件都不满足,读操作返回全1(0xFFFFFFFF),写操作被忽略。

重要提示:链路训练状态检查手册特别强调,在尝试发起外部配置事务之前,必须确保PCIe链路已经成功训练(Link Training)。软件可以通过轮询链路训练与状态状态机状态寄存器(PEX_LTSSM_STAT)来确认链路是否处于L0状态(正常工作状态)。在链路未就绪时发起配置访问,可能导致事务超时或系统挂起。

3.2 出站ATMU窗口配置机制(仅RC模式)

ATMU(Address Translation and Mapping Unit)通常用于将处理器的内部地址空间映射到PCIe总线地址空间,以进行大规模的数据传输。然而,它也可以被巧妙地用来访问配置空间,这种方式在某些场景下效率更高。

1. 工作原理:软件可以配置一个出站ATMU窗口(通过PEXOWAR寄存器),将其ReadTTypeWriteTType字段设置为0x2,表示该窗口用于生成配置事务。 当处理器访问这个ATMU窗口映射的本地地址时,控制器会将本地地址翻译成PCIe配置空间的地址格式:

  • PCIe地址[27:20]-> 总线号
  • PCIe地址[19:15]-> 设备号
  • PCIe地址[14:12]-> 功能号
  • PCIe地址[11:8]-> 扩展寄存器号(用于访问超过256字节的PCIe扩展配置空间)
  • PCIe地址[7:2]-> 寄存器号

然后,控制器会根据翻译出的总线号,按照与PEX_CONFIG_ADDR类似的规则,决定生成Type 0还是Type 1配置事务。

2. 限制与注意事项:

  • 访问粒度:通过ATMU窗口进行的配置访问必须是4字节或更小,并且不能跨越4字节边界。这是因为配置空间寄存器通常以DWord对齐。
  • 不支持内部访问绝对不能使用ATMU窗口来访问控制器自身的内部配置寄存器(即上文提到的“内部配置访问”)。ATMU机制仅用于访问外部设备的配置空间。尝试访问自身会导致未定义行为。
  • EP模式不支持:当控制器配置为端点(EP)模式时,ATMU窗口无法用于发起配置事务。任何尝试都会导致错误响应。

表:两种配置访问机制对比

特性配置访问寄存器 (PEX_CONFIG_ADDR/DATA)出站ATMU窗口
访问对象内部寄存器 & 外部设备配置空间仅外部设备配置空间
操作方式两步操作(先写地址,再读写数据)一步操作(直接读写映射的内存地址)
适用模式RC模式 & EP模式(仅内部访问)仅RC模式
字节序软件需处理小端格式地址翻译自动处理,数据访问遵循处理器字节序(需注意)
灵活性每次访问需设置地址,适合单次、随机访问窗口固定,适合批量、顺序访问特定设备配置空间
主要用途设备枚举、驱动初始化、零星配置读写特定场景下的高效批量配置(较少使用)

3.3 EP模式下的配置空间访问

当MPC8641D作为端点设备时,其配置空间的访问行为与RC模式有根本不同:

  • 被动响应:EP只能响应来自根复合体的配置请求,而不能主动发起配置请求。
  • 寄存器访问限制:远程主机可以访问其大部分PCIe配置空间,但无法访问偏移0x400–0x6FF范围内的PCIe控制器内部CSR寄存器。尝试访问这些区域将读回0。
  • 配置寄存器功能变化:在EP模式下,PEX_CONFIG_ADDR/DATA寄存器的行为发生变化。对它们的任何访问,无论其中编程的总线号、设备号是什么,都会直接映射到访问EP自身的内部配置寄存器。这意味着在EP模式下,你不能用这些寄存器去探测其他设备。
  • ATMU失效:EP模式下,出站ATMU窗口若被配置为发起配置事务,所有命中此窗口的请求都会被静默忽略或返回错误。

4. PCI兼容配置空间寄存器精讲

PCIe兼容配置空间的前256字节是软件与设备交互的基础。MPC8641D的配置空间布局遵循标准,但有其特定的字段含义。

4.1 公共头寄存器详解

前16字节是所有PCIe设备共有的,包含了设备的核心标识和控制状态。

1. 命令寄存器 (Command Register - Offset 0x04)这是设备的“总开关”,控制着其基本功能。

  • Bit 2 - Bus Master Enable:这是最关键的位之一。
    • EP模式:置1,允许设备作为主设备发起内存或IO读写请求(例如DMA)。清零此位会同时禁用MSI中断,因为MSI本质上是内存写操作。
    • RC模式:置1,允许控制器将来自下游设备的内存请求转发到上游(系统内存)。清零此位会导致所有入站内存请求被当作“不支持的请求”处理。
  • Bit 1 - Memory Space Enable
    • EP模式:控制设备是否响应目标内存读/写请求。清零则拒绝所有内存访问。
    • RC模式:此位被忽略,不影响出站内存事务。
  • Bit 0 - I/O Space Enable
    • EP模式:MPC8641D的EP模式不支持IO事务,故此位是无关项。
    • RC模式:此位被忽略,不影响出站IO事务。
  • Bit 6 - Parity Error Response:控制是否响应奇偶校验错误。注意,错误的实际报告还受更高级的PCIe错误使能寄存器控制。

2. 状态寄存器 (Status Register - Offset 0x06)用于记录各种错误和状态事件。许多位是“写1清除”(w1c)的,即通过向该位写1来清除它。

  • Bit 15 - Detected Parity Error:当设备收到一个“中毒”(Poisoned)的TLP时置位,无论命令寄存器的Bit 6是否使能。
  • Bit 14 - Signaled System Error:当设备发送了ERR_FATAL或ERR_NONFATAL消息,且命令寄存器的SERR位使能时置位。
  • Bit 13 - Received Master-Abort:当请求者收到一个“不支持的请求”完成状态时置位。
  • Bit 4 - Capabilities List:此位必须为1,表示该设备实现了PCIe能力结构链表(链表头指针在0x34)。

4.2 类型0头寄存器(端点模式)

当Header Type寄存器指示为0x00时,设备是端点。其特有寄存器主要围绕资源申请(BAR)。

1. 基地址寄存器 (BARs - Offset 0x10-0x27)BAR用于向系统声明设备需要的内存或IO地址空间。

  • BAR0 (PEXCSRBAR - Offset 0x10):这是一个特殊的、固定的1MB窗口,用于入站配置访问。系统软件通过配置此BAR的基地址,使得外部主机(在RC模式下)或同级设备能够访问本设备的配置空间。此BAR不能通过ATMU寄存器修改
  • BAR1 (Offset 0x14):32位内存空间BAR。其可写地址位(高20位)的大小由入站窗口属性寄存器PEXIWAR1中的窗口大小字段决定。最低支持4KB对齐。
  • BAR2 & BAR3, BAR4 & BAR5:这两对寄存器共同定义两个64位内存空间BAR。BAR2/BAR4存放低32位地址,BAR3/BAR5存放高32位地址。它们的属性分别由PEXIWAR2PEXIWAR3控制。

BAR编程要点

  1. 软件通过向BAR写入全1,再读回,可以探测该BAR所需空间的大小和对齐方式。设备会返回一个掩码,其中低位(不可写位)为0,高位(可写位)为1。
  2. BAR的Bit 0是只读的Memory Space Indicator(对于内存BAR为0)。
  3. BAR的Bit 2-1表示类型:00为32位空间,10为64位空间。
  4. BAR的Bit 3表示空间是否可预取(Prefetchable)。

4.3 类型1头寄存器(根复合体模式)

当Header Type寄存器指示为0x01时,设备作为根复合体或桥。其特有寄存器主要管理下游总线层次。

1. 总线号寄存器 (Primary/Secondary/Subordinate Bus Number - Offset 0x18-0x1A)这三个寄存器定义了该桥所连接的总线区间,是PCI/PCIe总线枚举的核心。

  • 主总线号 (Primary Bus Number):上游总线号。对于根复合体,此值通常为0。
  • 次级总线号 (Secondary Bus Number):直接连接的下游总线号。对于根复合体,枚举软件通常将其设置为1。
  • 下属总线号 (Subordinate Bus Number):下游所有总线中编号最大的一个。在枚举完成前,此值是一个动态变化的上限。

枚举软件(如BIOS或操作系统内核)通过遍历和设置这些寄存器,构建出整个系统的总线拓扑图。当配置请求的目标总线号落在[Secondary Bus Number, Subordinate Bus Number]这个闭区间内时,桥就会将其转发到下游。

5. 常见问题与调试技巧实录

在实际开发和调试中,会遇到各种棘手问题。以下是一些基于经验的排查思路。

5.1 错误捕获寄存器读不到有效数据

  • 症状:检测到错误标志,但读取PEX_ERR_CAP_Rx寄存器全是0或旧数据。
  • 排查
    1. 检查ECV位:首先读取PEX_ERR_CAP_STAT[ECV]。如果为0,说明没有新的错误被捕获,或者上次捕获后未清除。确保在错误中断服务例程中先读ECV确认。
    2. 确认错误源:检查PEX_ERR_CAP_STAT[GSID]。如果错误来源与你预期的不符(例如,你以为是外部设备错误,但GSID显示是内部错误),那么问题可能出在软件配置或内部总线访问上。
    3. 检查错误使能:确认PEX_ERR_DISABLE等寄存器没有屏蔽掉你关心的错误类型。有些错误默认是不触发捕获的。
    4. 时序问题:在极少数情况下,从检测到错误到捕获寄存器稳定,可能存在几个时钟周期的延迟。在读取捕获寄存器前,可以插入一个微小的延迟或屏障指令。

5.2 配置空间访问失败或返回全F

  • 症状:通过PEX_CONFIG_ADDR/DATA访问外部设备时,读回0xFFFFFFFF
  • 排查
    1. 链路状态首要检查PEX_LTSSM_STAT寄存器,确认链路是否处于L0状态。未训练成功的链路无法通信。
    2. 总线号配置:在RC模式下,确认你访问的总线号是否在[Secondary Bus Number, Subordinate Bus Number]范围内。如果访问总线0(RC自身),要确保设备号和功能号正确。
    3. 设备存在性:确认目标设备物理上存在且已上电。可以通过反复读取其Vendor ID(应为非0xFFFF)来探测。
    4. 字节序问题:在PowerPC等大端架构上,忘记数据的小端格式是最常见的坑。当你读取Device ID和Vendor ID时,如果得到的是0x70101957这样的值,实际上正确的值应该是0x19577010(小端格式)。你需要对读取的32位数据进行字节交换。
    5. 访问宽度:确保配置访问是32位宽的。8位或16位访问可能不被支持或行为异常。

5.3 设备枚举时BAR分配冲突或无法访问

  • 症状:系统枚举时卡住,或设备驱动无法映射BAR指定的内存区域。
  • 排查
    1. BAR大小探测:在分配地址前,系统会进行BAR大小探测。确保你的驱动或固件正确执行了“写全1-读回”的操作。MPC8641D的BAR大小由对应的PEXIWARn寄存器决定,如果配置不当,返回的掩码可能是错误的。
    2. 64位BAR对齐:对于64位BAR(BAR2+BAR3),其分配的地址必须按64位边界对齐(通常是8字节)。系统软件如果没有正确处理,会导致分配失败。
    3. PREF位:如果BAR标记为可预取(Prefetchable),系统可能会将其分配到一个支持预取特性的内存区域(如WC类型)。确保你的内存控制器支持对该区域的访问。
    4. ATMU与BAR的冲突:在RC模式下,入站ATMU窗口用于将PCIe地址映射到本地内存。如果ATMU窗口的配置与设备BAR申请的空间在PCIe地址域上有重叠,会导致访问冲突。需要仔细规划地址映射。

5.4 EP模式无法与主机通信

  • 症状:MPC8641D配置为EP,但主机无法发现或访问它。
  • 排查
    1. PEXCSRBAR配置:这是EP能被主机访问的唯一入口。必须确保在EP初始化时,正确设置了PEXCSRBAR的基地址(通常由EP固件根据主机分配来设置),并且该地址映射到了主机可以访问的PCIe内存空间。
    2. Bus Master Enable:在EP模式下,如果需要进行DMA操作(向主机写数据或发起MSI中断),必须将命令寄存器的Bit 2置1。很多通信失败是因为这个位没开。
    3. 链路训练方向:确认硬件设计上,EP的PCIe链路是正确连接到上游的RC端口的。有些SoC的PCIe控制器端口可能只支持RC模式。
    4. 内部CSR访问:在EP模式下,主机无法访问偏移0x400–0x6FF的内部CSR。如果主机驱动尝试访问这些区域进行配置,会失败。EP的固件需要通过其他方式(如共享内存)与主机交换必要的控制信息。

调试PCIe问题,逻辑分析仪或PCIe协议分析仪是终极武器。它们可以让你看到链路上实际传输的TLP包,直接对比协议规范,判断是控制器配置问题、软件驱动问题,还是物理层信号完整性问题。在没有硬件工具的情况下,系统地、逐位地核对寄存器配置,结合手册中的状态机描述进行逻辑推理,是解决问题的基本方法。

http://www.jsqmd.com/news/1071478/

相关文章:

  • 教学辅助问答系统:基于SpringBoot+Vue的知识引擎设计
  • 长上下文大模型在金融招股书理解中的实战突破
  • Llama4应用构建:基于DLAI范式的可监控生产流水线
  • 从实战视角解析学生方程式大赛:线控刹车标定与数据采集系统应用
  • MPC8572E DMA控制器工作模式详解:从基础到高级的性能优化实践
  • CTF实战:从流量分析到AES解密的Misc综合解题思路
  • 用 Nacos 3.2 构建企业级 Skills Registry
  • 安卓APP逆向实战:从静态分析到动态验证的完整流程解析
  • 科学计算代码现代化重构:从Python 2祖传算法到可维护工程实践
  • MATLAB eigshow 交互式学习:特征值与奇异值分解的几何可视化
  • IoT数据分析实战:从传感器数据到智能决策的完整指南
  • GUIDE跨控件数据访问:从原理到实践的MATLAB GUI开发指南
  • 20行Rust实现AI代码Agent骨架:基于A3S模型的轻量执行环
  • 挖矿木马攻击路径转向:Redis、Docker等非Web服务漏洞防御实战
  • Hermes Agent Linux安装指南:轻量级AI智能体运行时部署实战
  • SVG矢量图形原理、应用与前端开发实战指南
  • OpenClaw浏览器自动化实现微信公众号全自动运营
  • 大模型技术解析:从算法原理到微调部署实战指南
  • DeepSeek V4 实质是工程成熟度代号:R1模型+协议网关的本地AI开发落地实践
  • Linux内核堆溢出漏洞CVE-2022-0995深度剖析与复现
  • Metasploit实战:SSH弱口令爆破原理、自动化检测与防御策略
  • ASTER框架:基于VAE和LLM的时间序列异常检测新方法
  • MySQL多表查询本质:关系代数、执行顺序与NULL陷阱
  • Codex案例库:用Skills范式解决OpenAI API生产落地难题
  • MATLAB对话框管理:从基础使用到高级模式与实战指南
  • ATM控制器地址压缩与ABR流控机制深度解析
  • 基于RFID与Arduino的智能淋浴计时系统:从硬件搭建到云端可视化
  • MATLAB R2019a核心特性解析:性能优化、工作流与深度学习应用
  • 南瓜蟾蜍的生存策略:从生物力学缺陷看系统设计的权衡艺术
  • Plot Subfunctions:数据可视化工程化实践,提升MATLAB/Python绘图效率