1. 背景

随着电源管理机制越来越完善,处理器和其他系统组件的功耗越来越低,而像 PCIe 组件这样的外围设备在 PC 系统功耗中占据的比重越来越大。虽然早期的 PCIe 允许一些软件和硬件电源管理,但是并没有把电源管理策略与系统的协调放在一个高优先级,所以软件的控制也很有限。

缺乏系统与电源管理策略之间的协调会导致一个很明显的问题:某些时候,系统可能已经进入睡眠状态 (sleep state)了,而 PCIe 设备可能还处于工作状态。这些 PCIe 设备可能会产生中断或者 DMA 数据传输请求,虽然这些请求的优先级可能并不高,但也会导致系统从睡眠状态唤醒,这样就破坏了节能的目标。

还有一种情况,PCIe 设备在向系统提交请求后,并不一定需要即时响应,只要在某个时间范围内得到响应即可。如果系统不知道 PCIe 设备能够容忍的响应时间,那就会默认立即响应,这样会导致系统进入低功耗模式的时间比较短或者频繁的在低功耗与非低功耗模式之间来回切换。如果系统能知道 PCIe 设备能够容忍的响应时间,就可以合理的安排对设备请求的响应,在允许的时间范围内,可以把请求积攒起来,在某一个时刻统一进行响应。这样,系统就能有比较集中的时间处于低功耗模式。

2. OBFF(Optimized Buffer Flush Fill)

OBFF 给 PCIe 设备提供了一种获取系统电源状态的机制。利用 OBFF,PCIe 设备就可以选择与系统进行数据交互的最优时间。

2.1 问题

对于具有总线主控功能的设备(bus-master capable devices)来说,如果不知道系统当前的电源状态,那么它们可能会在某些不合适的时间提交请求。

Figure 16-31 展示一个比较差的电源管理系统场景:系统中有 3 个 PCIe 终端设备(Endpoint),而且每个设备提交申请的时间比较散乱。这种场景下,系统能够进入 Idle 状态的时间就很短。

Figure 16-32 展示一个改善后的电源管理系统场景:该场景下,相同类型的请求会被攒到一起进行统一响应。这样,系统就可以有大块的时间进入 Idle 状态。很明显,这种模式能够达到不错的电源管理效果,而且实现起来并不复杂。只要 PCIe 设备能够查询当前系统的电源状态,并且知道在当前状态下该做些什么就可以。

2.2 解决方案

通过 OBFF,系统告知 PCIe 设备在哪些时间进行数据传输。OBFF 只是提供一个建议时间,PCIe 设备可以忽略 OBFF 信息,在它想要发请求的任意时刻发送请求(这样就导致功耗比较大,所以最好还是按照 OBFF 的建议来做)。有两种方式完成 OBFF 信息的交互:(1)通过向 Endpoint 发送消息(message);(2)控制 WAKE# 引脚。在两种方式都支持的情况下,优先选择 WAKE# 引脚的方式。只有在 WAKE# 引脚不能用的时候,再去选择发送消息(message)的方式。

Figure 16-33 展示了 OBFF 的信息传输过程。在本例中,由于两个 Switch 之间不支持 WAKE# 引脚连接,所以同时用到了消息(message)和 WAKE# 引脚两种信息传输方式。上面的 Switch 收到来自 Root Complex WAKE# 引脚的信息后,会将其转化成消息(message)发送给下面的 Switch。

2.2.1 使用 WAKE# 引脚

以前,WAKE# 只有一个功能:PCIe 组件使用该引脚通知系统恢复该 PCIe 组件的主电源供电(低功耗情况下,系统可能会移除 PCIe 组件的主电源)。

