summaryrefslogtreecommitdiff
path: root/gcip-kernel-driver/include/gcip/gcip-thermal.h
blob: 7c9ebc481454b8b76fd647290eb0c132855085f5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Thermal management support for GCIP devices.
 *
 * Copyright (C) 2023 Google LLC
 */

#ifndef __GCIP_THERMAL_H__
#define __GCIP_THERMAL_H__

#include <linux/device.h>
#include <linux/mutex.h>
#include <linux/notifier.h>
#include <linux/thermal.h>

#define GCIP_THERMAL_TABLE_SIZE_NAME "gcip-dvfs-table-size"
#define GCIP_THERMAL_TABLE_NAME "gcip-dvfs-table"
#define GCIP_THERMAL_MAX_NUM_STATES 10

enum gcip_thermal_voter {
	GCIP_THERMAL_COOLING_DEVICE,
	GCIP_THERMAL_SYSFS,
	GCIP_THERMAL_NOTIFIER_BLOCK,

	/* Keeps as the last entry for the total number of voters. */
	GCIP_THERMAL_MAX_NUM_VOTERS,
};

struct gcip_thermal {
	struct device *dev;
	struct thermal_cooling_device *cdev;
	struct notifier_block nb;
	struct dentry *dentry;
	struct gcip_pm *pm;

	/*
	 * Lock to protect the struct members listed below.
	 *
	 * Note that since the request of thermal state adjusting might happen during power state
	 * transitions (i.e., another thread calling gcip_thermal_restore_on_powering() with pm lock
	 * held), one must either use the non-blocking gcip_pm_get_if_powered() or make sure there
	 * won't be any new power transition after holding this thermal lock to prevent deadlock.
	 */
	struct mutex lock;
	unsigned long num_states;
	unsigned long state;
	unsigned long vote[GCIP_THERMAL_MAX_NUM_VOTERS];
	bool device_suspended;
	bool enabled;

	/* Private data. See struct gcip_thermal_args.*/
	void *data;

	/* Callbacks. See struct gcip_thermal_args. */
	int (*get_rate)(void *data, unsigned long *rate);
	int (*set_rate)(void *data, unsigned long rate);
	int (*control)(void *data, bool enable);
};

/* Arguments for devm_gcip_thermal_create. */
struct gcip_thermal_args {
	/* Device struct of GCIP device. */
	struct device *dev;
	/* GCIP power management. */
	struct gcip_pm *pm;
	/* Top-level debugfs directory for the device. */
	struct dentry *dentry;
	/* Name of the thermal cooling-device node in device tree. */
	const char *node_name;
	/* Thermal cooling device type for thermal_of_cooling_device_register() . */
	const char *type;
	/* Private data for callbacks listed below. */
	void *data;
	/*
	 * Callbacks listed below are called only if the device is powered and with the guarantee
	 * that there won't be any new power transition during the call (i.e., after
	 * gcip_pm_get_if_powered() succeeds or during the power up triggered by gcip_pm_get())
	 * to prevent deadlock since they are called with thermal lock held. See the note about
	 * thermal lock in struct gcip_thermal.
	 */
	/* Callback to get the device clock rate. */
	int (*get_rate)(void *data, unsigned long *rate);
	/*
	 * Callback to set the device clock rate.
	 * Might be called with pm lock held in gcip_thermal_restore_on_powering().
	 */
	int (*set_rate)(void *data, unsigned long rate);
	/*
	 * Callback to enable/disable the thermal control.
	 * Might be called with pm lock held in gcip_thermal_restore_on_powering().
	 */
	int (*control)(void *data, bool enable);
};

/* Gets the notifier_block struct for thermal throttling requests. */
struct notifier_block *gcip_thermal_get_notifier_block(struct gcip_thermal *thermal);
/* Allocates and initializes GCIP thermal struct. */
struct gcip_thermal *gcip_thermal_create(const struct gcip_thermal_args *args);
/* Destroys and frees GCIP thermal struct. */
void gcip_thermal_destroy(struct gcip_thermal *thermal);
/* Suspends the device due to thermal request. */
int gcip_thermal_suspend_device(struct gcip_thermal *thermal);
/* Resumes the device and restores previous thermal state. */
int gcip_thermal_resume_device(struct gcip_thermal *thermal);
/*
 * Checks whether the device is suspended by thermal.
 * Note that it's checked without thermal lock and state might change subsequently.
 */
bool gcip_thermal_is_device_suspended(struct gcip_thermal *thermal);
/*
 * Restores the previous thermal state.
 *
 * This function is designed to restore the thermal state during power management calls and thus it
 * assumes the caller holds the pm lock.
 */
int gcip_thermal_restore_on_powering(struct gcip_thermal *thermal);

#endif /* __GCIP_THERMAL_H__ */