linux opp 模块

目录

  • 一、Linux OPP 介绍
  • 二、关键数据结构
    • dev_pm_opp
    • opp_table
  • 三、OPP 的 dts 结构
    • 3.1 operating-points
    • 3.2 operating-points-v2
      • opp table dts 属性
      • opp dts 属性
  • 四、关键接口
    • 4.1 创建/删除 opp_table
    • 4.2 获取 opp_table
    • 4.3 获取 opp 相关接口

一、Linux OPP 介绍

在Linux中,OPP(Operating Performance Points)结构是一种用于描述设备性能状态的机制,主要用于电源管理和性能调节,特别是在处理器、GPU和其他硬件设备中。OPP结构允许系统根据负载需求动态调整设备的性能和功耗,以实现更高的能效。

OPP的主要组成部分:

1. 频率:设备在不同性能状态下的工作频率。
2. 电压:相应的工作电压,通常与频率成正比。
3. 功耗:在特定频率和电压下设备的功耗。

OPP的使用场景:

1. 动态频率调节:在设备负载增加时提升频率,以提高性能;在负载降低时降低频率,以节省电能。
2. 热管理:根据设备的温度和功耗情况调整性能状态,以避免过热。
3. 负载平衡:在多核处理器中,可以根据任务需求将负载动态分配给不同核心,并调整其OPP以优化性能和能耗。

实现方式:

1. OPP通常通过设备树(Device Tree)描述,包含每个性能点的频率、电压和功耗信息。
2. Linux内核中的cpufreq、cpupower、dvfs、thermal 等子系统可以管理这些OPP,以实现对设备的频率和电压的动态调整。

通过OPP机制,Linux能够在提供所需性能的同时,有效管理能耗和热量,从而延长设备的使用寿命和电池续航时间。

二、关键数据结构

dev_pm_opp

dev_pm_opp 在 OPP 中表示单个性能点。

struct dev_pm_opp {struct list_head node;struct kref kref;    // 用于引用计数,确保相关变量在使用期间不被释放,防止内存泄漏。bool available;    // enable/disablebool dynamic;      // 标记动态性能点bool turbo;        // 标记节点为高性能模式bool suspend;      // suspend时是否有效unsigned int pstate;  // 表示该节点的性能状态unsigned long rate;   // 该opp点的频率unsigned int level;   // 该opp项的级别struct dev_pm_opp_supply *supplies;   // power电压信息unsigned long clock_latency_ns;    // 切换到该opp项的时间延时struct dev_pm_opp **required_opps;    //  指针数组,指向该opp项依赖的其它opp项struct opp_table *opp_table;  // 包含该opp项的opp表struct device_node *np;#ifdef CONFIG_DEBUG_FSstruct dentry *dentry;
#endif
};

opp_table

opp_table 负责管理一个设备的 OPP 表,一个 opp 表由多个dev_pm_opp表示的 opp 性能节点组成。

struct opp_table {struct list_head node;struct blocking_notifier_head head; //注册管理OPP状态变化时的通知回调struct list_head dev_list;  // 包含该opp table的设备列表struct list_head opp_list;  // 包含所有dev_pm_opp的列表struct kref kref;struct kref list_kref;  // 引用计数struct mutex lock;struct device_node *np;unsigned long clock_latency_ns_max;  // 表示设备在切换opp时最大的延迟/* For backward compatibility with v1 bindings */unsigned int voltage_tolerance_v1;  // 为向后兼容v1保留的电压容忍度(波动范围)bool parsed_static_opps;    // 指示opp表节点是否已解析enum opp_table_access shared_opp;    // 是否共享struct dev_pm_opp *suspend_opp;    // 指向suspend情况下使用的oppstruct mutex genpd_virt_dev_lock;    // 保护虚拟设备的访问struct device **genpd_virt_devs;     // 与opp表关联的虚拟设备数组struct opp_table **required_opp_tables;  // 依赖的其它opp表unsigned int required_opp_count;unsigned int *supported_hw;   // 支持的硬件配置(dts中配置支持的硬件表示符)unsigned int supported_hw_count;const char *prop_name;struct clk *clk;    // 与opp相关的时钟struct regulator **regulators;  // 与opp表相关的电压调节器int regulator_count;bool genpd_performance_state;bool is_genpd;int (*set_opp)(struct dev_pm_set_opp_data *data);  // 指向调整opp的函数指针struct dev_pm_set_opp_data *set_opp_data;  // 设置opp所需要的数据#ifdef CONFIG_DEBUG_FSstruct dentry *dentry;char dentry_name[NAME_MAX];
#endif
};

