thermal代码分析(2)thermal_core.c

adtxl
2020-10-15 / 0 评论 / 1,049 阅读 / 正在检测是否收录...

thermal\_core是thermal框架的核心,负责将thermal\_zone、thermal\_cooling和thermal\_governor连接起来
首先看下头文件thermal_core.h,

/* Initial state of a cooling device during binding */
#define THERMAL_NO_TARGET -1UL

/*
 * This structure is used to describe the behavior of
 * a certain cooling device on a certain trip point
 * in a certain thermal zone
 */
 // thermal_instance结构体定义
 struct thermal_instance{
 ......
 };
// 注册和卸载governor
int thermal_register_governor(struct thermal_governor *);
void thermal_unregister_governor(struct thermal_governor *);

// 下面通过宏判断使用哪个governor
#ifdef CONFIG_THERMAL_GOV_STEP_WISE
int thermal_gov_step_wise_register(void);
void thermal_gov_step_wise_unregister(void);
#else
static inline int thermal_gov_step_wise_register(void) { return 0; }
static inline void thermal_gov_step_wise_unregister(void) {}
#endif /* CONFIG_THERMAL_GOV_STEP_WISE */
...
...
/* device tree support */
#ifdef CONFIG_THERMAL_OF
int of_parse_thermal_zones(void);
void of_thermal_destroy_zones(void);
int of_thermal_get_ntrips(struct thermal_zone_device *);
bool of_thermal_is_trip_valid(struct thermal_zone_device *, int);
const struct thermal_trip *
of_thermal_get_trip_points(struct thermal_zone_device *);
#else
static inline int of_parse_thermal_zones(void) { return 0; }
static inline void of_thermal_destroy_zones(void) 
static inline int of_thermal_get_ntrips(struct thermal_zone_device *tz)
{
    return 0;
}
static inline bool of_thermal_is_trip_valid(struct thermal_zone_device *tz,
                        int trip)
{
    return false;
}
static inline const struct thermal_trip *
of_thermal_get_trip_points(struct thermal_zone_device *tz)
{
    return NULL;
}
#endif

#endif /* __THERMAL_CORE_H__ */

在thermal_core.c除了以上函数的具体实现,还包括一些其它函数,首先看一下thermal的初始化函数thermal\_init()函数:

static int __init thermal_init(void)
{
    int result;

    result = thermal_register_governors();    // 注册governor
    if (result)
        goto error;

    result = class_register(&thermal_class);    // 注册/sys/class/thermal
    if (result)
        goto unregister_governors;

    result = genetlink_init();        // generic netlink初始化,干嘛的?
    if (result)
        goto unregister_class;

    result = of_parse_thermal_zones();    // 解析dts文件中的“thermal-zone”节点,并注册thermal_zone_device
    if (result)
        goto exit_netlink;

    result = register_pm_notifier(&thermal_pm_nb);    // 注册notifier
    if (result)
        pr_warn("Thermal: Can not register suspend notifier, return %d\n",
            result);

    return 0;

exit_netlink:
    genetlink_exit();
unregister_class:
    class_unregister(&thermal_class);
unregister_governors:
    thermal_unregister_governors();
error:
    idr_destroy(&thermal_tz_idr);
    idr_destroy(&thermal_cdev_idr);
    mutex_destroy(&thermal_idr_lock);
    mutex_destroy(&thermal_list_lock);
    mutex_destroy(&thermal_governor_lock);
    return result;
}

接下来,看一下of_parse_thermal_zones函数,我们从设备树文件中找个thermal-zones节点,如下所示

