当前位置: 首页> 教育> 就业 > 购买备案域名_温州网络网_百度推广下载安装_品牌宣传策略有哪些

购买备案域名_温州网络网_百度推广下载安装_品牌宣传策略有哪些

时间:2025/7/11 5:44:51来源:https://blog.csdn.net/qq_28499879/article/details/143641282 浏览次数:0次
购买备案域名_温州网络网_百度推广下载安装_品牌宣传策略有哪些

文章目录

  • 一、简介
  • 二、关键数据结构
    • 2.1 devfreq_dev_profile 结构体
    • 2.2 devfreq_governor 结构体
    • 2.3 devfreq 设备结构体
  • 三、关键接口和工作流程
    • 3.1 devfreq framework 初始化
    • 3.2 添加 devfreq 设备
    • 3.3 governor 初始化
    • 3.4 频率监控和调整过程
      • governor_simpleondemand
      • userspace\powersave\performance
  • 四、通过修改 opp 来控制 devfreq 调频
    • 4.1 注册 devfreq_cooling 设备
    • 4.2 温控子系统修改 opp 状态
    • 4.3 devfreq 获取 opp 状态

一、简介

devfreq 在 linux 内核中主要用于动态调节设备频率,以优化功耗和性能。提供了管理设备(如 GPU\摄像头\ddr)频率的接口,以便系统能够根据实际需求动态地改变设备的工作频率。

devfreq 可能在温控系统中提供 cooling dev 的调频接口,也可能在功耗管理模块中提供功耗管理的调频接口。

二、关键数据结构

devfreq 子系统中主要的结构体有描述设备接口的结构体 devfreq_dev_profile、描述设备调频策略的结构体 devfreq_governor、以及核心结构体 devfreq。

2.1 devfreq_dev_profile 结构体

devfreq_dev_profile 结构体定义了设备频率管理的相关信息和操作接口。

struct devfreq_dev_profile {unsigned long initial_freq;  // 初始化频率,默认工作频率unsigned int polling_ms;    // 以ms为单位的轮询间隔,定义了设备状态的更新频率int (*target)(struct device *dev, unsigned long *freq, u32 flags);  // 设置频率// 获取设备当前频率、工作时间、私有数据等信息int (*get_dev_status)(struct device *dev, struct devfreq_dev_status *stat);  int (*get_cur_freq)(struct device *dev, unsigned long *freq);  // 返回当前频率void (*exit)(struct device *dev);  // 设备退出时清理函数回调unsigned long *freq_table;  // 设备opp支持的频率表unsigned int max_state;  // freq_table表大小
};

2.2 devfreq_governor 结构体

devfreq_governor 结构体定义了调频策略的相关接口和信息。

struct devfreq_governor {struct list_head node;const char name[DEVFREQ_NAME_LEN];const unsigned int immutable;  // 为1时表示该策略不可改变(不能切调频策略)// 调频策略算法,根据当前状态(温度、负载等)结合策略算法,返回设备应该设置的频率int (*get_target_freq)(struct devfreq *this, unsigned long *freq);// 处理特定事件,如start\stop\suspend\resume等事件int (*event_handler)(struct devfreq *devfreq, unsigned int event, void *data);  
};

2.3 devfreq 设备结构体

devfreq 结构体用于描述一个可以调频的设备的所有信息,包括设备调频接口、调频策略、状态等信息。

struct devfreq {struct list_head node;struct mutex lock;struct device dev;struct devfreq_dev_profile *profile;  // 设备调整频率的相关接口和参数const struct devfreq_governor *governor;  // 设备调频策略char governor_name[DEVFREQ_NAME_LEN];struct notifier_block nb;  // 设备状态变化相关的通知nbstruct delayed_work work;  // devfreq 监控的workunsigned long previous_freq;  // 上一次设置的频率struct devfreq_dev_status last_status;    // 设备最后的状态void *data; /* private data for governors */unsigned long min_freq;  // 设备支持频率的上下限unsigned long max_freq;unsigned long scaling_min_freq;   // opp请求的最小和最大频率unsigned long scaling_max_freq;bool stop_polling;   // 停止轮询的标志位unsigned long suspend_freq;unsigned long resume_freq;    // 设备suspend和resume时需要设置的频率atomic_t suspend_count;    // suspend计数器/* 记录频率转换的一些信息 */unsigned int total_trans;  // 转换次数unsigned int *trans_table;  // 指向转换表的信息unsigned long *time_in_state;  // 每种频率状态的持续时间unsigned long last_stat_updated;  // 最后一次状态更新的时间戳struct srcu_notifier_head transition_notifier_list;
};