三、OPP 的 dts 结构

参考Documentation\devicetree\bindings\opp\opp.txt。

在设备树中,OPP(Operating Performance Points)的结构主要用于描述设备的性能状态,包括频率、电压等信息。OPP的DTS结构通常包含多个OPP节点,每个节点对应一个性能点,通常在设备的设备树节点下定义。

3.1 operating-points

OPP dts 的 v1 版本结构,仅支持电压-频率对,节点名为 operating-points,节点包含了频率和电压的组合。

cpu@0 {compatible = "arm,cortex-a9";reg = <0>;next-level-cache = <&L2>;operating-points = </* kHz    uV */792000  1100000396000  950000198000  850000>;
};

3.2 operating-points-v2

OPP dts 的 v2 版本结构,支持更复杂的电压-频率组合。

opp table dts 属性

opp table的dts中可能包含以下属性节点:

  • compatible:必须是 “operating-points-v2”;
  • opp-shared:可选属性,当 opp table 的 dts 包含该属性时,表示该 opp table 会影响所有使用该 opp table 的设备,任意的 opp 切换会作用到所有的设备上;
  • opp 节点;

opp dts 属性

每个opp节点的dts,可能包含以下属性:

  • opp-microvolt:电压,uv。size 为 1 或者 3 的数组,size 为 1 时表示,size 为 3 时表示;
  • opp-microvolt-:特殊命名的opp-microvolt,可以为一个 opp 提供多个不同属性的电压值,每个电压值可能对应了不同的运行模式,例如 opp-microvolt-slow、opp-microvolt-fast;
  • opp-microamp:该 opp 下,设备最大的电流消耗,只有定义 opp-microvolt 前提下,opp-microamp 才是有意义的;
  • opp-microamp-:特殊命名的 opp-microamp;
  • opp-level:当前节点的性能等级,方便低功耗和高性能状态时调整设备的频率和电压;
  • clock-latency-ns:从任何 opp 切换到该 opp 所需要的耗时;
  • turbo-mode:指示是否支持短时间内超频;
  • opp-suspend:opp 的 dts 包含该属性时,表示当设备 suspend 时,切到该 opp。如果多个 opp 都包含该属性,在 suspend 时会切到最高频率的 opp;
  • opp-supported-hw:可选属性,用于指示哪些硬件版本可以支持该 opp,具体的硬件版本号是用户自己定义的;
  • required-opps:指示当前 opp 运行时所依赖的其它 opp;