引入 OBFF 机制后,该引脚被用来向 PCIe 组件传递当前系统的电源状态。这种方式的协议很简单,只需要按照一定规律改变 WAKE# 引脚的电平,就可以表示出三种状态:

  • CPU Active:系统处于活跃状态,可以进行任意类型的事务交互。
  • OBFF:可以进行系统内存访问,可以读写系统内存;除此之外其他类型的事务交互都需要等到更高等级的电源状态。
  • Idle:等待进入更高等级的电源状态之后,启动。

当处于 CPU Active 或者 OBFF 状态时,建议在 10 us 之内不要进入 Idle 状态。这样可以给 PCIe 组件足够的时间去处理之前 Idle 状态下积攒的未被处理的事务。但是,由于 10 us 只是一个建议,所以 PCIe Endpoint 也不要盲目的认为系统会在 CPU Active 或者 OBFF 状态保持足够的时间。

系统可以在真正进入 Idle 状态之前,先通过 WAKE# 提前发出切换到 Idle 状态的信号,这样收到信号的 PCIe 组件就知道该结束事务传输了。

这种提前通知的机制,可以避免 PCIe 组件在系统刚进入 Idle 状态时就发起事务传输,导致系统从 Idle 状态唤醒。

按照协议的建议,系统的这种提前通知与真正进入 Idle 状态的通知之间的间隔时间要尽量的短一些。

有趣的是,WAKE# 引脚仍然能支持它最初的功能:PCIe 组件使用该引脚通知系统恢复该 PCIe 组件的主电源供电。这种情况下,当某个 PCIe 组件尝试通知系统恢复它的主电源供电时,可能会被其他监听 WAKE# 引脚的 PCIe 组件误认为是 OBFF 信息。为了解决这个问题,协议规定:如果 PCIe 组件无法清晰的理解 WAKE# 引脚的变化所指示的信息,那么该组件就可以认为当前系统处于 CPU Active 状态。

2.2.2 使用 OBFF 消息(OBFF Message)

OBFF 消息(OBFF Message)只能从 Root Complex 发送到其他 PCIe 组件。消息格式如下图:

Routing Type = 0b100,表示 Point-to-Point 类型。
OBFF Code 有 3 中有效值,其它都是 reserved code:

  • 0b1111:CPU Active
  • 0b0001:OBFF
  • 0b000b:Idle
  • 其他:reserved code

如果收到的 OBFF 消息中,OBFF Code的值是 reserved code,那么 PCIe 组件可以认为当前系统处于 CPU Active 状态。

如果 PCIe 组件不支持 OBFF 或者还没有使能 OBFF,那么当它收到 OBFF 消息时,需要按照 Unsupported Request类型来处理(返回的 Completion 中,将 UR 状态位设置为 1)。

PCIe 配置空间中的 Device Capability 2 寄存器指示了 PCIe 设备是否支持 OBFF,如下图所示:

PCIe 配置空间中的 Device Capability 2 寄存器指示了 PCIe 设备是否使能 OBFF,如下图所示:

本文中的图片来自MindShare, Inc 经典书籍《PCI Express Technology》。

更多 PCIe 知识,点击该链接。