thermal-zones {
        soc_thermal {
            polling-delay = <1000>;
            polling-delay-passive = <100>;
            sustainable-power = <2150>;

            thermal-sensors = <&aml_sensor0 3>;

            trips {
                switch_on: trip-point@0 {
                    temperature = <70000>;
                    hysteresis = <1000>;
                    type = "passive";
                };
                control: trip-point@1 {
                    temperature = <80000>;
                    hysteresis = <1000>;
                    type = "passive";
                };
                hot: trip-point@2 {
                    temperature = <85000>;
                    hysteresis = <5000>;
                    type = "hot";
                };
                critical: trip-point@3 {
                    temperature = <260000>;
                    hysteresis = <1000>;
                    type = "critical";
                };
            };

            cooling-maps {
                cpufreq_cooling_map {
                    trip = <&control>;
                    cooling-device = <&cpus 0 4>;
                    contribution = <1024>;
                };
                cpucore_cooling_map {
                    trip = <&control>;
                    cooling-device = <&cpu_cluster0 0 3>;
                    contribution = <1024>;
                };
                gpufreq_cooling_map {
                    trip = <&control>;
                    cooling-device = <&gpu 0 4>;
                    contribution = <1024>;
                };
                gpucore_cooling_map {
                    trip = <&control>;
                    cooling-device = <&gpucore 0 2>;
                    contribution = <1024>;
                };
            };
        };
    };

}; /* end of / */

再看一下of\_parse\_thermal\_zones函数的具体实现,

/**
 * of_parse_thermal_zones - parse device tree thermal data
 *
 * Initialization function that can be called by machine initialization
 * code to parse thermal data and populate the thermal framework
 * with hardware thermal zones info. This function only parses thermal zones.
 * Cooling devices and sensor devices nodes are supposed to be parsed
 * by their respective drivers.
 *
 * Return: 0 on success, proper error code otherwise
 *
 */
int __init of_parse_thermal_zones(void)
{
    struct device_node *np, *child;
    struct __thermal_zone *tz;
    struct thermal_zone_device_ops *ops;

    np = of_find_node_by_name(NULL, "thermal-zones");
    if (!np) {
        pr_debug("unable to find thermal zones\n");
        return 0; /* Run successfully on systems without thermal DT */
    }

    for_each_available_child_of_node(np, child) {
        struct thermal_zone_device *zone;
        struct thermal_zone_params *tzp;
    #ifdef CONFIG_AMLOGIC_TEMP_SENSOR
        const char *str;
    #endif
        int i, mask = 0;
        u32 prop;

        tz = thermal_of_build_thermal_zone(child);
        if (IS_ERR(tz)) {
            pr_err("failed to build thermal zone %s: %ld\n",
                   child->name,
                   PTR_ERR(tz));
            continue;
        }

        ops = kmemdup(&of_thermal_ops, sizeof(*ops), GFP_KERNEL);
        if (!ops)
            goto exit_free;

        tzp = kzalloc(sizeof(*tzp), GFP_KERNEL);
        if (!tzp) {
            kfree(ops);
            goto exit_free;
        }

        /* No hwmon because there might be hwmon drivers registering */
        tzp->no_hwmon = true;

        if (!of_property_read_u32(child, "sustainable-power", &prop))
            tzp->sustainable_power = prop;

    #ifdef CONFIG_AMLOGIC_TEMP_SENSOR
        if (!of_property_read_string(child, "policy", &str))
            strncpy(tzp->governor_name, str, THERMAL_NAME_LENGTH);
    #endif

        for (i = 0; i < tz->ntrips; i++)
            mask |= 1 << i;

        /* these two are left for temperature drivers to use */
        tzp->slope = tz->slope;
        tzp->offset = tz->offset;
// 注册thermal_zone_device
        zone = thermal_zone_device_register(child->name, tz->ntrips,
                            mask, tz,
                            ops, tzp,
                            tz->passive_delay,
                            tz->polling_delay);
        if (IS_ERR(zone)) {
            pr_err("Failed to build %s zone %ld\n", child->name,
                   PTR_ERR(zone));
            kfree(tzp);
            kfree(ops);
            of_thermal_free_zone(tz);
            /* attempting to build remaining zones still */
        }
    }
    of_node_put(np);

    return 0;

exit_free:
    of_node_put(child);
    of_node_put(np);
    of_thermal_free_zone(tz);

    /* no memory available, so free what we have built */
    of_thermal_destroy_zones();

    return -ENOMEM;
}

在解析设备树函数中,将会调用thermal\_zone\_device设备注册函数,

0

评论 (0)

取消