0001
0002
0003
0004
0005
0006 #include <asm/tsc.h>
0007 #include <linux/cpufreq.h>
0008
0009 #include "i915_drv.h"
0010 #include "i915_reg.h"
0011 #include "intel_gt.h"
0012 #include "intel_llc.h"
0013 #include "intel_mchbar_regs.h"
0014 #include "intel_pcode.h"
0015 #include "intel_rps.h"
0016
0017 struct ia_constants {
0018 unsigned int min_gpu_freq;
0019 unsigned int max_gpu_freq;
0020
0021 unsigned int min_ring_freq;
0022 unsigned int max_ia_freq;
0023 };
0024
0025 static struct intel_gt *llc_to_gt(struct intel_llc *llc)
0026 {
0027 return container_of(llc, struct intel_gt, llc);
0028 }
0029
0030 static unsigned int cpu_max_MHz(void)
0031 {
0032 struct cpufreq_policy *policy;
0033 unsigned int max_khz;
0034
0035 policy = cpufreq_cpu_get(0);
0036 if (policy) {
0037 max_khz = policy->cpuinfo.max_freq;
0038 cpufreq_cpu_put(policy);
0039 } else {
0040
0041
0042
0043
0044 max_khz = tsc_khz;
0045 }
0046
0047 return max_khz / 1000;
0048 }
0049
0050 static bool get_ia_constants(struct intel_llc *llc,
0051 struct ia_constants *consts)
0052 {
0053 struct drm_i915_private *i915 = llc_to_gt(llc)->i915;
0054 struct intel_rps *rps = &llc_to_gt(llc)->rps;
0055
0056 if (!HAS_LLC(i915) || IS_DGFX(i915))
0057 return false;
0058
0059 consts->max_ia_freq = cpu_max_MHz();
0060
0061 consts->min_ring_freq =
0062 intel_uncore_read(llc_to_gt(llc)->uncore, DCLK) & 0xf;
0063
0064 consts->min_ring_freq = mult_frac(consts->min_ring_freq, 8, 3);
0065
0066 consts->min_gpu_freq = intel_rps_get_min_raw_freq(rps);
0067 consts->max_gpu_freq = intel_rps_get_max_raw_freq(rps);
0068
0069 return true;
0070 }
0071
0072 static void calc_ia_freq(struct intel_llc *llc,
0073 unsigned int gpu_freq,
0074 const struct ia_constants *consts,
0075 unsigned int *out_ia_freq,
0076 unsigned int *out_ring_freq)
0077 {
0078 struct drm_i915_private *i915 = llc_to_gt(llc)->i915;
0079 const int diff = consts->max_gpu_freq - gpu_freq;
0080 unsigned int ia_freq = 0, ring_freq = 0;
0081
0082 if (GRAPHICS_VER(i915) >= 9) {
0083
0084
0085
0086
0087 ring_freq = gpu_freq;
0088 } else if (GRAPHICS_VER(i915) >= 8) {
0089
0090 ring_freq = max(consts->min_ring_freq, gpu_freq);
0091 } else if (IS_HASWELL(i915)) {
0092 ring_freq = mult_frac(gpu_freq, 5, 4);
0093 ring_freq = max(consts->min_ring_freq, ring_freq);
0094
0095 } else {
0096 const int min_freq = 15;
0097 const int scale = 180;
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107 if (gpu_freq < min_freq)
0108 ia_freq = 800;
0109 else
0110 ia_freq = consts->max_ia_freq - diff * scale / 2;
0111 ia_freq = DIV_ROUND_CLOSEST(ia_freq, 100);
0112 }
0113
0114 *out_ia_freq = ia_freq;
0115 *out_ring_freq = ring_freq;
0116 }
0117
0118 static void gen6_update_ring_freq(struct intel_llc *llc)
0119 {
0120 struct ia_constants consts;
0121 unsigned int gpu_freq;
0122
0123 if (!get_ia_constants(llc, &consts))
0124 return;
0125
0126
0127
0128
0129
0130 if (consts.max_gpu_freq <= consts.min_gpu_freq)
0131 return;
0132
0133
0134
0135
0136
0137 for (gpu_freq = consts.max_gpu_freq;
0138 gpu_freq >= consts.min_gpu_freq;
0139 gpu_freq--) {
0140 unsigned int ia_freq, ring_freq;
0141
0142 calc_ia_freq(llc, gpu_freq, &consts, &ia_freq, &ring_freq);
0143 snb_pcode_write(llc_to_gt(llc)->uncore, GEN6_PCODE_WRITE_MIN_FREQ_TABLE,
0144 ia_freq << GEN6_PCODE_FREQ_IA_RATIO_SHIFT |
0145 ring_freq << GEN6_PCODE_FREQ_RING_RATIO_SHIFT |
0146 gpu_freq);
0147 }
0148 }
0149
0150 void intel_llc_enable(struct intel_llc *llc)
0151 {
0152 gen6_update_ring_freq(llc);
0153 }
0154
0155 void intel_llc_disable(struct intel_llc *llc)
0156 {
0157
0158 }
0159
0160 #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
0161 #include "selftest_llc.c"
0162 #endif