三、关键接口和工作流程

3.1 devfreq framework 初始化

devfreq framework 初始化非常简单:

● 创建设备类;
● 创建工作队列,后续用于频率监控任务调用;
static int __init devfreq_init(void)
{devfreq_class = class_create(THIS_MODULE, "devfreq");devfreq_wq = create_freezable_workqueue("devfreq_wq");devfreq_class->dev_groups = devfreq_groups;return 0;
}
subsys_initcall(devfreq_init);

3.2 添加 devfreq 设备

使用 devm_devfreq_add_device 或者 devfreq_add_device 接口添加 devfreq 设备。

devm_ 前缀的接口区别就是使用了设备管理机制,当设备被创建时,内核会自动管理资源的分配和释放;当设备不再使用(例如驱动被卸载时),内核会自动调用 devm_devfreq_dev_release 接口来清理相关资源。

函数声明如下:

struct devfreq *devfreq_add_device(struct device *dev,struct devfreq_dev_profile *profile,const char *governor_name,void *data)
  • struct devfreq_dev_profile *profile,入参 profile 是设备操作函数和相关信息的结构体指针;
  • const char *governor_name,入参 governor_name 表示默认配置的 governor;
  • void *data,data 是传递给 governor 的私有数据。

具体实现如下:

struct devfreq *devfreq_add_device(struct device *dev,struct devfreq_dev_profile *profile,const char *governor_name,void *data)
{// 检查是否已经注册过devfreq设备mutex_lock(&devfreq_list_lock);devfreq = find_device_devfreq(dev);mutex_unlock(&devfreq_list_lock);if (!IS_ERR(devfreq)) {dev_err(dev, "%s: Unable to create devfreq for the device.\n",__func__);err = -EINVAL;goto err_out;}devfreq = kzalloc(sizeof(struct devfreq), GFP_KERNEL);// devfreq设备相关信息的初始化mutex_init(&devfreq->lock);mutex_lock(&devfreq->lock);devfreq->dev.parent = dev;devfreq->dev.class = devfreq_class;devfreq->dev.release = devfreq_dev_release;INIT_LIST_HEAD(&devfreq->node);devfreq->profile = profile;strncpy(devfreq->governor_name, governor_name, DEVFREQ_NAME_LEN);devfreq->previous_freq = profile->initial_freq;devfreq->last_status.current_frequency = profile->initial_freq;devfreq->data = data;devfreq->nb.notifier_call = devfreq_notifier_call;// 如果没有创建freq table,从opp读取相关信息创建profile的freq tableif (!devfreq->profile->max_state && !devfreq->profile->freq_table) {mutex_unlock(&devfreq->lock);err = set_freq_table(devfreq);if (err < 0)goto err_dev;mutex_lock(&devfreq->lock);}// 设置opp支持配置的频率范围和devfreq支持的频率范围// 受温控或者功耗模块配置影响,opp支持配置的频率范围会改变// 最小频率配置devfreq->scaling_min_freq = find_available_min_freq(devfreq);devfreq->min_freq = devfreq->scaling_min_freq;// 最大频率配置devfreq->scaling_max_freq = find_available_max_freq(devfreq);devfreq->max_freq = devfreq->scaling_max_freq;// suspend 频率和计数配置devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);atomic_set(&devfreq->suspend_count, 0);dev_set_name(&devfreq->dev, "%s", dev_name(dev));err = device_register(&devfreq->dev);// 频率转换表资源申请devfreq->trans_table = devm_kzalloc(&devfreq->dev,array3_size(sizeof(unsigned int),devfreq->profile->max_state,devfreq->profile->max_state),GFP_KERNEL);devfreq->time_in_state = devm_kcalloc(&devfreq->dev,devfreq->profile->max_state,sizeof(unsigned long),GFP_KERNEL);devfreq->last_stat_updated = jiffies;// 初始化频率状态变化的notifiersrcu_init_notifier_head(&devfreq->transition_notifier_list);mutex_unlock(&devfreq->lock);mutex_lock(&devfreq_list_lock);// 注册设备的governor,并通知governor start eventgovernor = try_then_request_governor(devfreq->governor_name);devfreq->governor = governor;err = devfreq->governor->event_handler(devfreq, DEVFREQ_GOV_START,NULL);list_add(&devfreq->node, &devfreq_list);mutex_unlock(&devfreq_list_lock);return devfreq;
}
EXPORT_SYMBOL(devfreq_add_device);

