高通平台GPU动态调频DCVS . 篇2 . Framework & Procedure

本文深入解析高通平台GPU动态调频DCVS机制,涵盖Adreno驱动、kgsl抽象层、msm-adreno-tz governor及Devfreq框架。通过详细的技术流程和代码分析,揭示了DCVS决策算法如何在TrustZone环境下实现GPU频率的智能调节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


系列文章
高通平台GPU动态调频DCVS . 篇1 . Interface
高通平台GPU动态调频DCVS . 篇2 . Framework & Procedure
高通平台GPU动态调频DCVS . 篇3 . 一个无法调频问题的解决过程


1. 高通平台 GPU DCVS架构

GPU DCVS是基于Linux Devfreq来实现

  • 高通的kgsl(kernel-graphics-support-layer)作为devfreq device
  • msm-adreno-tz 作为devfreq governor

简单的架构如下
在这里插入图片描述

如上图所示

  • 首先 KGSL 作为device,msm-adreno-tz 作为governor注册到devfreq core
  • KGSL driver通过notify机制去调用 governor msm-adreno-tz 的tz_notify() 函数
  • tz_notify() 调用 devfreq core的 update_devfreq()
  • update_devfreq() 调用governor的 get_target_freq()来计算处理目标频率
  • update_devfreq() 调用KGSL的target回调来传递目标频率,并实施调频

2. Adreno 部分

Anreno作为平台相关的GPU驱动,提供了读取和操作GPU硬件的interface

2.1 频率解析
  • 频率表
    频率表位于dts arch/arm64/boot/dts/qcom/sm8150-v2.dtsi
    qcom,gpu-pwrlevels {
        #address-cells = <1>;
        #size-cells = <0>;

        compatible = "qcom,gpu-pwrlevels";

        qcom,gpu-pwrlevel@0 {
            reg = <0>;
            qcom,gpu-freq = <810000000>;
            qcom,bus-freq = <11>;
            qcom,bus-min = <11>;
            qcom,bus-max = <11>;
        };

        qcom,gpu-pwrlevel@1 {
            reg = <1>;
            qcom,gpu-freq = <585000000>;
            qcom,bus-freq = <11>;
            qcom,bus-min = <11>;
            qcom,bus-max = <11>;
        };

        qcom,gpu-pwrlevel@2 {
            reg = <2>;
            qcom,gpu-freq = <499200000>;
            qcom,bus-freq = <9>;
            qcom,bus-min = <8>;
            qcom,bus-max = <11>;
        };

        qcom,gpu-pwrlevel@3 {
            reg = <3>;
            qcom,gpu-freq = <427000000>;
            qcom,bus-freq = <6>;
            qcom,bus-min = <5>;
            qcom,bus-max = <7>;
        };

        qcom,gpu-pwrlevel@4 {
            reg = <4>;
            qcom,gpu-freq = <345000000>;
            qcom,bus-freq = <3>;
            qcom,bus-min = <3>;
            qcom,bus-max = <5>;
        };

        qcom,gpu-pwrlevel@5 {
            reg = <5>;
            qcom,gpu-freq = <257000000>;
            qcom,bus-freq = <3>;
            qcom,bus-min = <2>;
            qcom,bus-max = <4>;
        };

        qcom,gpu-pwrlevel@6 {
            reg = <6>;
            qcom,gpu-freq = <0>;
            qcom,bus-freq = <0>;
            qcom,bus-min = <0>;
            qcom,bus-max = <0>;
        };
        /delete-node/ qcom,gpu-pwrlevel@7;
    };
  • 驱动解析
    drivers/gpu/msm/adreno.c
    adreno 驱动对应的设备名为qcom,kgsl-3d0
static const struct of_device_id adreno_match_table[] = {
    { .compatible = "qcom,kgsl-3d0", .data = &device_3d0 },
    {}
};
adreno_probe()
    -> adreno_of_get_power()
        -> adreno_of_get_pwrlevels()
            -> adreno_of_parse_pwrlevels()