举例

	cpu_opp_table: opp_table0 {compatible = "operating-points-v2";opp-shared;opp-1000000000 {opp-hz = /bits/ 64 <1000000000>;opp-microvolt = <975000 970000 985000>;opp-microamp = <70000>;opp-microvolt-slow = <915000 900000 925000>;opp-microvolt-fast = <975000 970000 985000>;opp-microamp-slow =  <70000>;opp-microamp-fast =  <71000>;clock-latency-ns = <300000>;opp-supported-hw = <0xF 0xFFFFFFFF 0xFFFFFFFF>;opp-suspend;};opp-1100000000 {opp-hz = /bits/ 64 <1100000000>;opp-microvolt = <1000000 980000 1010000>;opp-microamp = <80000>;clock-latency-ns = <310000>;opp-supported-hw = <0x20 0xff0000ff 0x0000f4f0>;opp-microvolt-slow = <915000 900000 925000>, /* Supply vcc0 */<925000 910000 935000>; /* Supply vcc1 */opp-microvolt-fast = <975000 970000 985000>, /* Supply vcc0 */<965000 960000 975000>; /* Supply vcc1 */opp-microamp =  <70000>; /* Will be used for both slow/fast */};opp-1200000000 {opp-hz = /bits/ 64 <1200000000>;opp-microvolt = <1025000>;clock-latency-ns = <290000>;turbo-mode;};};cpus {#address-cells = <1>;#size-cells = <0>;cpu@0 {compatible = "arm,cortex-a9";reg = <0>;next-level-cache = <&L2>;clocks = <&clk_controller 0>;clock-names = "cpu";cpu-supply = <&cpu_supply0>;operating-points-v2 = <&cpu0_opp_table>;};cpu@1 {compatible = "arm,cortex-a9";reg = <1>;next-level-cache = <&L2>;clocks = <&clk_controller 0>;clock-names = "cpu";cpu-supply = <&cpu_supply0>;operating-points-v2 = <&cpu0_opp_table>;};};

四、关键接口

4.1 创建/删除 opp_table

int dev_pm_opp_of_add_table(struct device *dev);
int dev_pm_opp_of_add_table_indexed(struct device *dev, int index);
void dev_pm_opp_of_remove_table(struct device *dev);

以上是部分删除和创建 opp_table 的接口。
dev_pm_opp_of_add_table 接口通过从设备树中解析 opp 信息,并注册 opp_table、添加到设备中。

int dev_pm_opp_of_add_table(struct device *dev)
{struct opp_table *opp_table;int ret;opp_table = dev_pm_opp_get_opp_table_indexed(dev, 0); // 查找或解析dts创建opp_tableif (!opp_table)return -ENOMEM;/** OPPs have two version of bindings now. Also try the old (v1)* bindings for backward compatibility with older dtbs.*/if (opp_table->np)ret = _of_add_opp_table_v2(dev, opp_table);  // 解析dts,将opp添加到opp_tableelseret = _of_add_opp_table_v1(dev, opp_table);if (ret)dev_pm_opp_put_opp_table(opp_table);return ret;
}
EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table);

注意,在 _of_add_opp_table_v2 解析 dts 添加 opp 时,会将 opp freq 从低到高的顺序排序(_opp_is_duplicate)然后再添加到 opp_list 中。方便在遍历 list 时,能最有效地找到大于或者小于给定频率的 opp

dev_pm_opp_get_opp_table_indexed 从已经创建的 opp_table list 查找并返回 opp_table,查找不到的话,则解析 dts 创建 opp_table 并返回。

struct opp_table *dev_pm_opp_get_opp_table_indexed(struct device *dev,int index)-> _opp_get_opp_table(dev, index);-> opp_table = _find_opp_table_unlocked(dev); // 遍历opp_tables和opp_table->dev_list,查找dev的opp_table。查找到的话返回-> opp_table = _managed_opp(dev, index);  // 遍历opp_tables查找opp_table(可能其它设备使用相同的opp_table,已经注册过opp_table), 找到直接返回-> opp_table = _allocate_opp_table(dev, index);  // 申请内存、解析dts创建opp_table

dev_pm_opp_of_add_table_indexeddev_pm_opp_of_add_table 接口类似,初始化指定 index 的 opp_table.

4.2 获取 opp_table

struct opp_table *dev_pm_opp_get_opp_table(struct device *dev);
struct opp_table *dev_pm_opp_get_opp_table_indexed(struct device *dev, int index);

dev_pm_opp_get_opp_table 接口会调用 _opp_get_opp_table 接口,前面已经讲过,_opp_get_opp_table 接口会从已经创建的 opp_table list 查找并返回 opp_table,查找不到的话,则解析 dts 创建 opp_table 并返回。

struct opp_table *dev_pm_opp_get_opp_table(struct device *dev)
{return _opp_get_opp_table(dev, 0);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_get_opp_table);

dev_pm_opp_get_opp_table_indexed 接口类似。

4.3 获取 opp 相关接口

// 根据freq和available精确的查找opp
struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,unsigned long freq,bool available);
// 根据level,精确度查找opp,level通过dts中的“opp-level"定义
struct dev_pm_opp *dev_pm_opp_find_level_exact(struct device *dev,unsigned int level);// 返回小于或等于freq的最高opp,并将opp的freq赋给freq
struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,unsigned long *freq);
// 根据给定volt查找opp频率上限(大于等于指定打压的最小频率)
struct dev_pm_opp *dev_pm_opp_find_freq_ceil_by_volt(struct device *dev,unsigned long u_volt);
// 根据给定的freq查找opp表中大于或等于freq的最小频率。
struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,unsigned long *freq);

