xref: /openbmc/linux/drivers/gpu/drm/i915/i915_sysfs.c (revision 3ccfd19dea7c5c85aa4b1f929a97a02b026ab356)
10136db58SBen Widawsky /*
20136db58SBen Widawsky  * Copyright © 2012 Intel Corporation
30136db58SBen Widawsky  *
40136db58SBen Widawsky  * Permission is hereby granted, free of charge, to any person obtaining a
50136db58SBen Widawsky  * copy of this software and associated documentation files (the "Software"),
60136db58SBen Widawsky  * to deal in the Software without restriction, including without limitation
70136db58SBen Widawsky  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
80136db58SBen Widawsky  * and/or sell copies of the Software, and to permit persons to whom the
90136db58SBen Widawsky  * Software is furnished to do so, subject to the following conditions:
100136db58SBen Widawsky  *
110136db58SBen Widawsky  * The above copyright notice and this permission notice (including the next
120136db58SBen Widawsky  * paragraph) shall be included in all copies or substantial portions of the
130136db58SBen Widawsky  * Software.
140136db58SBen Widawsky  *
150136db58SBen Widawsky  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
160136db58SBen Widawsky  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
170136db58SBen Widawsky  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
180136db58SBen Widawsky  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
190136db58SBen Widawsky  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
200136db58SBen Widawsky  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
210136db58SBen Widawsky  * IN THE SOFTWARE.
220136db58SBen Widawsky  *
230136db58SBen Widawsky  * Authors:
240136db58SBen Widawsky  *    Ben Widawsky <ben@bwidawsk.net>
250136db58SBen Widawsky  *
260136db58SBen Widawsky  */
270136db58SBen Widawsky 
280136db58SBen Widawsky #include <linux/device.h>
290136db58SBen Widawsky #include <linux/module.h>
300136db58SBen Widawsky #include <linux/stat.h>
310136db58SBen Widawsky #include <linux/sysfs.h>
3284bc7581SBen Widawsky #include "intel_drv.h"
330136db58SBen Widawsky #include "i915_drv.h"
340136db58SBen Widawsky 
355ab3633dSHunt Xu #ifdef CONFIG_PM
360136db58SBen Widawsky static u32 calc_residency(struct drm_device *dev, const u32 reg)
370136db58SBen Widawsky {
380136db58SBen Widawsky 	struct drm_i915_private *dev_priv = dev->dev_private;
390136db58SBen Widawsky 	u64 raw_time; /* 32b value may overflow during fixed point math */
400136db58SBen Widawsky 
410136db58SBen Widawsky 	if (!intel_enable_rc6(dev))
420136db58SBen Widawsky 		return 0;
430136db58SBen Widawsky 
44a85d4bcbSBen Widawsky 	raw_time = I915_READ(reg) * 128ULL;
45a85d4bcbSBen Widawsky 	return DIV_ROUND_UP_ULL(raw_time, 100000);
460136db58SBen Widawsky }
470136db58SBen Widawsky 
480136db58SBen Widawsky static ssize_t
49dbdfd8e9SBen Widawsky show_rc6_mask(struct device *kdev, struct device_attribute *attr, char *buf)
500136db58SBen Widawsky {
51dbdfd8e9SBen Widawsky 	struct drm_minor *dminor = container_of(kdev, struct drm_minor, kdev);
523e2a1556SJani Nikula 	return snprintf(buf, PAGE_SIZE, "%x\n", intel_enable_rc6(dminor->dev));
530136db58SBen Widawsky }
540136db58SBen Widawsky 
550136db58SBen Widawsky static ssize_t
56dbdfd8e9SBen Widawsky show_rc6_ms(struct device *kdev, struct device_attribute *attr, char *buf)
570136db58SBen Widawsky {
58dbdfd8e9SBen Widawsky 	struct drm_minor *dminor = container_of(kdev, struct drm_minor, kdev);
590136db58SBen Widawsky 	u32 rc6_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6);
603e2a1556SJani Nikula 	return snprintf(buf, PAGE_SIZE, "%u\n", rc6_residency);
610136db58SBen Widawsky }
620136db58SBen Widawsky 
630136db58SBen Widawsky static ssize_t
64dbdfd8e9SBen Widawsky show_rc6p_ms(struct device *kdev, struct device_attribute *attr, char *buf)
650136db58SBen Widawsky {
66dbdfd8e9SBen Widawsky 	struct drm_minor *dminor = container_of(kdev, struct drm_minor, kdev);
670136db58SBen Widawsky 	u32 rc6p_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6p);
683e2a1556SJani Nikula 	return snprintf(buf, PAGE_SIZE, "%u\n", rc6p_residency);
690136db58SBen Widawsky }
700136db58SBen Widawsky 
710136db58SBen Widawsky static ssize_t
72dbdfd8e9SBen Widawsky show_rc6pp_ms(struct device *kdev, struct device_attribute *attr, char *buf)
730136db58SBen Widawsky {
74dbdfd8e9SBen Widawsky 	struct drm_minor *dminor = container_of(kdev, struct drm_minor, kdev);
750136db58SBen Widawsky 	u32 rc6pp_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6pp);
763e2a1556SJani Nikula 	return snprintf(buf, PAGE_SIZE, "%u\n", rc6pp_residency);
770136db58SBen Widawsky }
780136db58SBen Widawsky 
790136db58SBen Widawsky static DEVICE_ATTR(rc6_enable, S_IRUGO, show_rc6_mask, NULL);
800136db58SBen Widawsky static DEVICE_ATTR(rc6_residency_ms, S_IRUGO, show_rc6_ms, NULL);
810136db58SBen Widawsky static DEVICE_ATTR(rc6p_residency_ms, S_IRUGO, show_rc6p_ms, NULL);
820136db58SBen Widawsky static DEVICE_ATTR(rc6pp_residency_ms, S_IRUGO, show_rc6pp_ms, NULL);
830136db58SBen Widawsky 
840136db58SBen Widawsky static struct attribute *rc6_attrs[] = {
850136db58SBen Widawsky 	&dev_attr_rc6_enable.attr,
860136db58SBen Widawsky 	&dev_attr_rc6_residency_ms.attr,
870136db58SBen Widawsky 	&dev_attr_rc6p_residency_ms.attr,
880136db58SBen Widawsky 	&dev_attr_rc6pp_residency_ms.attr,
890136db58SBen Widawsky 	NULL
900136db58SBen Widawsky };
910136db58SBen Widawsky 
920136db58SBen Widawsky static struct attribute_group rc6_attr_group = {
930136db58SBen Widawsky 	.name = power_group_name,
940136db58SBen Widawsky 	.attrs =  rc6_attrs
950136db58SBen Widawsky };
968c3f929bSBen Widawsky #endif
970136db58SBen Widawsky 
9884bc7581SBen Widawsky static int l3_access_valid(struct drm_device *dev, loff_t offset)
9984bc7581SBen Widawsky {
100ebf69cb8SDaniel Vetter 	if (!HAS_L3_GPU_CACHE(dev))
10184bc7581SBen Widawsky 		return -EPERM;
10284bc7581SBen Widawsky 
10384bc7581SBen Widawsky 	if (offset % 4 != 0)
10484bc7581SBen Widawsky 		return -EINVAL;
10584bc7581SBen Widawsky 
10684bc7581SBen Widawsky 	if (offset >= GEN7_L3LOG_SIZE)
10784bc7581SBen Widawsky 		return -ENXIO;
10884bc7581SBen Widawsky 
10984bc7581SBen Widawsky 	return 0;
11084bc7581SBen Widawsky }
11184bc7581SBen Widawsky 
11284bc7581SBen Widawsky static ssize_t
11384bc7581SBen Widawsky i915_l3_read(struct file *filp, struct kobject *kobj,
11484bc7581SBen Widawsky 	     struct bin_attribute *attr, char *buf,
11584bc7581SBen Widawsky 	     loff_t offset, size_t count)
11684bc7581SBen Widawsky {
11784bc7581SBen Widawsky 	struct device *dev = container_of(kobj, struct device, kobj);
11884bc7581SBen Widawsky 	struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev);
11984bc7581SBen Widawsky 	struct drm_device *drm_dev = dminor->dev;
12084bc7581SBen Widawsky 	struct drm_i915_private *dev_priv = drm_dev->dev_private;
12135a85ac6SBen Widawsky 	int slice = (int)(uintptr_t)attr->private;
122*3ccfd19dSBen Widawsky 	int ret;
12384bc7581SBen Widawsky 
1241c3dcd1cSBen Widawsky 	count = round_down(count, 4);
1251c3dcd1cSBen Widawsky 
12684bc7581SBen Widawsky 	ret = l3_access_valid(drm_dev, offset);
12784bc7581SBen Widawsky 	if (ret)
12884bc7581SBen Widawsky 		return ret;
12984bc7581SBen Widawsky 
13033618ea5SBen Widawsky 	count = min_t(int, GEN7_L3LOG_SIZE-offset, count);
13133618ea5SBen Widawsky 
13284bc7581SBen Widawsky 	ret = i915_mutex_lock_interruptible(drm_dev);
13384bc7581SBen Widawsky 	if (ret)
13484bc7581SBen Widawsky 		return ret;
13584bc7581SBen Widawsky 
13635a85ac6SBen Widawsky 	if (dev_priv->l3_parity.remap_info[slice])
1371c966dd2SBen Widawsky 		memcpy(buf,
13835a85ac6SBen Widawsky 		       dev_priv->l3_parity.remap_info[slice] + (offset/4),
1391c966dd2SBen Widawsky 		       count);
1401c966dd2SBen Widawsky 	else
1411c966dd2SBen Widawsky 		memset(buf, 0, count);
1421c966dd2SBen Widawsky 
14384bc7581SBen Widawsky 	mutex_unlock(&drm_dev->struct_mutex);
14484bc7581SBen Widawsky 
1451c966dd2SBen Widawsky 	return count;
14684bc7581SBen Widawsky }
14784bc7581SBen Widawsky 
14884bc7581SBen Widawsky static ssize_t
14984bc7581SBen Widawsky i915_l3_write(struct file *filp, struct kobject *kobj,
15084bc7581SBen Widawsky 	      struct bin_attribute *attr, char *buf,
15184bc7581SBen Widawsky 	      loff_t offset, size_t count)
15284bc7581SBen Widawsky {
15384bc7581SBen Widawsky 	struct device *dev = container_of(kobj, struct device, kobj);
15484bc7581SBen Widawsky 	struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev);
15584bc7581SBen Widawsky 	struct drm_device *drm_dev = dminor->dev;
15684bc7581SBen Widawsky 	struct drm_i915_private *dev_priv = drm_dev->dev_private;
157*3ccfd19dSBen Widawsky 	struct i915_hw_context *ctx;
15884bc7581SBen Widawsky 	u32 *temp = NULL; /* Just here to make handling failures easy */
15935a85ac6SBen Widawsky 	int slice = (int)(uintptr_t)attr->private;
16084bc7581SBen Widawsky 	int ret;
16184bc7581SBen Widawsky 
16284bc7581SBen Widawsky 	ret = l3_access_valid(drm_dev, offset);
16384bc7581SBen Widawsky 	if (ret)
16484bc7581SBen Widawsky 		return ret;
16584bc7581SBen Widawsky 
166*3ccfd19dSBen Widawsky 	if (dev_priv->hw_contexts_disabled)
167*3ccfd19dSBen Widawsky 		return -ENXIO;
168*3ccfd19dSBen Widawsky 
16984bc7581SBen Widawsky 	ret = i915_mutex_lock_interruptible(drm_dev);
17084bc7581SBen Widawsky 	if (ret)
17184bc7581SBen Widawsky 		return ret;
17284bc7581SBen Widawsky 
17335a85ac6SBen Widawsky 	if (!dev_priv->l3_parity.remap_info[slice]) {
17484bc7581SBen Widawsky 		temp = kzalloc(GEN7_L3LOG_SIZE, GFP_KERNEL);
17584bc7581SBen Widawsky 		if (!temp) {
17684bc7581SBen Widawsky 			mutex_unlock(&drm_dev->struct_mutex);
17784bc7581SBen Widawsky 			return -ENOMEM;
17884bc7581SBen Widawsky 		}
17984bc7581SBen Widawsky 	}
18084bc7581SBen Widawsky 
18184bc7581SBen Widawsky 	ret = i915_gpu_idle(drm_dev);
18284bc7581SBen Widawsky 	if (ret) {
18384bc7581SBen Widawsky 		kfree(temp);
18484bc7581SBen Widawsky 		mutex_unlock(&drm_dev->struct_mutex);
18584bc7581SBen Widawsky 		return ret;
18684bc7581SBen Widawsky 	}
18784bc7581SBen Widawsky 
18884bc7581SBen Widawsky 	/* TODO: Ideally we really want a GPU reset here to make sure errors
18984bc7581SBen Widawsky 	 * aren't propagated. Since I cannot find a stable way to reset the GPU
19084bc7581SBen Widawsky 	 * at this point it is left as a TODO.
19184bc7581SBen Widawsky 	*/
19284bc7581SBen Widawsky 	if (temp)
19335a85ac6SBen Widawsky 		dev_priv->l3_parity.remap_info[slice] = temp;
19484bc7581SBen Widawsky 
19535a85ac6SBen Widawsky 	memcpy(dev_priv->l3_parity.remap_info[slice] + (offset/4), buf, count);
19684bc7581SBen Widawsky 
197*3ccfd19dSBen Widawsky 	/* NB: We defer the remapping until we switch to the context */
198*3ccfd19dSBen Widawsky 	list_for_each_entry(ctx, &dev_priv->context_list, link)
199*3ccfd19dSBen Widawsky 		ctx->remap_slice |= (1<<slice);
20084bc7581SBen Widawsky 
20184bc7581SBen Widawsky 	mutex_unlock(&drm_dev->struct_mutex);
20284bc7581SBen Widawsky 
20384bc7581SBen Widawsky 	return count;
20484bc7581SBen Widawsky }
20584bc7581SBen Widawsky 
20684bc7581SBen Widawsky static struct bin_attribute dpf_attrs = {
20784bc7581SBen Widawsky 	.attr = {.name = "l3_parity", .mode = (S_IRUSR | S_IWUSR)},
20884bc7581SBen Widawsky 	.size = GEN7_L3LOG_SIZE,
20984bc7581SBen Widawsky 	.read = i915_l3_read,
21084bc7581SBen Widawsky 	.write = i915_l3_write,
21135a85ac6SBen Widawsky 	.mmap = NULL,
21235a85ac6SBen Widawsky 	.private = (void *)0
21335a85ac6SBen Widawsky };
21435a85ac6SBen Widawsky 
21535a85ac6SBen Widawsky static struct bin_attribute dpf_attrs_1 = {
21635a85ac6SBen Widawsky 	.attr = {.name = "l3_parity_slice_1", .mode = (S_IRUSR | S_IWUSR)},
21735a85ac6SBen Widawsky 	.size = GEN7_L3LOG_SIZE,
21835a85ac6SBen Widawsky 	.read = i915_l3_read,
21935a85ac6SBen Widawsky 	.write = i915_l3_write,
22035a85ac6SBen Widawsky 	.mmap = NULL,
22135a85ac6SBen Widawsky 	.private = (void *)1
22284bc7581SBen Widawsky };
22384bc7581SBen Widawsky 
224df6eedc8SBen Widawsky static ssize_t gt_cur_freq_mhz_show(struct device *kdev,
225df6eedc8SBen Widawsky 				    struct device_attribute *attr, char *buf)
226df6eedc8SBen Widawsky {
227df6eedc8SBen Widawsky 	struct drm_minor *minor = container_of(kdev, struct drm_minor, kdev);
228df6eedc8SBen Widawsky 	struct drm_device *dev = minor->dev;
229df6eedc8SBen Widawsky 	struct drm_i915_private *dev_priv = dev->dev_private;
230df6eedc8SBen Widawsky 	int ret;
231df6eedc8SBen Widawsky 
2324fc688ceSJesse Barnes 	mutex_lock(&dev_priv->rps.hw_lock);
233177006a1SJesse Barnes 	if (IS_VALLEYVIEW(dev_priv->dev)) {
234177006a1SJesse Barnes 		u32 freq;
23564936258SJani Nikula 		freq = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS);
236177006a1SJesse Barnes 		ret = vlv_gpu_freq(dev_priv->mem_freq, (freq >> 8) & 0xff);
237177006a1SJesse Barnes 	} else {
238df6eedc8SBen Widawsky 		ret = dev_priv->rps.cur_delay * GT_FREQUENCY_MULTIPLIER;
239177006a1SJesse Barnes 	}
2404fc688ceSJesse Barnes 	mutex_unlock(&dev_priv->rps.hw_lock);
241df6eedc8SBen Widawsky 
2423e2a1556SJani Nikula 	return snprintf(buf, PAGE_SIZE, "%d\n", ret);
243df6eedc8SBen Widawsky }
244df6eedc8SBen Widawsky 
24597e4eed7SChris Wilson static ssize_t vlv_rpe_freq_mhz_show(struct device *kdev,
24697e4eed7SChris Wilson 				     struct device_attribute *attr, char *buf)
24797e4eed7SChris Wilson {
24897e4eed7SChris Wilson 	struct drm_minor *minor = container_of(kdev, struct drm_minor, kdev);
24997e4eed7SChris Wilson 	struct drm_device *dev = minor->dev;
25097e4eed7SChris Wilson 	struct drm_i915_private *dev_priv = dev->dev_private;
25197e4eed7SChris Wilson 
25297e4eed7SChris Wilson 	return snprintf(buf, PAGE_SIZE, "%d\n",
25397e4eed7SChris Wilson 			vlv_gpu_freq(dev_priv->mem_freq,
25497e4eed7SChris Wilson 				     dev_priv->rps.rpe_delay));
25597e4eed7SChris Wilson }
25697e4eed7SChris Wilson 
257df6eedc8SBen Widawsky static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute *attr, char *buf)
258df6eedc8SBen Widawsky {
259df6eedc8SBen Widawsky 	struct drm_minor *minor = container_of(kdev, struct drm_minor, kdev);
260df6eedc8SBen Widawsky 	struct drm_device *dev = minor->dev;
261df6eedc8SBen Widawsky 	struct drm_i915_private *dev_priv = dev->dev_private;
262df6eedc8SBen Widawsky 	int ret;
263df6eedc8SBen Widawsky 
2644fc688ceSJesse Barnes 	mutex_lock(&dev_priv->rps.hw_lock);
2650a073b84SJesse Barnes 	if (IS_VALLEYVIEW(dev_priv->dev))
2660a073b84SJesse Barnes 		ret = vlv_gpu_freq(dev_priv->mem_freq, dev_priv->rps.max_delay);
2670a073b84SJesse Barnes 	else
268182642b0SMika Kuoppala 		ret = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER;
2694fc688ceSJesse Barnes 	mutex_unlock(&dev_priv->rps.hw_lock);
270df6eedc8SBen Widawsky 
2713e2a1556SJani Nikula 	return snprintf(buf, PAGE_SIZE, "%d\n", ret);
272df6eedc8SBen Widawsky }
273df6eedc8SBen Widawsky 
27446ddf194SBen Widawsky static ssize_t gt_max_freq_mhz_store(struct device *kdev,
27546ddf194SBen Widawsky 				     struct device_attribute *attr,
27646ddf194SBen Widawsky 				     const char *buf, size_t count)
27746ddf194SBen Widawsky {
27846ddf194SBen Widawsky 	struct drm_minor *minor = container_of(kdev, struct drm_minor, kdev);
27946ddf194SBen Widawsky 	struct drm_device *dev = minor->dev;
28046ddf194SBen Widawsky 	struct drm_i915_private *dev_priv = dev->dev_private;
28131c77388SBen Widawsky 	u32 val, rp_state_cap, hw_max, hw_min, non_oc_max;
28246ddf194SBen Widawsky 	ssize_t ret;
28346ddf194SBen Widawsky 
28446ddf194SBen Widawsky 	ret = kstrtou32(buf, 0, &val);
28546ddf194SBen Widawsky 	if (ret)
28646ddf194SBen Widawsky 		return ret;
28746ddf194SBen Widawsky 
2884fc688ceSJesse Barnes 	mutex_lock(&dev_priv->rps.hw_lock);
28946ddf194SBen Widawsky 
2900a073b84SJesse Barnes 	if (IS_VALLEYVIEW(dev_priv->dev)) {
2910a073b84SJesse Barnes 		val = vlv_freq_opcode(dev_priv->mem_freq, val);
2920a073b84SJesse Barnes 
2930a073b84SJesse Barnes 		hw_max = valleyview_rps_max_freq(dev_priv);
2940a073b84SJesse Barnes 		hw_min = valleyview_rps_min_freq(dev_priv);
2950a073b84SJesse Barnes 		non_oc_max = hw_max;
2960a073b84SJesse Barnes 	} else {
2970a073b84SJesse Barnes 		val /= GT_FREQUENCY_MULTIPLIER;
2980a073b84SJesse Barnes 
29946ddf194SBen Widawsky 		rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
30031c77388SBen Widawsky 		hw_max = dev_priv->rps.hw_max;
30131c77388SBen Widawsky 		non_oc_max = (rp_state_cap & 0xff);
30246ddf194SBen Widawsky 		hw_min = ((rp_state_cap & 0xff0000) >> 16);
3030a073b84SJesse Barnes 	}
30446ddf194SBen Widawsky 
3050a073b84SJesse Barnes 	if (val < hw_min || val > hw_max ||
3060a073b84SJesse Barnes 	    val < dev_priv->rps.min_delay) {
3074fc688ceSJesse Barnes 		mutex_unlock(&dev_priv->rps.hw_lock);
30846ddf194SBen Widawsky 		return -EINVAL;
30946ddf194SBen Widawsky 	}
31046ddf194SBen Widawsky 
31131c77388SBen Widawsky 	if (val > non_oc_max)
31231c77388SBen Widawsky 		DRM_DEBUG("User requested overclocking to %d\n",
31331c77388SBen Widawsky 			  val * GT_FREQUENCY_MULTIPLIER);
31431c77388SBen Widawsky 
3150a073b84SJesse Barnes 	if (dev_priv->rps.cur_delay > val) {
3160a073b84SJesse Barnes 		if (IS_VALLEYVIEW(dev_priv->dev))
3170a073b84SJesse Barnes 			valleyview_set_rps(dev_priv->dev, val);
3180a073b84SJesse Barnes 		else
31946ddf194SBen Widawsky 			gen6_set_rps(dev_priv->dev, val);
3200a073b84SJesse Barnes 	}
32146ddf194SBen Widawsky 
32246ddf194SBen Widawsky 	dev_priv->rps.max_delay = val;
32346ddf194SBen Widawsky 
3244fc688ceSJesse Barnes 	mutex_unlock(&dev_priv->rps.hw_lock);
32546ddf194SBen Widawsky 
32646ddf194SBen Widawsky 	return count;
32746ddf194SBen Widawsky }
32846ddf194SBen Widawsky 
329df6eedc8SBen Widawsky static ssize_t gt_min_freq_mhz_show(struct device *kdev, struct device_attribute *attr, char *buf)
330df6eedc8SBen Widawsky {
331df6eedc8SBen Widawsky 	struct drm_minor *minor = container_of(kdev, struct drm_minor, kdev);
332df6eedc8SBen Widawsky 	struct drm_device *dev = minor->dev;
333df6eedc8SBen Widawsky 	struct drm_i915_private *dev_priv = dev->dev_private;
334df6eedc8SBen Widawsky 	int ret;
335df6eedc8SBen Widawsky 
3364fc688ceSJesse Barnes 	mutex_lock(&dev_priv->rps.hw_lock);
3370a073b84SJesse Barnes 	if (IS_VALLEYVIEW(dev_priv->dev))
3380a073b84SJesse Barnes 		ret = vlv_gpu_freq(dev_priv->mem_freq, dev_priv->rps.min_delay);
3390a073b84SJesse Barnes 	else
340df6eedc8SBen Widawsky 		ret = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER;
3414fc688ceSJesse Barnes 	mutex_unlock(&dev_priv->rps.hw_lock);
342df6eedc8SBen Widawsky 
3433e2a1556SJani Nikula 	return snprintf(buf, PAGE_SIZE, "%d\n", ret);
344df6eedc8SBen Widawsky }
345df6eedc8SBen Widawsky 
34646ddf194SBen Widawsky static ssize_t gt_min_freq_mhz_store(struct device *kdev,
34746ddf194SBen Widawsky 				     struct device_attribute *attr,
34846ddf194SBen Widawsky 				     const char *buf, size_t count)
34946ddf194SBen Widawsky {
35046ddf194SBen Widawsky 	struct drm_minor *minor = container_of(kdev, struct drm_minor, kdev);
35146ddf194SBen Widawsky 	struct drm_device *dev = minor->dev;
35246ddf194SBen Widawsky 	struct drm_i915_private *dev_priv = dev->dev_private;
35346ddf194SBen Widawsky 	u32 val, rp_state_cap, hw_max, hw_min;
35446ddf194SBen Widawsky 	ssize_t ret;
35546ddf194SBen Widawsky 
35646ddf194SBen Widawsky 	ret = kstrtou32(buf, 0, &val);
35746ddf194SBen Widawsky 	if (ret)
35846ddf194SBen Widawsky 		return ret;
35946ddf194SBen Widawsky 
3604fc688ceSJesse Barnes 	mutex_lock(&dev_priv->rps.hw_lock);
36146ddf194SBen Widawsky 
3620a073b84SJesse Barnes 	if (IS_VALLEYVIEW(dev)) {
3630a073b84SJesse Barnes 		val = vlv_freq_opcode(dev_priv->mem_freq, val);
3640a073b84SJesse Barnes 
3650a073b84SJesse Barnes 		hw_max = valleyview_rps_max_freq(dev_priv);
3660a073b84SJesse Barnes 		hw_min = valleyview_rps_min_freq(dev_priv);
3670a073b84SJesse Barnes 	} else {
3680a073b84SJesse Barnes 		val /= GT_FREQUENCY_MULTIPLIER;
3690a073b84SJesse Barnes 
37046ddf194SBen Widawsky 		rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
37131c77388SBen Widawsky 		hw_max = dev_priv->rps.hw_max;
37246ddf194SBen Widawsky 		hw_min = ((rp_state_cap & 0xff0000) >> 16);
3730a073b84SJesse Barnes 	}
37446ddf194SBen Widawsky 
37546ddf194SBen Widawsky 	if (val < hw_min || val > hw_max || val > dev_priv->rps.max_delay) {
3764fc688ceSJesse Barnes 		mutex_unlock(&dev_priv->rps.hw_lock);
37746ddf194SBen Widawsky 		return -EINVAL;
37846ddf194SBen Widawsky 	}
37946ddf194SBen Widawsky 
3800a073b84SJesse Barnes 	if (dev_priv->rps.cur_delay < val) {
3810a073b84SJesse Barnes 		if (IS_VALLEYVIEW(dev))
3820a073b84SJesse Barnes 			valleyview_set_rps(dev, val);
3830a073b84SJesse Barnes 		else
38446ddf194SBen Widawsky 			gen6_set_rps(dev_priv->dev, val);
3850a073b84SJesse Barnes 	}
38646ddf194SBen Widawsky 
38746ddf194SBen Widawsky 	dev_priv->rps.min_delay = val;
38846ddf194SBen Widawsky 
3894fc688ceSJesse Barnes 	mutex_unlock(&dev_priv->rps.hw_lock);
39046ddf194SBen Widawsky 
39146ddf194SBen Widawsky 	return count;
39246ddf194SBen Widawsky 
39346ddf194SBen Widawsky }
39446ddf194SBen Widawsky 
395df6eedc8SBen Widawsky static DEVICE_ATTR(gt_cur_freq_mhz, S_IRUGO, gt_cur_freq_mhz_show, NULL);
39646ddf194SBen Widawsky static DEVICE_ATTR(gt_max_freq_mhz, S_IRUGO | S_IWUSR, gt_max_freq_mhz_show, gt_max_freq_mhz_store);
39746ddf194SBen Widawsky static DEVICE_ATTR(gt_min_freq_mhz, S_IRUGO | S_IWUSR, gt_min_freq_mhz_show, gt_min_freq_mhz_store);
398df6eedc8SBen Widawsky 
39997e4eed7SChris Wilson static DEVICE_ATTR(vlv_rpe_freq_mhz, S_IRUGO, vlv_rpe_freq_mhz_show, NULL);
400ac6ae347SBen Widawsky 
401ac6ae347SBen Widawsky static ssize_t gt_rp_mhz_show(struct device *kdev, struct device_attribute *attr, char *buf);
402ac6ae347SBen Widawsky static DEVICE_ATTR(gt_RP0_freq_mhz, S_IRUGO, gt_rp_mhz_show, NULL);
403ac6ae347SBen Widawsky static DEVICE_ATTR(gt_RP1_freq_mhz, S_IRUGO, gt_rp_mhz_show, NULL);
404ac6ae347SBen Widawsky static DEVICE_ATTR(gt_RPn_freq_mhz, S_IRUGO, gt_rp_mhz_show, NULL);
405ac6ae347SBen Widawsky 
406ac6ae347SBen Widawsky /* For now we have a static number of RP states */
407ac6ae347SBen Widawsky static ssize_t gt_rp_mhz_show(struct device *kdev, struct device_attribute *attr, char *buf)
408ac6ae347SBen Widawsky {
409ac6ae347SBen Widawsky 	struct drm_minor *minor = container_of(kdev, struct drm_minor, kdev);
410ac6ae347SBen Widawsky 	struct drm_device *dev = minor->dev;
411ac6ae347SBen Widawsky 	struct drm_i915_private *dev_priv = dev->dev_private;
412ac6ae347SBen Widawsky 	u32 val, rp_state_cap;
413ac6ae347SBen Widawsky 	ssize_t ret;
414ac6ae347SBen Widawsky 
415ac6ae347SBen Widawsky 	ret = mutex_lock_interruptible(&dev->struct_mutex);
416ac6ae347SBen Widawsky 	if (ret)
417ac6ae347SBen Widawsky 		return ret;
418ac6ae347SBen Widawsky 	rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
419ac6ae347SBen Widawsky 	mutex_unlock(&dev->struct_mutex);
420ac6ae347SBen Widawsky 
421ac6ae347SBen Widawsky 	if (attr == &dev_attr_gt_RP0_freq_mhz) {
422ac6ae347SBen Widawsky 		val = ((rp_state_cap & 0x0000ff) >> 0) * GT_FREQUENCY_MULTIPLIER;
423ac6ae347SBen Widawsky 	} else if (attr == &dev_attr_gt_RP1_freq_mhz) {
424ac6ae347SBen Widawsky 		val = ((rp_state_cap & 0x00ff00) >> 8) * GT_FREQUENCY_MULTIPLIER;
425ac6ae347SBen Widawsky 	} else if (attr == &dev_attr_gt_RPn_freq_mhz) {
426ac6ae347SBen Widawsky 		val = ((rp_state_cap & 0xff0000) >> 16) * GT_FREQUENCY_MULTIPLIER;
427ac6ae347SBen Widawsky 	} else {
428ac6ae347SBen Widawsky 		BUG();
429ac6ae347SBen Widawsky 	}
4303e2a1556SJani Nikula 	return snprintf(buf, PAGE_SIZE, "%d\n", val);
431ac6ae347SBen Widawsky }
432ac6ae347SBen Widawsky 
433df6eedc8SBen Widawsky static const struct attribute *gen6_attrs[] = {
434df6eedc8SBen Widawsky 	&dev_attr_gt_cur_freq_mhz.attr,
435df6eedc8SBen Widawsky 	&dev_attr_gt_max_freq_mhz.attr,
436df6eedc8SBen Widawsky 	&dev_attr_gt_min_freq_mhz.attr,
437ac6ae347SBen Widawsky 	&dev_attr_gt_RP0_freq_mhz.attr,
438ac6ae347SBen Widawsky 	&dev_attr_gt_RP1_freq_mhz.attr,
439ac6ae347SBen Widawsky 	&dev_attr_gt_RPn_freq_mhz.attr,
440df6eedc8SBen Widawsky 	NULL,
441df6eedc8SBen Widawsky };
442df6eedc8SBen Widawsky 
44397e4eed7SChris Wilson static const struct attribute *vlv_attrs[] = {
44497e4eed7SChris Wilson 	&dev_attr_gt_cur_freq_mhz.attr,
44597e4eed7SChris Wilson 	&dev_attr_gt_max_freq_mhz.attr,
44697e4eed7SChris Wilson 	&dev_attr_gt_min_freq_mhz.attr,
44797e4eed7SChris Wilson 	&dev_attr_vlv_rpe_freq_mhz.attr,
44897e4eed7SChris Wilson 	NULL,
44997e4eed7SChris Wilson };
45097e4eed7SChris Wilson 
451ef86ddceSMika Kuoppala static ssize_t error_state_read(struct file *filp, struct kobject *kobj,
452ef86ddceSMika Kuoppala 				struct bin_attribute *attr, char *buf,
453ef86ddceSMika Kuoppala 				loff_t off, size_t count)
454ef86ddceSMika Kuoppala {
455ef86ddceSMika Kuoppala 
456ef86ddceSMika Kuoppala 	struct device *kdev = container_of(kobj, struct device, kobj);
457ef86ddceSMika Kuoppala 	struct drm_minor *minor = container_of(kdev, struct drm_minor, kdev);
458ef86ddceSMika Kuoppala 	struct drm_device *dev = minor->dev;
459ef86ddceSMika Kuoppala 	struct i915_error_state_file_priv error_priv;
460ef86ddceSMika Kuoppala 	struct drm_i915_error_state_buf error_str;
461ef86ddceSMika Kuoppala 	ssize_t ret_count = 0;
462ef86ddceSMika Kuoppala 	int ret;
463ef86ddceSMika Kuoppala 
464ef86ddceSMika Kuoppala 	memset(&error_priv, 0, sizeof(error_priv));
465ef86ddceSMika Kuoppala 
466ef86ddceSMika Kuoppala 	ret = i915_error_state_buf_init(&error_str, count, off);
467ef86ddceSMika Kuoppala 	if (ret)
468ef86ddceSMika Kuoppala 		return ret;
469ef86ddceSMika Kuoppala 
470ef86ddceSMika Kuoppala 	error_priv.dev = dev;
471ef86ddceSMika Kuoppala 	i915_error_state_get(dev, &error_priv);
472ef86ddceSMika Kuoppala 
473ef86ddceSMika Kuoppala 	ret = i915_error_state_to_str(&error_str, &error_priv);
474ef86ddceSMika Kuoppala 	if (ret)
475ef86ddceSMika Kuoppala 		goto out;
476ef86ddceSMika Kuoppala 
477ef86ddceSMika Kuoppala 	ret_count = count < error_str.bytes ? count : error_str.bytes;
478ef86ddceSMika Kuoppala 
479ef86ddceSMika Kuoppala 	memcpy(buf, error_str.buf, ret_count);
480ef86ddceSMika Kuoppala out:
481ef86ddceSMika Kuoppala 	i915_error_state_put(&error_priv);
482ef86ddceSMika Kuoppala 	i915_error_state_buf_release(&error_str);
483ef86ddceSMika Kuoppala 
484ef86ddceSMika Kuoppala 	return ret ?: ret_count;
485ef86ddceSMika Kuoppala }
486ef86ddceSMika Kuoppala 
487ef86ddceSMika Kuoppala static ssize_t error_state_write(struct file *file, struct kobject *kobj,
488ef86ddceSMika Kuoppala 				 struct bin_attribute *attr, char *buf,
489ef86ddceSMika Kuoppala 				 loff_t off, size_t count)
490ef86ddceSMika Kuoppala {
491ef86ddceSMika Kuoppala 	struct device *kdev = container_of(kobj, struct device, kobj);
492ef86ddceSMika Kuoppala 	struct drm_minor *minor = container_of(kdev, struct drm_minor, kdev);
493ef86ddceSMika Kuoppala 	struct drm_device *dev = minor->dev;
494ef86ddceSMika Kuoppala 	int ret;
495ef86ddceSMika Kuoppala 
496ef86ddceSMika Kuoppala 	DRM_DEBUG_DRIVER("Resetting error state\n");
497ef86ddceSMika Kuoppala 
498ef86ddceSMika Kuoppala 	ret = mutex_lock_interruptible(&dev->struct_mutex);
499ef86ddceSMika Kuoppala 	if (ret)
500ef86ddceSMika Kuoppala 		return ret;
501ef86ddceSMika Kuoppala 
502ef86ddceSMika Kuoppala 	i915_destroy_error_state(dev);
503ef86ddceSMika Kuoppala 	mutex_unlock(&dev->struct_mutex);
504ef86ddceSMika Kuoppala 
505ef86ddceSMika Kuoppala 	return count;
506ef86ddceSMika Kuoppala }
507ef86ddceSMika Kuoppala 
508ef86ddceSMika Kuoppala static struct bin_attribute error_state_attr = {
509ef86ddceSMika Kuoppala 	.attr.name = "error",
510ef86ddceSMika Kuoppala 	.attr.mode = S_IRUSR | S_IWUSR,
511ef86ddceSMika Kuoppala 	.size = 0,
512ef86ddceSMika Kuoppala 	.read = error_state_read,
513ef86ddceSMika Kuoppala 	.write = error_state_write,
514ef86ddceSMika Kuoppala };
515ef86ddceSMika Kuoppala 
5160136db58SBen Widawsky void i915_setup_sysfs(struct drm_device *dev)
5170136db58SBen Widawsky {
5180136db58SBen Widawsky 	int ret;
5190136db58SBen Widawsky 
5208c3f929bSBen Widawsky #ifdef CONFIG_PM
521112abd29SDaniel Vetter 	if (INTEL_INFO(dev)->gen >= 6) {
522112abd29SDaniel Vetter 		ret = sysfs_merge_group(&dev->primary->kdev.kobj,
523112abd29SDaniel Vetter 					&rc6_attr_group);
5240136db58SBen Widawsky 		if (ret)
52584bc7581SBen Widawsky 			DRM_ERROR("RC6 residency sysfs setup failed\n");
526112abd29SDaniel Vetter 	}
5278c3f929bSBen Widawsky #endif
528e1ef7cc2SBen Widawsky 	if (HAS_L3_GPU_CACHE(dev)) {
52984bc7581SBen Widawsky 		ret = device_create_bin_file(&dev->primary->kdev, &dpf_attrs);
53084bc7581SBen Widawsky 		if (ret)
53184bc7581SBen Widawsky 			DRM_ERROR("l3 parity sysfs setup failed\n");
53235a85ac6SBen Widawsky 
53335a85ac6SBen Widawsky 		if (NUM_L3_SLICES(dev) > 1) {
53435a85ac6SBen Widawsky 			ret = device_create_bin_file(&dev->primary->kdev,
53535a85ac6SBen Widawsky 						     &dpf_attrs_1);
53635a85ac6SBen Widawsky 			if (ret)
53735a85ac6SBen Widawsky 				DRM_ERROR("l3 parity slice 1 setup failed\n");
53835a85ac6SBen Widawsky 		}
5390136db58SBen Widawsky 	}
540df6eedc8SBen Widawsky 
54197e4eed7SChris Wilson 	ret = 0;
54297e4eed7SChris Wilson 	if (IS_VALLEYVIEW(dev))
54397e4eed7SChris Wilson 		ret = sysfs_create_files(&dev->primary->kdev.kobj, vlv_attrs);
54497e4eed7SChris Wilson 	else if (INTEL_INFO(dev)->gen >= 6)
545df6eedc8SBen Widawsky 		ret = sysfs_create_files(&dev->primary->kdev.kobj, gen6_attrs);
546df6eedc8SBen Widawsky 	if (ret)
54797e4eed7SChris Wilson 		DRM_ERROR("RPS sysfs setup failed\n");
548ef86ddceSMika Kuoppala 
549ef86ddceSMika Kuoppala 	ret = sysfs_create_bin_file(&dev->primary->kdev.kobj,
550ef86ddceSMika Kuoppala 				    &error_state_attr);
551ef86ddceSMika Kuoppala 	if (ret)
552ef86ddceSMika Kuoppala 		DRM_ERROR("error_state sysfs setup failed\n");
553112abd29SDaniel Vetter }
5540136db58SBen Widawsky 
5550136db58SBen Widawsky void i915_teardown_sysfs(struct drm_device *dev)
5560136db58SBen Widawsky {
557ef86ddceSMika Kuoppala 	sysfs_remove_bin_file(&dev->primary->kdev.kobj, &error_state_attr);
55897e4eed7SChris Wilson 	if (IS_VALLEYVIEW(dev))
55997e4eed7SChris Wilson 		sysfs_remove_files(&dev->primary->kdev.kobj, vlv_attrs);
56097e4eed7SChris Wilson 	else
561df6eedc8SBen Widawsky 		sysfs_remove_files(&dev->primary->kdev.kobj, gen6_attrs);
56235a85ac6SBen Widawsky 	device_remove_bin_file(&dev->primary->kdev,  &dpf_attrs_1);
56384bc7581SBen Widawsky 	device_remove_bin_file(&dev->primary->kdev,  &dpf_attrs);
564853c70e8SBen Widawsky #ifdef CONFIG_PM
5650136db58SBen Widawsky 	sysfs_unmerge_group(&dev->primary->kdev.kobj, &rc6_attr_group);
566853c70e8SBen Widawsky #endif
5670136db58SBen Widawsky }
568