i915_sysfs.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  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. #include <linux/device.h>
  28. #include <linux/module.h>
  29. #include <linux/stat.h>
  30. #include <linux/sysfs.h>
  31. #include "intel_drv.h"
  32. #include "i915_drv.h"
  33. static u32 calc_residency(struct drm_device *dev, const u32 reg)
  34. {
  35. struct drm_i915_private *dev_priv = dev->dev_private;
  36. u64 raw_time; /* 32b value may overflow during fixed point math */
  37. if (!intel_enable_rc6(dev))
  38. return 0;
  39. raw_time = I915_READ(reg) * 128ULL;
  40. return DIV_ROUND_UP_ULL(raw_time, 100000);
  41. }
  42. static ssize_t
  43. show_rc6_mask(struct device *dev, struct device_attribute *attr, char *buf)
  44. {
  45. struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev);
  46. return snprintf(buf, PAGE_SIZE, "%x", intel_enable_rc6(dminor->dev));
  47. }
  48. static ssize_t
  49. show_rc6_ms(struct device *dev, struct device_attribute *attr, char *buf)
  50. {
  51. struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev);
  52. u32 rc6_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6);
  53. return snprintf(buf, PAGE_SIZE, "%u", rc6_residency);
  54. }
  55. static ssize_t
  56. show_rc6p_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 rc6p_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6p);
  60. return snprintf(buf, PAGE_SIZE, "%u", rc6p_residency);
  61. }
  62. static ssize_t
  63. show_rc6pp_ms(struct device *dev, struct device_attribute *attr, char *buf)
  64. {
  65. struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev);
  66. u32 rc6pp_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6pp);
  67. return snprintf(buf, PAGE_SIZE, "%u", rc6pp_residency);
  68. }
  69. static DEVICE_ATTR(rc6_enable, S_IRUGO, show_rc6_mask, NULL);
  70. static DEVICE_ATTR(rc6_residency_ms, S_IRUGO, show_rc6_ms, NULL);
  71. static DEVICE_ATTR(rc6p_residency_ms, S_IRUGO, show_rc6p_ms, NULL);
  72. static DEVICE_ATTR(rc6pp_residency_ms, S_IRUGO, show_rc6pp_ms, NULL);
  73. static struct attribute *rc6_attrs[] = {
  74. &dev_attr_rc6_enable.attr,
  75. &dev_attr_rc6_residency_ms.attr,
  76. &dev_attr_rc6p_residency_ms.attr,
  77. &dev_attr_rc6pp_residency_ms.attr,
  78. NULL
  79. };
  80. static struct attribute_group rc6_attr_group = {
  81. .name = power_group_name,
  82. .attrs = rc6_attrs
  83. };
  84. static int l3_access_valid(struct drm_device *dev, loff_t offset)
  85. {
  86. if (!IS_IVYBRIDGE(dev))
  87. return -EPERM;
  88. if (offset % 4 != 0)
  89. return -EINVAL;
  90. if (offset >= GEN7_L3LOG_SIZE)
  91. return -ENXIO;
  92. return 0;
  93. }
  94. static ssize_t
  95. i915_l3_read(struct file *filp, struct kobject *kobj,
  96. struct bin_attribute *attr, char *buf,
  97. loff_t offset, size_t count)
  98. {
  99. struct device *dev = container_of(kobj, struct device, kobj);
  100. struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev);
  101. struct drm_device *drm_dev = dminor->dev;
  102. struct drm_i915_private *dev_priv = drm_dev->dev_private;
  103. uint32_t misccpctl;
  104. int i, ret;
  105. ret = l3_access_valid(drm_dev, offset);
  106. if (ret)
  107. return ret;
  108. ret = i915_mutex_lock_interruptible(drm_dev);
  109. if (ret)
  110. return ret;
  111. misccpctl = I915_READ(GEN7_MISCCPCTL);
  112. I915_WRITE(GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE);
  113. for (i = offset; count >= 4 && i < GEN7_L3LOG_SIZE; i += 4, count -= 4)
  114. *((uint32_t *)(&buf[i])) = I915_READ(GEN7_L3LOG_BASE + i);
  115. I915_WRITE(GEN7_MISCCPCTL, misccpctl);
  116. mutex_unlock(&drm_dev->struct_mutex);
  117. return i - offset;
  118. }
  119. static ssize_t
  120. i915_l3_write(struct file *filp, struct kobject *kobj,
  121. struct bin_attribute *attr, char *buf,
  122. loff_t offset, size_t count)
  123. {
  124. struct device *dev = container_of(kobj, struct device, kobj);
  125. struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev);
  126. struct drm_device *drm_dev = dminor->dev;
  127. struct drm_i915_private *dev_priv = drm_dev->dev_private;
  128. u32 *temp = NULL; /* Just here to make handling failures easy */
  129. int ret;
  130. ret = l3_access_valid(drm_dev, offset);
  131. if (ret)
  132. return ret;
  133. ret = i915_mutex_lock_interruptible(drm_dev);
  134. if (ret)
  135. return ret;
  136. if (!dev_priv->mm.l3_remap_info) {
  137. temp = kzalloc(GEN7_L3LOG_SIZE, GFP_KERNEL);
  138. if (!temp) {
  139. mutex_unlock(&drm_dev->struct_mutex);
  140. return -ENOMEM;
  141. }
  142. }
  143. ret = i915_gpu_idle(drm_dev);
  144. if (ret) {
  145. kfree(temp);
  146. mutex_unlock(&drm_dev->struct_mutex);
  147. return ret;
  148. }
  149. /* TODO: Ideally we really want a GPU reset here to make sure errors
  150. * aren't propagated. Since I cannot find a stable way to reset the GPU
  151. * at this point it is left as a TODO.
  152. */
  153. if (temp)
  154. dev_priv->mm.l3_remap_info = temp;
  155. memcpy(dev_priv->mm.l3_remap_info + (offset/4),
  156. buf + (offset/4),
  157. count);
  158. i915_gem_l3_remap(drm_dev);
  159. mutex_unlock(&drm_dev->struct_mutex);
  160. return count;
  161. }
  162. static struct bin_attribute dpf_attrs = {
  163. .attr = {.name = "l3_parity", .mode = (S_IRUSR | S_IWUSR)},
  164. .size = GEN7_L3LOG_SIZE,
  165. .read = i915_l3_read,
  166. .write = i915_l3_write,
  167. .mmap = NULL
  168. };
  169. void i915_setup_sysfs(struct drm_device *dev)
  170. {
  171. int ret;
  172. if (INTEL_INFO(dev)->gen >= 6) {
  173. ret = sysfs_merge_group(&dev->primary->kdev.kobj,
  174. &rc6_attr_group);
  175. if (ret)
  176. DRM_ERROR("RC6 residency sysfs setup failed\n");
  177. }
  178. if (IS_IVYBRIDGE(dev)) {
  179. ret = device_create_bin_file(&dev->primary->kdev, &dpf_attrs);
  180. if (ret)
  181. DRM_ERROR("l3 parity sysfs setup failed\n");
  182. }
  183. }
  184. void i915_teardown_sysfs(struct drm_device *dev)
  185. {
  186. device_remove_bin_file(&dev->primary->kdev, &dpf_attrs);
  187. sysfs_unmerge_group(&dev->primary->kdev.kobj, &rc6_attr_group);
  188. }