例如:
在驱动程序中,根据不同条件查找确定合适的 opp,方便进一步调频等动作。

unsigned long target_freq = 1200000; // 1.2 GHz
struct dev_pm_opp *opp = dev_pm_opp_find_freq_ceil(dev, &target_freq);
if (!IS_ERR(opp)) {// 找到了合适的 OPP,可以获取其频率等信息unsigned long freq = opp->rate;// 使用频率...dev_pm_opp_put(opp); // 减少引用计数
} else {// 处理未找到 OPP 的情况
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/468445.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DataFrame

目录 一、创建DataFrame二、Sql语法三、DSL语法四、RDD与DataFrame互相转换 一、创建DataFrame 在SparkSql中SparkSession是创建DataFrame和执行Sql的入口&#xff0c;创建DataFrame有三种方式&#xff1a; 通过Spark的数据源进行创建 从一个存在的RDD进行转换 从Hive Tabl…

Redis 高并发分布式锁实战

目录 环境准备 一 . Redis 安装 二&#xff1a;Spring boot 项目准备 三&#xff1a;nginx 安装 四&#xff1a;Jmeter 下载和配置 案例实战 优化一&#xff1a;加 synchronized 锁 优化二&#xff1a;使用 redis 的 setnx 实现分布式锁 优化三&#xff1a;使用 Lua 脚本…

参数估计理论

估计理论的主要任务是在某种信号假设下&#xff0c;估算该信号中某个参数&#xff08;比如幅度、相位、达到时间&#xff09;的具体取值。 参数估计&#xff1a;先假定研究的问题具有某种数学模型&#xff0c; 如正态分布&#xff0c;二项分布&#xff0c;再用已知类别的学习样…

[vulnhub] DarkHole: 2

https://www.vulnhub.com/entry/darkhole-2,740/ 端口扫描主机发现 探测存活主机&#xff0c;185是靶机 # nmap -sP 192.168.75.0/24 Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-11-08 18:02 CST Nmap scan report for 192.168.75.1 Host is up (0.…

【温度表达转化】

【温度表达转化】 C语言代码C代码Java代码Python代码 &#x1f490;The Begin&#x1f490;点点关注&#xff0c;收藏不迷路&#x1f490; 利用公式 C5∗(F−32)/9 &#xff08;其中C表示摄氏温度&#xff0c;F表示华氏温度&#xff09; 进行计算转化。 输出 输出一行&#x…

【Promise】JS 异步之宏队列与微队列

文章目录 1 原理图2 说明3 相关面试题3.1 面试题13.2 面试题23.3 面试题33.4 面试题4 1 原理图 2 说明 JS 中用来存储待执行回调函数的队列包含 2 个不同特定的队列&#xff1a;宏队列和微队列。宏队列&#xff1a;用来保存待执行的宏任务(回调)&#xff0c;比如&#xff1a;定…

【Linux】Linux入门实操——vim、目录结构、远程登录、重启注销

一、Linux 概述 1. 应用领域 服务器领域 linux在服务器领域是最强的&#xff0c;因为它免费、开源、稳定。 嵌入式领域 它的内核最小可以达到几百KB, 可根据需求对软件剪裁&#xff0c;近些年在嵌入式领域得到了很大的应用。 主要应用&#xff1a;机顶盒、数字电视、网络…

ubuntu下aarch64-linux-gnu(交叉编译) gdb/gdbserver(二)

ubuntu下aarch64-linux-gnu(交叉编译) gdb/gdbserver&#xff08;二&#xff09; 本教程作为gdb/gdbserver编译安装教程的一个补充&#xff0c;教会大家如何使用gdb/gdbserver进行远程调试。 如上图所示&#xff0c;我们需要将编译后的gdbserver上传至目标设备&#xff0c;其上…

Flutter错误: uses-sdk:minSdkVersion 16 cannot be smaller than version 21 declared

前言 今天要做蓝牙通信的功能&#xff0c;我使用了flutter_reactive_ble这个库&#xff0c;但是在运行的时候发现一下错误 Launching lib/main.dart on AQM AL10 in debug mode... /Users/macbook/Desktop/test/flutter/my_app/android/app/src/debug/AndroidManifest.xml Err…

c中柔性数组

c99中&#xff0c;结构中最后一个元素允许是未知大小的数组&#xff0c;这就叫柔性数组成员。 柔性数组的特点 1.结构中柔性数组前必须至少有一个其他成员 2.sizeof返回的这种结构大小不包括柔性数组的内存 3.包含柔性数组成员的结构用malloc函数进行动态分配&#xff0c;并…

WPS 默认模板修改

重装系统把word自定义样式搞没了&#xff0c;安装office时间太长&#xff0c;转战wps 解决方案 打开wps 点击【新建】word空白文档 设置修改你自己的样式 点击文件–另存为–Microsoft Word 带宏的模板文件&#xff08;*.dotm&#xff09; 另存路径为如下&#xff1a; 查…

Ubuntu24.04网络异常与应对方案记录

PS: 参加过408改卷的ZJU ghsongzju.edu.cn 开启嘲讽: 你们知道408有多简单吗&#xff0c;操作系统真实水平自己知道就行&#xff5e;&#xff5e; Requested credits of master in UWSC30&#xff0c;in ZJU24&#xff0c;domestic master is too simple ubuntu安全软件 在 U…

[C++11] Lambda 表达式

lambda 表达式&#xff08;Lambda Expressions&#xff09;作为一种匿名函数&#xff0c;为开发者提供了简洁、灵活的函数定义方式。相比传统的函数指针和仿函数&#xff0c;lambda 表达式在简化代码结构、提升代码可读性和编程效率方面表现出色。 Lambda 表达式的基本语法 在…

Docker平台搭建方法

Docker平台搭建方法 1.1在VMware中创建两个虚拟机&#xff0c;只需要1个网卡&#xff0c;连接192.168.200.0网络。 虚拟机分配2个CPU,2G内存&#xff0c;60G硬盘&#xff0c;主机名分别为server和client,IP地址分别为192.168.200.137和192.168.200.138。server节点还兼做regis…

【学习笔记】Kylin-Desktop-V10-SP1 麒麟系统知识4——设备设置

提示&#xff1a;学习麒麟Kylin-Desktop-V10-SP1系统设备设置相关知识&#xff0c;包含设备设置进入方法、配置打印机、设置鼠标、键盘相关参数&#xff08;包含输入法的配置&#xff09;、以及管理快捷键组合、和多屏协同相关配置 一、前期准备 成功安装麒麟系统&#xff08…

Linux应用项目之量产工具(一)——显示系统

目录 前言 项目特点及介绍 ① 简单易用 ② 软件可配置、易扩展 ③ 纯 C 语言编程 软件总框架 显示系统 1.数据结构抽象 disp_manager.h 2.Framebuffer编程 framebuffer.c 3.显示管理 disp_manager.c 4.单元测试 disp_test.c 顶层目录Makefile 顶层目录Makefil…

企微SCRM价格解析及其性价比分析

内容概要 在如今的数字化时代&#xff0c;企业对于客户关系管理的需求日益增长&#xff0c;而企微SCRM&#xff08;Social Customer Relationship Management&#xff09;作为一款新兴的客户管理工具&#xff0c;正好满足了这一需求。本文旨在为大家深入解析企微SCRM的价格体系…

leetcode92:反转链表||

给你单链表的头指针 head 和两个整数 left 和 right &#xff0c;其中 left < right 。请你反转从位置 left 到位置 right 的链表节点&#xff0c;返回 反转后的链表 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], left 2, right 4 输出&#xff1a;[1,4,3,2…

Python——数列1/2,2/3,3/4,···,n/(n+1)···的一般项为Xn=n/(n+1),当n—>∞时,判断数列{Xn}是否收敛

没注释的源代码 from sympy import * n symbols(n) s n/(n1) print(数列的极限为&#xff1a;,limit(s,n,oo))

多线程的创建方式以及及Thread类详解

目录 一.线程的创建方法&#xff1a;&#xff08;重点&#xff09; 一&#xff1a;继承Thread类 写法一&#xff1a;正常写法 写法二&#xff1a;匿名内部类 二.实现Runnable接口 写法一&#xff1a;正常写法 写法二&#xff1a;匿名内部类 三. 实现 Callable 接口 ​…