250 lines · c
1// SPDX-License-Identifier: MIT2/*3 * Copyright © 2023 Intel Corporation4 */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_device_types.h"15#include "xe_gt_sysfs.h"16#include "xe_gt_throttle.h"17#include "xe_guc_pc.h"18#include "xe_pm.h"19 20/**21 * DOC: Xe GT Frequency Management22 *23 * This component is responsible for the raw GT frequency management, including24 * the sysfs API.25 *26 * Underneath, Xe enables GuC SLPC automated frequency management. GuC is then27 * allowed to request PCODE any frequency between the Minimum and the Maximum28 * selected by this component. Furthermore, it is important to highlight that29 * PCODE is the ultimate decision maker of the actual running frequency, based30 * 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 * - act_freq: The actual resolved frequency decided by PCODE.36 * - cur_freq: The current one requested by GuC PC to the PCODE.37 * - rpn_freq: The Render Performance (RP) N level, which is the minimal one.38 * - rpe_freq: The Render Performance (RP) E level, which is the efficient one.39 * - rp0_freq: The Render Performance (RP) 0 level, which is the maximum one.40 *41 * device/tile#/gt#/freq0/<item>_freq *read-write* files:42 * - min_freq: Min frequency request.43 * - max_freq: Max frequency request.44 * If max <= min, then freq_min becomes a fixed frequency request.45 */46 47static struct xe_guc_pc *48dev_to_pc(struct device *dev)49{50 return &kobj_to_gt(dev->kobj.parent)->uc.guc.pc;51}52 53static struct xe_device *54dev_to_xe(struct device *dev)55{56 return gt_to_xe(kobj_to_gt(dev->kobj.parent));57}58 59static ssize_t act_freq_show(struct device *dev,60 struct device_attribute *attr, char *buf)61{62 struct xe_guc_pc *pc = dev_to_pc(dev);63 u32 freq;64 65 xe_pm_runtime_get(dev_to_xe(dev));66 freq = xe_guc_pc_get_act_freq(pc);67 xe_pm_runtime_put(dev_to_xe(dev));68 69 return sysfs_emit(buf, "%d\n", freq);70}71static DEVICE_ATTR_RO(act_freq);72 73static ssize_t cur_freq_show(struct device *dev,74 struct device_attribute *attr, char *buf)75{76 struct xe_guc_pc *pc = dev_to_pc(dev);77 u32 freq;78 ssize_t ret;79 80 xe_pm_runtime_get(dev_to_xe(dev));81 ret = xe_guc_pc_get_cur_freq(pc, &freq);82 xe_pm_runtime_put(dev_to_xe(dev));83 if (ret)84 return ret;85 86 return sysfs_emit(buf, "%d\n", freq);87}88static DEVICE_ATTR_RO(cur_freq);89 90static ssize_t rp0_freq_show(struct device *dev,91 struct device_attribute *attr, char *buf)92{93 struct xe_guc_pc *pc = dev_to_pc(dev);94 u32 freq;95 96 xe_pm_runtime_get(dev_to_xe(dev));97 freq = xe_guc_pc_get_rp0_freq(pc);98 xe_pm_runtime_put(dev_to_xe(dev));99 100 return sysfs_emit(buf, "%d\n", freq);101}102static DEVICE_ATTR_RO(rp0_freq);103 104static ssize_t rpe_freq_show(struct device *dev,105 struct device_attribute *attr, char *buf)106{107 struct xe_guc_pc *pc = dev_to_pc(dev);108 u32 freq;109 110 xe_pm_runtime_get(dev_to_xe(dev));111 freq = xe_guc_pc_get_rpe_freq(pc);112 xe_pm_runtime_put(dev_to_xe(dev));113 114 return sysfs_emit(buf, "%d\n", freq);115}116static DEVICE_ATTR_RO(rpe_freq);117 118static ssize_t rpn_freq_show(struct device *dev,119 struct device_attribute *attr, char *buf)120{121 struct xe_guc_pc *pc = dev_to_pc(dev);122 123 return sysfs_emit(buf, "%d\n", xe_guc_pc_get_rpn_freq(pc));124}125static DEVICE_ATTR_RO(rpn_freq);126 127static ssize_t min_freq_show(struct device *dev,128 struct device_attribute *attr, char *buf)129{130 struct xe_guc_pc *pc = dev_to_pc(dev);131 u32 freq;132 ssize_t ret;133 134 xe_pm_runtime_get(dev_to_xe(dev));135 ret = xe_guc_pc_get_min_freq(pc, &freq);136 xe_pm_runtime_put(dev_to_xe(dev));137 if (ret)138 return ret;139 140 return sysfs_emit(buf, "%d\n", freq);141}142 143static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,144 const char *buff, size_t count)145{146 struct xe_guc_pc *pc = dev_to_pc(dev);147 u32 freq;148 ssize_t ret;149 150 ret = kstrtou32(buff, 0, &freq);151 if (ret)152 return ret;153 154 xe_pm_runtime_get(dev_to_xe(dev));155 ret = xe_guc_pc_set_min_freq(pc, freq);156 xe_pm_runtime_put(dev_to_xe(dev));157 if (ret)158 return ret;159 160 return count;161}162static DEVICE_ATTR_RW(min_freq);163 164static ssize_t max_freq_show(struct device *dev,165 struct device_attribute *attr, char *buf)166{167 struct xe_guc_pc *pc = dev_to_pc(dev);168 u32 freq;169 ssize_t ret;170 171 xe_pm_runtime_get(dev_to_xe(dev));172 ret = xe_guc_pc_get_max_freq(pc, &freq);173 xe_pm_runtime_put(dev_to_xe(dev));174 if (ret)175 return ret;176 177 return sysfs_emit(buf, "%d\n", freq);178}179 180static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,181 const char *buff, size_t count)182{183 struct xe_guc_pc *pc = dev_to_pc(dev);184 u32 freq;185 ssize_t ret;186 187 ret = kstrtou32(buff, 0, &freq);188 if (ret)189 return ret;190 191 xe_pm_runtime_get(dev_to_xe(dev));192 ret = xe_guc_pc_set_max_freq(pc, freq);193 xe_pm_runtime_put(dev_to_xe(dev));194 if (ret)195 return ret;196 197 return count;198}199static DEVICE_ATTR_RW(max_freq);200 201static const struct attribute *freq_attrs[] = {202 &dev_attr_act_freq.attr,203 &dev_attr_cur_freq.attr,204 &dev_attr_rp0_freq.attr,205 &dev_attr_rpe_freq.attr,206 &dev_attr_rpn_freq.attr,207 &dev_attr_min_freq.attr,208 &dev_attr_max_freq.attr,209 NULL210};211 212static void freq_fini(void *arg)213{214 struct kobject *kobj = arg;215 216 sysfs_remove_files(kobj, freq_attrs);217 kobject_put(kobj);218}219 220/**221 * xe_gt_freq_init - Initialize Xe Freq component222 * @gt: Xe GT object223 *224 * It needs to be initialized after GT Sysfs and GuC PC components are ready.225 *226 * Returns: Returns error value for failure and 0 for success.227 */228int xe_gt_freq_init(struct xe_gt *gt)229{230 struct xe_device *xe = gt_to_xe(gt);231 int err;232 233 if (xe->info.skip_guc_pc)234 return 0;235 236 gt->freq = kobject_create_and_add("freq0", gt->sysfs);237 if (!gt->freq)238 return -ENOMEM;239 240 err = sysfs_create_files(gt->freq, freq_attrs);241 if (err)242 return err;243 244 err = devm_add_action_or_reset(xe->drm.dev, freq_fini, gt->freq);245 if (err)246 return err;247 248 return xe_gt_throttle_init(gt);249}250