i915_sysfs.c 6.5 KB

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