结果保存在 adreno_device->kgsl_device->kgsl_pwrctrl结构体的kgsl_pwrlevel结构体类型的的数组中,pwrlevel作为这个数组的index

/**
 * struct kgsl_pwrlevel - Struct holding different pwrlevel info obtained from
 * from dtsi file
 * @gpu_freq:          GPU frequency vote in Hz
 * @bus_freq:          Bus bandwidth vote index
 * @bus_min:           Min bus index @gpu_freq
 * @bus_max:           Max bus index @gpu_freq
 */
struct kgsl_pwrlevel {
    unsigned int gpu_freq;
    unsigned int bus_freq;
    unsigned int bus_min;
    unsigned int bus_max;
};

3. kgsl 部分

kgsl是抽象层,代码位于drivers/gpu/msm

3.1 注册devfreq device

kgsl是作为Devfreq的device存在, 在kgsl_pwrscale_init() 函数,就会去注册kgsl device到devfreq framework

    devfreq = devfreq_add_device(dev, &pwrscale->gpu_profile.profile,
            governor, pwrscale->gpu_profile.private_data);
3.2 Notify 定义和注册、通知方法

在DCVS架构中,GPU调频实际上是由adreno-kgsl发起,进而通知msm-adreno-tz governor

  • 定义notify head
    kgsl_pwrscale_init()
srcu_init_notifier_head(&pwrscale->nh);
  • 提供notify register方法
    提供kgsl_devfreq_add_notifier()方法,供governor使用
/*
 * kgsl_devfreq_add_notifier - add a fine grained notifier.
 * @dev: The device
 * @nb: Notifier block that will recieve updates.
 *
 * Add a notifier to recieve ADRENO_DEVFREQ_NOTIFY_* events
 * from the device.
 */
int kgsl_devfreq_add_notifier(struct device *dev,
        struct notifier_block *nb)
{
    struct kgsl_device *device = dev_get_drvdata(dev);

    if (device == NULL)
        return -ENODEV;

    if (nb == NULL)
        return -EINVAL;

    return srcu_notifier_chain_register(&device->pwrscale.nh, nb);
}
EXPORT_SYMBOL(kgsl_devfreq_add_notifier);
  • 提供notify call chain 方法
    触发governor notify 处理函数tz_notify()工作
static void do_devfreq_notify(struct work_struct *work)
{
    struct kgsl_pwrscale *pwrscale = container_of(work,
            struct kgsl_pwrscale, devfreq_notify_ws);
    struct devfreq *devfreq = pwrscale->devfreqptr;
    srcu_notifier_call_chain(&pwrscale->nh,
                 ADRENO_DEVFREQ_NOTIFY_RETIRE,
                 devfreq);
}
3.3 提供调频回调方法

Devfreq 框架需要device端提供target() 回调, 获取并处理来自devfreq的目标频率

#define KGSL_PWRSCALE_INIT(_priv_data) { \
    .enabled = true, \
    .gpu_profile = { \
        .private_data = _priv_data, \
        .profile = { \
            .target = kgsl_devfreq_target, \
            .get_dev_status = kgsl_devfreq_get_dev_status, \
            .get_cur_freq = kgsl_devfreq_get_cur_freq, \
    } }, \
/*
 * kgsl_devfreq_target - devfreq_dev_profile.target callback
 * @dev: see devfreq.h
 * @freq: see devfreq.h
 * @flags: see devfreq.h
 *
 * This function expects the device mutex to be unlocked.
 */
