File Index
Files and directories
Sign in
FILE

xe_gt_freq.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/xe/xe_gt_freq.c C
  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 under
 33 * ``<device>/tile#/gt#/freq0/`` directory.
 34 *
 35 * **Read-only** attributes:
 36 *
 37 * - ``act_freq``: The actual resolved frequency decided by PCODE.
 38 * - ``cur_freq``: The current one requested by GuC PC to the PCODE.
 39 * - ``rpn_freq``: The Render Performance (RP) N level, which is the minimal one.
 40 * - ``rpa_freq``: The Render Performance (RP) A level, which is the achievable one.
 41 *                 Calculated by PCODE at runtime based on multiple running conditions
 42 * - ``rpe_freq``: The Render Performance (RP) E level, which is the efficient one.
 43 *                 Calculated by PCODE at runtime based on multiple running conditions
 44 * - ``rp0_freq``: The Render Performance (RP) 0 level, which is the maximum one.
 45 *
 46 * **Read-write** attributes:
 47 *
 48 * - ``min_freq``: Min frequency request.
 49 * - ``max_freq``: Max frequency request.
 50 *                 If max <= min, then freq_min becomes a fixed frequency
 51 *                 request.
 52 */
 53
 54static struct xe_guc_pc *
 55dev_to_pc(struct device *dev)
 56{
 57	return &kobj_to_gt(dev->kobj.parent)->uc.guc.pc;
 58}
 59
 60static struct xe_device *
 61dev_to_xe(struct device *dev)
 62{
 63	return gt_to_xe(kobj_to_gt(dev->kobj.parent));
 64}
 65
 66static ssize_t act_freq_show(struct kobject *kobj,
 67			     struct kobj_attribute *attr, char *buf)
 68{
 69	struct device *dev = kobj_to_dev(kobj);
 70	struct xe_guc_pc *pc = dev_to_pc(dev);
 71	u32 freq;
 72
 73	xe_pm_runtime_get(dev_to_xe(dev));
 74	freq = xe_guc_pc_get_act_freq(pc);
 75	xe_pm_runtime_put(dev_to_xe(dev));
 76
 77	return sysfs_emit(buf, "%d\n", freq);
 78}
 79static struct kobj_attribute attr_act_freq = __ATTR_RO(act_freq);
 80
 81static ssize_t cur_freq_show(struct kobject *kobj,
 82			     struct kobj_attribute *attr, char *buf)
 83{
 84	struct device *dev = kobj_to_dev(kobj);
 85	struct xe_guc_pc *pc = dev_to_pc(dev);
 86	u32 freq;
 87	ssize_t ret;
 88
 89	xe_pm_runtime_get(dev_to_xe(dev));
 90	ret = xe_guc_pc_get_cur_freq(pc, &freq);
 91	xe_pm_runtime_put(dev_to_xe(dev));
 92	if (ret)
 93		return ret;
 94
 95	return sysfs_emit(buf, "%d\n", freq);
 96}
 97static struct kobj_attribute attr_cur_freq = __ATTR_RO(cur_freq);
 98
 99static ssize_t rp0_freq_show(struct kobject *kobj,
100			     struct kobj_attribute *attr, char *buf)
101{
102	struct device *dev = kobj_to_dev(kobj);
103	struct xe_guc_pc *pc = dev_to_pc(dev);
104
105	return sysfs_emit(buf, "%d\n", xe_guc_pc_get_rp0_freq(pc));
106}
107static struct kobj_attribute attr_rp0_freq = __ATTR_RO(rp0_freq);
108
109static ssize_t rpe_freq_show(struct kobject *kobj,
110			     struct kobj_attribute *attr, char *buf)
111{
112	struct device *dev = kobj_to_dev(kobj);
113	struct xe_guc_pc *pc = dev_to_pc(dev);
114	u32 freq;
115
116	xe_pm_runtime_get(dev_to_xe(dev));
117	freq = xe_guc_pc_get_rpe_freq(pc);
118	xe_pm_runtime_put(dev_to_xe(dev));
119
120	return sysfs_emit(buf, "%d\n", freq);
121}
122static struct kobj_attribute attr_rpe_freq = __ATTR_RO(rpe_freq);
123
124static ssize_t rpa_freq_show(struct kobject *kobj,
125			     struct kobj_attribute *attr, char *buf)
126{
127	struct device *dev = kobj_to_dev(kobj);
128	struct xe_guc_pc *pc = dev_to_pc(dev);
129	u32 freq;
130
131	xe_pm_runtime_get(dev_to_xe(dev));
132	freq = xe_guc_pc_get_rpa_freq(pc);
133	xe_pm_runtime_put(dev_to_xe(dev));
134
135	return sysfs_emit(buf, "%d\n", freq);
136}
137static struct kobj_attribute attr_rpa_freq = __ATTR_RO(rpa_freq);
138
139static ssize_t rpn_freq_show(struct kobject *kobj,
140			     struct kobj_attribute *attr, char *buf)
141{
142	struct device *dev = kobj_to_dev(kobj);
143	struct xe_guc_pc *pc = dev_to_pc(dev);
144
145	return sysfs_emit(buf, "%d\n", xe_guc_pc_get_rpn_freq(pc));
146}
147static struct kobj_attribute attr_rpn_freq = __ATTR_RO(rpn_freq);
148
149static ssize_t min_freq_show(struct kobject *kobj,
150			     struct kobj_attribute *attr, char *buf)
151{
152	struct device *dev = kobj_to_dev(kobj);
153	struct xe_guc_pc *pc = dev_to_pc(dev);
154	u32 freq;
155	ssize_t ret;
156
157	xe_pm_runtime_get(dev_to_xe(dev));
158	ret = xe_guc_pc_get_min_freq(pc, &freq);
159	xe_pm_runtime_put(dev_to_xe(dev));
160	if (ret)
161		return ret;
162
163	return sysfs_emit(buf, "%d\n", freq);
164}
165
166static ssize_t min_freq_store(struct kobject *kobj,
167			      struct kobj_attribute *attr, const char *buff, size_t count)
168{
169	struct device *dev = kobj_to_dev(kobj);
170	struct xe_guc_pc *pc = dev_to_pc(dev);
171	u32 freq;
172	ssize_t ret;
173
174	ret = kstrtou32(buff, 0, &freq);
175	if (ret)
176		return ret;
177
178	xe_pm_runtime_get(dev_to_xe(dev));
179	ret = xe_guc_pc_set_min_freq(pc, freq);
180	xe_pm_runtime_put(dev_to_xe(dev));
181	if (ret)
182		return ret;
183
184	return count;
185}
186static struct kobj_attribute attr_min_freq = __ATTR_RW(min_freq);
187
188static ssize_t max_freq_show(struct kobject *kobj,
189			     struct kobj_attribute *attr, char *buf)
190{
191	struct device *dev = kobj_to_dev(kobj);
192	struct xe_guc_pc *pc = dev_to_pc(dev);
193	u32 freq;
194	ssize_t ret;
195
196	xe_pm_runtime_get(dev_to_xe(dev));
197	ret = xe_guc_pc_get_max_freq(pc, &freq);
198	xe_pm_runtime_put(dev_to_xe(dev));
199	if (ret)
200		return ret;
201
202	return sysfs_emit(buf, "%d\n", freq);
203}
204
205static ssize_t max_freq_store(struct kobject *kobj,
206			      struct kobj_attribute *attr, const char *buff, size_t count)
207{
208	struct device *dev = kobj_to_dev(kobj);
209	struct xe_guc_pc *pc = dev_to_pc(dev);
210	u32 freq;
211	ssize_t ret;
212
213	ret = kstrtou32(buff, 0, &freq);
214	if (ret)
215		return ret;
216
217	xe_pm_runtime_get(dev_to_xe(dev));
218	ret = xe_guc_pc_set_max_freq(pc, freq);
219	xe_pm_runtime_put(dev_to_xe(dev));
220	if (ret)
221		return ret;
222
223	return count;
224}
225static struct kobj_attribute attr_max_freq = __ATTR_RW(max_freq);
226
227static ssize_t power_profile_show(struct kobject *kobj,
228				  struct kobj_attribute *attr,
229				  char *buff)
230{
231	struct device *dev = kobj_to_dev(kobj);
232
233	xe_guc_pc_get_power_profile(dev_to_pc(dev), buff);
234
235	return strlen(buff);
236}
237
238static ssize_t power_profile_store(struct kobject *kobj,
239				   struct kobj_attribute *attr,
240				   const char *buff, size_t count)
241{
242	struct device *dev = kobj_to_dev(kobj);
243	struct xe_guc_pc *pc = dev_to_pc(dev);
244	int err;
245
246	xe_pm_runtime_get(dev_to_xe(dev));
247	err = xe_guc_pc_set_power_profile(pc, buff);
248	xe_pm_runtime_put(dev_to_xe(dev));
249
250	return err ?: count;
251}
252static struct kobj_attribute attr_power_profile = __ATTR_RW(power_profile);
253
254static const struct attribute *freq_attrs[] = {
255	&attr_act_freq.attr,
256	&attr_cur_freq.attr,
257	&attr_rp0_freq.attr,
258	&attr_rpa_freq.attr,
259	&attr_rpe_freq.attr,
260	&attr_rpn_freq.attr,
261	&attr_min_freq.attr,
262	&attr_max_freq.attr,
263	&attr_power_profile.attr,
264	NULL
265};
266
267static void freq_fini(void *arg)
268{
269	struct kobject *kobj = arg;
270
271	sysfs_remove_files(kobj, freq_attrs);
272	kobject_put(kobj);
273}
274
275/**
276 * xe_gt_freq_init - Initialize Xe Freq component
277 * @gt: Xe GT object
278 *
279 * It needs to be initialized after GT Sysfs and GuC PC components are ready.
280 *
281 * Returns: Returns error value for failure and 0 for success.
282 */
283int xe_gt_freq_init(struct xe_gt *gt)
284{
285	struct xe_device *xe = gt_to_xe(gt);
286	int err;
287
288	if (xe->info.skip_guc_pc)
289		return 0;
290
291	gt->freq = kobject_create_and_add("freq0", gt->sysfs);
292	if (!gt->freq)
293		return -ENOMEM;
294
295	err = sysfs_create_files(gt->freq, freq_attrs);
296	if (err) {
297		kobject_put(gt->freq);
298		return err;
299	}
300
301	err = devm_add_action_or_reset(xe->drm.dev, freq_fini, gt->freq);
302	if (err)
303		return err;
304
305	return xe_gt_throttle_init(gt);
306}
~/ Read-only file preview.