1 /* 2 * Copyright © 2012 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 * 23 * Authors: 24 * Ben Widawsky <ben@bwidawsk.net> 25 * 26 */ 27 28 #include <linux/device.h> 29 #include <linux/module.h> 30 #include <linux/stat.h> 31 #include <linux/sysfs.h> 32 #include "intel_drv.h" 33 #include "i915_drv.h" 34 35 #ifdef CONFIG_PM 36 static u32 calc_residency(struct drm_device *dev, const u32 reg) 37 { 38 struct drm_i915_private *dev_priv = dev->dev_private; 39 u64 raw_time; /* 32b value may overflow during fixed point math */ 40 41 if (!intel_enable_rc6(dev)) 42 return 0; 43 44 raw_time = I915_READ(reg) * 128ULL; 45 return DIV_ROUND_UP_ULL(raw_time, 100000); 46 } 47 48 static ssize_t 49 show_rc6_mask(struct device *dev, struct device_attribute *attr, char *buf) 50 { 51 struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev); 52 return snprintf(buf, PAGE_SIZE, "%x", intel_enable_rc6(dminor->dev)); 53 } 54 55 static ssize_t 56 show_rc6_ms(struct device *dev, struct device_attribute *attr, char *buf) 57 { 58 struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev); 59 u32 rc6_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6); 60 return snprintf(buf, PAGE_SIZE, "%u", rc6_residency); 61 } 62 63 static ssize_t 64 show_rc6p_ms(struct device *dev, struct device_attribute *attr, char *buf) 65 { 66 struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev); 67 u32 rc6p_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6p); 68 return snprintf(buf, PAGE_SIZE, "%u", rc6p_residency); 69 } 70 71 static ssize_t 72 show_rc6pp_ms(struct device *dev, struct device_attribute *attr, char *buf) 73 { 74 struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev); 75 u32 rc6pp_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6pp); 76 return snprintf(buf, PAGE_SIZE, "%u", rc6pp_residency); 77 } 78 79 static DEVICE_ATTR(rc6_enable, S_IRUGO, show_rc6_mask, NULL); 80 static DEVICE_ATTR(rc6_residency_ms, S_IRUGO, show_rc6_ms, NULL); 81 static DEVICE_ATTR(rc6p_residency_ms, S_IRUGO, show_rc6p_ms, NULL); 82 static DEVICE_ATTR(rc6pp_residency_ms, S_IRUGO, show_rc6pp_ms, NULL); 83 84 static struct attribute *rc6_attrs[] = { 85 &dev_attr_rc6_enable.attr, 86 &dev_attr_rc6_residency_ms.attr, 87 &dev_attr_rc6p_residency_ms.attr, 88 &dev_attr_rc6pp_residency_ms.attr, 89 NULL 90 }; 91 92 static struct attribute_group rc6_attr_group = { 93 .name = power_group_name, 94 .attrs = rc6_attrs 95 }; 96 97 static int l3_access_valid(struct drm_device *dev, loff_t offset) 98 { 99 if (!IS_IVYBRIDGE(dev)) 100 return -EPERM; 101 102 if (offset % 4 != 0) 103 return -EINVAL; 104 105 if (offset >= GEN7_L3LOG_SIZE) 106 return -ENXIO; 107 108 return 0; 109 } 110 111 static ssize_t 112 i915_l3_read(struct file *filp, struct kobject *kobj, 113 struct bin_attribute *attr, char *buf, 114 loff_t offset, size_t count) 115 { 116 struct device *dev = container_of(kobj, struct device, kobj); 117 struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev); 118 struct drm_device *drm_dev = dminor->dev; 119 struct drm_i915_private *dev_priv = drm_dev->dev_private; 120 uint32_t misccpctl; 121 int i, ret; 122 123 ret = l3_access_valid(drm_dev, offset); 124 if (ret) 125 return ret; 126 127 ret = i915_mutex_lock_interruptible(drm_dev); 128 if (ret) 129 return ret; 130 131 misccpctl = I915_READ(GEN7_MISCCPCTL); 132 I915_WRITE(GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE); 133 134 for (i = offset; count >= 4 && i < GEN7_L3LOG_SIZE; i += 4, count -= 4) 135 *((uint32_t *)(&buf[i])) = I915_READ(GEN7_L3LOG_BASE + i); 136 137 I915_WRITE(GEN7_MISCCPCTL, misccpctl); 138 139 mutex_unlock(&drm_dev->struct_mutex); 140 141 return i - offset; 142 } 143 144 static ssize_t 145 i915_l3_write(struct file *filp, struct kobject *kobj, 146 struct bin_attribute *attr, char *buf, 147 loff_t offset, size_t count) 148 { 149 struct device *dev = container_of(kobj, struct device, kobj); 150 struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev); 151 struct drm_device *drm_dev = dminor->dev; 152 struct drm_i915_private *dev_priv = drm_dev->dev_private; 153 u32 *temp = NULL; /* Just here to make handling failures easy */ 154 int ret; 155 156 ret = l3_access_valid(drm_dev, offset); 157 if (ret) 158 return ret; 159 160 ret = i915_mutex_lock_interruptible(drm_dev); 161 if (ret) 162 return ret; 163 164 if (!dev_priv->mm.l3_remap_info) { 165 temp = kzalloc(GEN7_L3LOG_SIZE, GFP_KERNEL); 166 if (!temp) { 167 mutex_unlock(&drm_dev->struct_mutex); 168 return -ENOMEM; 169 } 170 } 171 172 ret = i915_gpu_idle(drm_dev); 173 if (ret) { 174 kfree(temp); 175 mutex_unlock(&drm_dev->struct_mutex); 176 return ret; 177 } 178 179 /* TODO: Ideally we really want a GPU reset here to make sure errors 180 * aren't propagated. Since I cannot find a stable way to reset the GPU 181 * at this point it is left as a TODO. 182 */ 183 if (temp) 184 dev_priv->mm.l3_remap_info = temp; 185 186 memcpy(dev_priv->mm.l3_remap_info + (offset/4), 187 buf + (offset/4), 188 count); 189 190 i915_gem_l3_remap(drm_dev); 191 192 mutex_unlock(&drm_dev->struct_mutex); 193 194 return count; 195 } 196 197 static struct bin_attribute dpf_attrs = { 198 .attr = {.name = "l3_parity", .mode = (S_IRUSR | S_IWUSR)}, 199 .size = GEN7_L3LOG_SIZE, 200 .read = i915_l3_read, 201 .write = i915_l3_write, 202 .mmap = NULL 203 }; 204 205 void i915_setup_sysfs(struct drm_device *dev) 206 { 207 int ret; 208 209 if (INTEL_INFO(dev)->gen >= 6) { 210 ret = sysfs_merge_group(&dev->primary->kdev.kobj, 211 &rc6_attr_group); 212 if (ret) 213 DRM_ERROR("RC6 residency sysfs setup failed\n"); 214 } 215 216 if (IS_IVYBRIDGE(dev)) { 217 ret = device_create_bin_file(&dev->primary->kdev, &dpf_attrs); 218 if (ret) 219 DRM_ERROR("l3 parity sysfs setup failed\n"); 220 } 221 } 222 223 void i915_teardown_sysfs(struct drm_device *dev) 224 { 225 device_remove_bin_file(&dev->primary->kdev, &dpf_attrs); 226 sysfs_unmerge_group(&dev->primary->kdev.kobj, &rc6_attr_group); 227 } 228 #else 229 void i915_setup_sysfs(struct drm_device *dev) 230 { 231 return; 232 } 233 234 void i915_teardown_sysfs(struct drm_device *dev) 235 { 236 return; 237 } 238 #endif /* CONFIG_PM */ 239