3.3 governor 初始化

系统支持的 governor 在启动(subsys_initcall)时调用 devfreq_add_governor 接口注册 governor 到 devfreq framework 中。

以 userspace governor 为例:

static struct devfreq_governor devfreq_userspace = {.name = "userspace",.get_target_freq = devfreq_userspace_func,.event_handler = devfreq_userspace_handler,
};static int __init devfreq_userspace_init(void)
{return devfreq_add_governor(&devfreq_userspace);
}
subsys_initcall(devfreq_userspace_init);static void __exit devfreq_userspace_exit(void)
{int ret;ret = devfreq_remove_governor(&devfreq_userspace);if (ret)pr_err("%s: failed remove governor %d\n", __func__, ret);return;
}
module_exit(devfreq_userspace_exit);
MODULE_LICENSE("GPL");

devfreq_add_governor 接口实现如下,实际操作就是:

	● 将 governor 添加到 list 链表中;● 遍历已经注册的 devfreq 设备链表,如果 governor->name 与 devfreq->governor_name 相等,则将 governor 注册为 devfreq 的 governor;
int devfreq_add_governor(struct devfreq_governor *governor)
{mutex_lock(&devfreq_list_lock);// 检查是否已经注册g = find_devfreq_governor(governor->name);// 添加到governor list中list_add(&governor->node, &devfreq_governor_list);// 遍历已经注册的devfreq设备列表,将governor注册到对应的devfreq上list_for_each_entry(devfreq, &devfreq_list, node) {int ret = 0;struct device *dev = devfreq->dev.parent;if (!strncmp(devfreq->governor_name, governor->name,DEVFREQ_NAME_LEN)) {devfreq->governor = governor;ret = devfreq->governor->event_handler(devfreq,DEVFREQ_GOV_START, NULL);}}err_out:mutex_unlock(&devfreq_list_lock);return err;
}
EXPORT_SYMBOL(devfreq_add_governor);

3.4 频率监控和调整过程

devfreq 系统使用 update_devfreq 接口更新设备的频率,该接口实现流程如下图所示:
devfreq调整频率的流程

governor_simpleondemand

simpleondemand 算法根据设备当前的负载调整工作频率。

在注册 devfreq 设备或者向 devfreq framework 中注册 governor 时,会像 governor 发送 DEVFREQ_GOV_START 事件,governor 在处理 start 事件时调用 devfreq_monitor_start 接口启动通过 delay work 实现的 devfreq 监控和调整模拟器。

userspace\powersave\performance

这三种 governor 比较简单,不需要依赖任务来更新频率:

  • userspace:在用户修改频率时,调用 update_devfreq 接口更新频率,get_target_freq() 接口返回的是用户定义的频率;
  • performance:在 start event 处理时,调用 update_devfreq 接口更新频率,get_target_freq() 接口返回的是最大值;
  • powersave:在 start event 处理时,调用 update_devfreq 接口更新频率,get_target_freq() 接口返回的是最小值;

四、通过修改 opp 来控制 devfreq 调频

linux温控子系统参考 :《linux thermal 温控子系统》
linux opp模块参考 :《linux opp模块》

在 linux 中温控子系统或者功耗子系统中,都是通过修改设备的 opp 属性来控制设备的频率的。
温控子系统调整频率流程