int kgsl_devfreq_target(struct device *dev, unsigned long *freq, u32 flags)
{
    struct kgsl_device *device = dev_get_drvdata(dev);
    struct kgsl_pwrctrl *pwr;
    struct kgsl_pwrlevel *pwr_level;
    int level;
    unsigned int i;
    unsigned long cur_freq;

    if (device == NULL)
        return -ENODEV;
    if (freq == NULL)
        return -EINVAL;
    if (!device->pwrscale.enabled)
        return 0;

    pwr = &device->pwrctrl;
    if (_check_maxfreq(flags)) {
        /*
         * The GPU is about to get suspended,
         * but it needs to be at the max power level when waking up
        */
        pwr->wakeup_maxpwrlevel = 1;
        return 0;
    }

    mutex_lock(&device->mutex);
    cur_freq = kgsl_pwrctrl_active_freq(pwr);
    level = pwr->active_pwrlevel;
    pwr_level = &pwr->pwrlevels[level];

    /* If the governor recommends a new frequency, update it here */
    if (*freq != cur_freq) {
        level = pwr->max_pwrlevel;
        /*
         * Array index of pwrlevels[] should be within the permitted
         * power levels, i.e., from max_pwrlevel to min_pwrlevel.
         */
        for (i = pwr->min_pwrlevel; (i >= pwr->max_pwrlevel
                    && i <= pwr->min_pwrlevel); i--)
            if (*freq <= pwr->pwrlevels[i].gpu_freq) {
                if (pwr->thermal_cycle == CYCLE_ACTIVE)
                    level = _thermal_adjust(pwr, i);
                else
                    level = popp_trans2(device, i);
                break;
            }
        if (level != pwr->active_pwrlevel)
            kgsl_pwrctrl_pwrlevel_change(device, level);
    } else if (popp_stable(device)) {
        popp_trans1(device);
    }

    *freq = kgsl_pwrctrl_active_freq(pwr);

    mutex_unlock(&device->mutex);
    return 0;
}
EXPORT_SYMBOL(kgsl_devfreq_target);

4. msm-adreno-tz 部分

代码位于drivers/devfreq/governor_msm_adreno_tz.c

4.1 注册devfreq governor
static int __init msm_adreno_tz_init(void)
{
    workqueue = create_freezable_workqueue("governor_msm_adreno_tz_wq");
    if (workqueue == NULL)
        return -ENOMEM;

    return devfreq_add_governor(&msm_adreno_tz);
}
4.2 实现notify callback function

实现notify callback function tz_notify()

static int tz_notify(struct notifier_block *nb, unsigned long type, void *devp)
{
    int result = 0;
    struct devfreq *devfreq = devp;

    switch (type) {
    case ADRENO_DEVFREQ_NOTIFY_IDLE:
    case ADRENO_DEVFREQ_NOTIFY_RETIRE:
        mutex_lock(&devfreq->lock);
        result = update_devfreq(devfreq);
        mutex_unlock(&devfreq->lock);
        /* Nofifying partner bus governor if any */
        if (partner_gpu_profile && partner_gpu_profile->bus_devfreq) {
            mutex_lock(&partner_gpu_profile->bus_devfreq->lock);
            update_devfreq(partner_gpu_profile->bus_devfreq);
            mutex_unlock(&partner_gpu_profile->bus_devfreq->lock);
        }
        break;
    /* ignored by this governor */
    case ADRENO_DEVFREQ_NOTIFY_SUBMIT:
    default:
        break;
    }
    return notifier_from_errno(result);
}

tz_notify() 会调用到 update_devfreq()

update_devfreq() 是devfreq core提供通用调频方法, governor通过update_devfreq() 来实现对频率的处理运算以及调用device的target() 回调传递频率到device端.

  • 频率处理运算
    /* Reevaluate the proper frequency */
    err = devfreq->governor->get_target_freq(devfreq, &freq, &flags);
  • 通过target回调传递目标频率到device
    err = devfreq->profile->target(devfreq->dev.parent, &freq, flags);

5. DEVFREQ Framework

Devfreq是该机制的核心框架,所以需要了解,可以参考下文
Linux DEVFREQ - 通用DVFS Framework

6. 流程简述

调频实际上是由Adreno发起,governor是为了满足devfreq标准框架而存在,流程图如下,从上到下的执行顺序
核心的DCVS决策算法位于TrustZone
在这里插入图片描述

adreno_dispatcher_work
    ->kgsl_pwrscale_update
        ->queue_work(devfreq_notify_ws)
            ->do_devfreq_notify(ADRENO_DEVFREQ_NOTIFY_RETIRE)
                ->tz_notify()
                    ->update_devfreq(devfreq)
                        ->profile->get_dev_status()
                            ->profile.target()

