1 // SPDX-License-Identifier: MIT
2 /*
3 * Copyright © 2023 Intel Corporation
4 */
5
6 #include "xe_gt_freq.h"
7
8 #include <linux/kobject.h>
9 #include <linux/sysfs.h>
10
11 #include <drm/drm_managed.h>
12 #include <drm/drm_print.h>
13
14 #include "xe_gt_sysfs.h"
15 #include "xe_gt_throttle.h"
16 #include "xe_gt_types.h"
17 #include "xe_guc_pc.h"
18 #include "xe_pm.h"
19
20 /**
21 * DOC: Xe GT Frequency Management
22 *
23 * This component is responsible for the raw GT frequency management, including
24 * the sysfs API.
25 *
26 * Underneath, Xe enables GuC SLPC automated frequency management. GuC is then
27 * allowed to request PCODE any frequency between the Minimum and the Maximum
28 * selected by this component. Furthermore, it is important to highlight that
29 * PCODE is the ultimate decision maker of the actual running frequency, based
30 * on thermal and other running conditions.
31 *
32 * Xe's Freq provides a sysfs API for frequency management:
33 *
34 * device/tile#/gt#/freq0/<item>_freq *read-only* files:
35 *
36 * - act_freq: The actual resolved frequency decided by PCODE.
37 * - cur_freq: The current one requested by GuC PC to the PCODE.
38 * - rpn_freq: The Render Performance (RP) N level, which is the minimal one.
39 * - rpa_freq: The Render Performance (RP) A level, which is the achiveable one.
40 * Calculated by PCODE at runtime based on multiple running conditions
41 * - rpe_freq: The Render Performance (RP) E level, which is the efficient one.
42 * Calculated by PCODE at runtime based on multiple running conditions
43 * - rp0_freq: The Render Performance (RP) 0 level, which is the maximum one.
44 *
45 * device/tile#/gt#/freq0/<item>_freq *read-write* files:
46 *
47 * - min_freq: Min frequency request.
48 * - max_freq: Max frequency request.
49 * If max <= min, then freq_min becomes a fixed frequency request.
50 */
51
52 static struct xe_guc_pc *
dev_to_pc(struct device * dev)53 dev_to_pc(struct device *dev)
54 {
55 return &kobj_to_gt(dev->kobj.parent)->uc.guc.pc;
56 }
57
58 static struct xe_device *
dev_to_xe(struct device * dev)59 dev_to_xe(struct device *dev)
60 {
61 return gt_to_xe(kobj_to_gt(dev->kobj.parent));
62 }
63
act_freq_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)64 static ssize_t act_freq_show(struct kobject *kobj,
65 struct kobj_attribute *attr, char *buf)
66 {
67 struct device *dev = kobj_to_dev(kobj);
68 struct xe_guc_pc *pc = dev_to_pc(dev);
69 u32 freq;
70
71 xe_pm_runtime_get(dev_to_xe(dev));
72 freq = xe_guc_pc_get_act_freq(pc);
73 xe_pm_runtime_put(dev_to_xe(dev));
74
75 return sysfs_emit(buf, "%d\n", freq);
76 }
77 static struct kobj_attribute attr_act_freq = __ATTR_RO(act_freq);
78
cur_freq_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)79 static ssize_t cur_freq_show(struct kobject *kobj,
80 struct kobj_attribute *attr, char *buf)
81 {
82 struct device *dev = kobj_to_dev(kobj);
83 struct xe_guc_pc *pc = dev_to_pc(dev);
84 u32 freq;
85 ssize_t ret;
86
87 xe_pm_runtime_get(dev_to_xe(dev));
88 ret = xe_guc_pc_get_cur_freq(pc, &freq);
89 xe_pm_runtime_put(dev_to_xe(dev));
90 if (ret)
91 return ret;
92
93 return sysfs_emit(buf, "%d\n", freq);
94 }
95 static struct kobj_attribute attr_cur_freq = __ATTR_RO(cur_freq);
96
rp0_freq_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)97 static ssize_t rp0_freq_show(struct kobject *kobj,
98 struct kobj_attribute *attr, char *buf)
99 {
100 struct device *dev = kobj_to_dev(kobj);
101 struct xe_guc_pc *pc = dev_to_pc(dev);
102 u32 freq;
103
104 xe_pm_runtime_get(dev_to_xe(dev));
105 freq = xe_guc_pc_get_rp0_freq(pc);
106 xe_pm_runtime_put(dev_to_xe(dev));
107
108 return sysfs_emit(buf, "%d\n", freq);
109 }
110 static struct kobj_attribute attr_rp0_freq = __ATTR_RO(rp0_freq);
111
rpe_freq_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)112 static ssize_t rpe_freq_show(struct kobject *kobj,
113 struct kobj_attribute *attr, char *buf)
114 {
115 struct device *dev = kobj_to_dev(kobj);
116 struct xe_guc_pc *pc = dev_to_pc(dev);
117 u32 freq;
118
119 xe_pm_runtime_get(dev_to_xe(dev));
120 freq = xe_guc_pc_get_rpe_freq(pc);
121 xe_pm_runtime_put(dev_to_xe(dev));
122
123 return sysfs_emit(buf, "%d\n", freq);
124 }
125 static struct kobj_attribute attr_rpe_freq = __ATTR_RO(rpe_freq);
126
rpa_freq_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)127 static ssize_t rpa_freq_show(struct kobject *kobj,
128 struct kobj_attribute *attr, char *buf)
129 {
130 struct device *dev = kobj_to_dev(kobj);
131 struct xe_guc_pc *pc = dev_to_pc(dev);
132 u32 freq;
133
134 xe_pm_runtime_get(dev_to_xe(dev));
135 freq = xe_guc_pc_get_rpa_freq(pc);
136 xe_pm_runtime_put(dev_to_xe(dev));
137
138 return sysfs_emit(buf, "%d\n", freq);
139 }
140 static struct kobj_attribute attr_rpa_freq = __ATTR_RO(rpa_freq);
141
rpn_freq_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)142 static ssize_t rpn_freq_show(struct kobject *kobj,
143 struct kobj_attribute *attr, char *buf)
144 {
145 struct device *dev = kobj_to_dev(kobj);
146 struct xe_guc_pc *pc = dev_to_pc(dev);
147
148 return sysfs_emit(buf, "%d\n", xe_guc_pc_get_rpn_freq(pc));
149 }
150 static struct kobj_attribute attr_rpn_freq = __ATTR_RO(rpn_freq);
151
min_freq_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)152 static ssize_t min_freq_show(struct kobject *kobj,
153 struct kobj_attribute *attr, char *buf)
154 {
155 struct device *dev = kobj_to_dev(kobj);
156 struct xe_guc_pc *pc = dev_to_pc(dev);
157 u32 freq;
158 ssize_t ret;
159
160 xe_pm_runtime_get(dev_to_xe(dev));
161 ret = xe_guc_pc_get_min_freq(pc, &freq);
162 xe_pm_runtime_put(dev_to_xe(dev));
163 if (ret)
164 return ret;
165
166 return sysfs_emit(buf, "%d\n", freq);
167 }
168
min_freq_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buff,size_t count)169 static ssize_t min_freq_store(struct kobject *kobj,
170 struct kobj_attribute *attr, const char *buff, size_t count)
171 {
172 struct device *dev = kobj_to_dev(kobj);
173 struct xe_guc_pc *pc = dev_to_pc(dev);
174 u32 freq;
175 ssize_t ret;
176
177 ret = kstrtou32(buff, 0, &freq);
178 if (ret)
179 return ret;
180
181 xe_pm_runtime_get(dev_to_xe(dev));
182 ret = xe_guc_pc_set_min_freq(pc, freq);
183 xe_pm_runtime_put(dev_to_xe(dev));
184 if (ret)
185 return ret;
186
187 return count;
188 }
189 static struct kobj_attribute attr_min_freq = __ATTR_RW(min_freq);
190
max_freq_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)191 static ssize_t max_freq_show(struct kobject *kobj,
192 struct kobj_attribute *attr, char *buf)
193 {
194 struct device *dev = kobj_to_dev(kobj);
195 struct xe_guc_pc *pc = dev_to_pc(dev);
196 u32 freq;
197 ssize_t ret;
198
199 xe_pm_runtime_get(dev_to_xe(dev));
200 ret = xe_guc_pc_get_max_freq(pc, &freq);
201 xe_pm_runtime_put(dev_to_xe(dev));
202 if (ret)
203 return ret;
204
205 return sysfs_emit(buf, "%d\n", freq);
206 }
207
max_freq_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buff,size_t count)208 static ssize_t max_freq_store(struct kobject *kobj,
209 struct kobj_attribute *attr, const char *buff, size_t count)
210 {
211 struct device *dev = kobj_to_dev(kobj);
212 struct xe_guc_pc *pc = dev_to_pc(dev);
213 u32 freq;
214 ssize_t ret;
215
216 ret = kstrtou32(buff, 0, &freq);
217 if (ret)
218 return ret;
219
220 xe_pm_runtime_get(dev_to_xe(dev));
221 ret = xe_guc_pc_set_max_freq(pc, freq);
222 xe_pm_runtime_put(dev_to_xe(dev));
223 if (ret)
224 return ret;
225
226 return count;
227 }
228 static struct kobj_attribute attr_max_freq = __ATTR_RW(max_freq);
229
230 static const struct attribute *freq_attrs[] = {
231 &attr_act_freq.attr,
232 &attr_cur_freq.attr,
233 &attr_rp0_freq.attr,
234 &attr_rpa_freq.attr,
235 &attr_rpe_freq.attr,
236 &attr_rpn_freq.attr,
237 &attr_min_freq.attr,
238 &attr_max_freq.attr,
239 NULL
240 };
241
freq_fini(void * arg)242 static void freq_fini(void *arg)
243 {
244 struct kobject *kobj = arg;
245
246 sysfs_remove_files(kobj, freq_attrs);
247 kobject_put(kobj);
248 }
249
250 /**
251 * xe_gt_freq_init - Initialize Xe Freq component
252 * @gt: Xe GT object
253 *
254 * It needs to be initialized after GT Sysfs and GuC PC components are ready.
255 *
256 * Returns: Returns error value for failure and 0 for success.
257 */
xe_gt_freq_init(struct xe_gt * gt)258 int xe_gt_freq_init(struct xe_gt *gt)
259 {
260 struct xe_device *xe = gt_to_xe(gt);
261 int err;
262
263 if (xe->info.skip_guc_pc)
264 return 0;
265
266 gt->freq = kobject_create_and_add("freq0", gt->sysfs);
267 if (!gt->freq)
268 return -ENOMEM;
269
270 err = sysfs_create_files(gt->freq, freq_attrs);
271 if (err)
272 return err;
273
274 err = devm_add_action_or_reset(xe->drm.dev, freq_fini, gt->freq);
275 if (err)
276 return err;
277
278 return xe_gt_throttle_init(gt);
279 }
280