OBFF (Optimized Buffer Flush and Fill)相关推荐

  1. PCIE总线理解笔记

    基本介绍 网上有和多好的网站可以看比如下面这个,我写笔记是从嵌入式底层开始的学习记录不完整和成体系. 一篇很好的文章可以看看 PCI的EP和RC分别对应从模式和主模式,普通的PCI RC主模式可以用于 ...

  2. PCIe中的Message

    PCIe中的Message主要是为了替代PCI中采用边带信号,这些边带信号的主要功能是中断,错误报告和电源管理等.所有的Message请求采用的都是4DW的TLP Header,但是并不是所有的空间都 ...

  3. node MySQL buffer_node.js中buffer方法使用说明

    熟悉JavaScript的童鞋应该对Node.js都不陌生,没错Node.js是一个基于Chrome JavaScript运行时建立的平台,用于方便地搭建响应速度快.易于扩展的网络应用.Node.js ...

  4. 14.4.3.5 Configuring InnoDB Buffer Pool Flushing 配置InnoDB Buffer Pool 刷新:

    14.4.3.5 Configuring InnoDB Buffer Pool Flushing 配置InnoDB Buffer Pool 刷新:InnoDB执行某些任务在后台, 包括flush 脏数 ...

  5. java io flush_《文件传输基础——Java IO流》,对其中flush方法的思考

    在学习了<文件传输基础--Java IO流> 课程后,发现自己对flush()方法的调用有很多疑惑.在查询资料和自己看源码以及动手试验之后发现有以下几个特点.如有误也请大家指正出来,一切为 ...

  6. nodeJS之二进制buffer对象

    前面的话 在ES6引入TypedArray之前,JavaScript语言没有读取或操作二进制数据流的机制.Buffer类被引入作为Nodejs的API的一部分,使其可以在TCP流和文件系统操作等场景中 ...

  7. Node的文件系统及Buffer概述

    目录 node.js开发网站 Node的文件系统 文件与目录的基本操作 写入文件操作 读文件操作 Node事件处理机制 Node的全局对象 Buffer node.js开发网站 node.js本身就是 ...

  8. Node.js知识点整理之----Buffer类

    Buffer类,是用来创建一个专门存放二进制数据的缓存区. Buffer类,是一个可以在任何模块中使用的全局类. Buffer类使用 new 关键字创建该类的实例对象. 三种形式创建实例对象: new ...

  9. Node.js Buffer(缓冲区)

    一.Node.js Buffer(缓冲区) JavaScript 语言自身只有字符串数据类型,没有二进制数据类型. 但在处理像TCP流或文件流时,必须使用到二进制数据.因此在 Node.js中,定义了 ...

最新文章

  1. Android中使用WebChromeClient显示Openlayers加载本地GeoJson文件显示地图(跨域问题解决)
  2. 面试题:如何实现一个深拷贝
  3. sublime代码片段
  4. python爬携程酒店评论_python爬虫爬取携程网的酒店评论数据时,有个请求参数不知道是怎么生成的?...
  5. Linux_PAM_用户之间的信息传递
  6. mybatis一个方法执行多条sql_精尽MyBatis源码分析——SQL执行过程之Executor!
  7. lua学习笔记(三)
  8. jdbc存储过程mysql_使用JDBC操作存储过程
  9. 参考文献中英文人名_参考文献中英文人名的缩写规则
  10. java比python快多少倍_java为什么比python快
  11. 用visio制作机柜服务器,visio 绘制机柜接线图 实例教程
  12. 利用git进行word文档的版本管理
  13. day12 函数高级
  14. 基于图书管理系统的需求分析之可行性分析安全需求分析系统需求分析
  15. 《黑客秘笈——渗透测试实用指南(第2版)》—第2章2.3节外部或内部主动式信息搜集...
  16. windows下choco 安装helm
  17. UE4第三人称多人联机游戏开发02
  18. Vue.js中的自定义指令directives
  19. linux系统的midi制作软件,MIDI音乐制作软件(MidiEditor)
  20. .net的反射技术(2)深究及 性能比较

热门文章

  1. 如何设计一个公司级别的消息通知系统?
  2. python 三维装箱可视化图代码
  3. HTML表格行上下移动,jQuery表格行上下移动(带过渡效果)
  4. Flume 安装使用(自己总结) 吐槽CSDN 对Markdown 的mermaid 语法支持不完整
  5. grails链接mysql_grails 连接Mysql
  6. Computer:项目管理之软件开发模式(瀑布式开发、快速原型开发、迭代式开发、螺旋式开发、敏捷式开发、DevOps开发)的简介、对比之详细攻略
  7. kafka性能参数和压力测试
  8. 微创医疗机器人行业调研报告 - 市场现状分析与发展前景预测
  9. Linux快速入门(摘录笔记,大量文字,b站狂神)
  10. MPEG-7描述子(4)——颜色结构描述子CSD