最后: 代码来源

Linux 内核部分分析用的代码来源于内核开源代码,这里是以最新的SM8150作为例子
手机厂商内核开源代码

&lt;think&gt;好的,用户想了解高通KGSL的相关信息,包括功能、架构等。首先,我需要回忆一下之前提供的引用内容。引用[1]提到KGSL位于/sys/class/kgsl/kgsl-3d0目录,涉及GPU的devfreq框架,这可能与电源管理和频率调节有关。而引用[2]主要关于Perfetto工具,可能与性能分析相关,但用户的问题重点在KGSL本身。 KGSL是高通Adreno GPU的驱动模块,负责图形渲染和计算任务的管理。我需要详细说明它的功能,比如提供用户空间接口、电源管理、内存管理等。架构方面,可能需要分层描述,从用户空间到内核驱动,再到硬件层。同时,结合引用中的devfreq,可以提到GPU动态调频功能,这是通过Linux的devfreq框架实现的,这也解释了为什么在sysfs中有相关目录。 用户可能还想知道KGSL的应用场景或如何调试,比如使用Perfetto进行性能分析,但引用[2]提到的是Display显示调试,可能关联性不大,不过可以简要提及工具使用。需要确保回答结构清晰,分点列出功能和架构,并补充相关问题,帮助用户深入理解。另外,注意使用中文,正确应用LaTeX格式,如遇到数学公式用$...$,独立公式用$$...$$,但这里可能用不上太多数学公式,所以主要关注功能架构的描述和引用标注。&lt;/think&gt;### 高通 KGSL 的功能与架构解析 #### 1. KGSL 的基本定义 高通 **KGSL**(**Kernel Graphics Support Layer**)是用于管理 Adreno GPU 的 Linux 内核驱动模块,主要负责图形渲染、计算任务调度以及与硬件交互的底层控制。它是 Android 系统中 GPU 功能实现的核心组件[^1]。 #### 2. 主要功能 - **图形渲染管理** 提供 OpenGL ES、Vulkan 等图形 API 的底层支持,处理顶点着色、光栅化、纹理映射等渲染流程。 - **计算任务调度** 支持 GPU 通用计算(如机器学习推理),通过命令流处理器(Command Stream Processor)分配任务。 - **电源与性能管理** 基于 Linux `devfreq` 框架实现动态频率调节(DCVS),根据负载自动调整 GPU 频率以平衡性能与功耗。例如: ```bash # 查看可用频率列表 cat /sys/class/kgsl/kgsl-3d0/devfreq/available_frequencies ``` 引用[1]中提到的 `/sys/class/kgsl/kgsl-3d0/devfreq` 目录即为此功能的实现。 - **内存管理** 管理 GPU 专用内存(GMEM)与系统内存的交互,包括缓存同步和 DMA 传输。 #### 3. 架构分层 KGSL 的架构可分为三层: 1. **用户空间接口** 通过 `/dev/kgsl-3d0` 设备节点向用户空间提供 IOCTL 接口,供图形库(如 libGLESv2.so)调用。 2. **内核驱动层** 包含以下核心模块: - **命令流处理器**:解析并执行 GPU 指令 - **内存管理器**:处理 GPU 内存分配与映射 - **电源管理模块**:集成 `devfreq` 实现动态调频 3. **硬件抽象层** 直接操作 Adreno GPU 寄存器,实现特定型号的硬件适配。 #### 4. 关键调试与监控 - **GPU 负载监控** 通过 `gpu_load` 文件实时查看 GPU 利用率: ```bash cat /sys/class/kgsl/kgsl-3d0/gpu_load ``` - **性能跟踪工具** 结合 Perfetto 或 Systrace 分析 GPU 活动轨迹(引用[2]中提到 Perfetto 可捕获 Display 子系统数据,KGSL 事件也包含在跟踪范围内)。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值