以温控系统中的 devfreq_cooling 设备为例,代码在 drivers\thermal\devfreq_cooling.c 中。

4.1 注册 devfreq_cooling 设备

在 devfreq device 初始化的时候,调用 of_devfreq_cooling_register 接口,将 devfreq 设备注册为温控子系统中的 devfreq_cooling 设备。

同时,调用 devfreq_register_opp_notifier 接口将 update_devfreq 注册为 notifier_block 回调,该回调最终注册到 opp_table 中,当 opp 状态发生变化时,会调用 update_devfreq 接口更新设备频率。

4.2 温控子系统修改 opp 状态

opp 中使用 dev_pm_opp 结构体表示 opp 项,结构体中的 available 表示 opp 是否 enable。

struct dev_pm_opp {……bool available;    // enable/disable……
}

温控子系统中调频接口为 devfreq_cooling_set_cur_state,该接口调用 partition_enable_opps,将大于输入的 state 的 opp 状态全部设置为 disable(opp_table 中的 opp 按照频率从低到高的顺序排列),实现将大于某 freq 的 opp 状态设置为 disable:

static int devfreq_cooling_set_cur_state(struct thermal_cooling_device *cdev,unsigned long state)
{ret = partition_enable_opps(dfc, state);dfc->cooling_state = state;return 0;
}static int partition_enable_opps(struct devfreq_cooling_device *dfc,unsigned long cdev_state)
{int i;struct device *dev = dfc->devfreq->dev.parent;for (i = 0; i < dfc->freq_table_size; i++) {struct dev_pm_opp *opp;int ret = 0;unsigned int freq = dfc->freq_table[i];bool want_enable = i >= cdev_state ? true : false;opp = dev_pm_opp_find_freq_exact(dev, freq, !want_enable);if (PTR_ERR(opp) == -ERANGE)continue;else if (IS_ERR(opp))return PTR_ERR(opp);dev_pm_opp_put(opp);if (want_enable)ret = dev_pm_opp_enable(dev, freq);elseret = dev_pm_opp_disable(dev, freq);if (ret)return ret;}return 0;
}

opp 模块中调用 _opp_set_availability 接口配置 opp available state,更新状态后调用 notifier 回调,也就是 devfreq 设备的 update_devfreq 接口。

static int _opp_set_availability(struct device *dev, unsigned long freq,bool availability_req)
{opp->available = availability_req;/* Notify the change of the OPP availability */if (availability_req)blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_ENABLE,opp);elseblocking_notifier_call_chain(&opp_table->head,OPP_EVENT_DISABLE, opp);return r;
}

4.3 devfreq 获取 opp 状态

如在 3.4 中描述的 update_devfreq 流程,该接口先根据 governor 算法计算出 target_freq 目标频率,调用 devfreq device 的 target 接口设置频率。

在 devfreq device 设置频率是,需要调用 devfreq_recommended_opp,根据 target_freq 从 opp 表中查找最合适的频率,然后将频率设置为 opp 表返回的频率。

struct dev_pm_opp *devfreq_recommended_opp(struct device *dev,unsigned long *freq,u32 flags)
{struct dev_pm_opp *opp;if (flags & DEVFREQ_FLAG_LEAST_UPPER_BOUND) {/* The freq is an upper bound. opp should be lower */opp = dev_pm_opp_find_freq_floor(dev, freq);/* If not available, use the closest opp */if (opp == ERR_PTR(-ERANGE))opp = dev_pm_opp_find_freq_ceil(dev, freq);} else {/* The freq is an lower bound. opp should be higher */opp = dev_pm_opp_find_freq_ceil(dev, freq);/* If not available, use the closest opp */if (opp == ERR_PTR(-ERANGE))opp = dev_pm_opp_find_freq_floor(dev, freq);}return opp;
}
EXPORT_SYMBOL(devfreq_recommended_opp);

也就是 devfreq governor 算法计算的 target_freq 只是推荐频率,最终设置的频率可以通过查找 opp 表得来。

关键字:购买备案域名_温州网络网_百度推广下载安装_品牌宣传策略有哪些

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: