xref: /openbmc/linux/drivers/gpu/drm/i915/i915_sysfs.c (revision a10234fda4664f9ffe9608abe1e99b51815113f5)
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>
3256c5098fSChris Wilson 
330d6419e9SMatt Roper #include "gt/intel_gt_regs.h"
34c1132367SAndi Shyti #include "gt/intel_rc6.h"
353e7abf81SAndi Shyti #include "gt/intel_rps.h"
364ec76dbeSChris Wilson #include "gt/sysfs_engines.h"
37c1132367SAndi Shyti 
380136db58SBen Widawsky #include "i915_drv.h"
39be68261dSJani Nikula #include "i915_sysfs.h"
40ecbb5fb7SJani Nikula #include "intel_pm.h"
410136db58SBen Widawsky 
42b770bcfaSAndi Shyti struct drm_i915_private *kdev_minor_to_i915(struct device *kdev)
43c49d13eeSDavid Weinehall {
44694c2828SDavid Weinehall 	struct drm_minor *minor = dev_get_drvdata(kdev);
45694c2828SDavid Weinehall 	return to_i915(minor->dev);
46c49d13eeSDavid Weinehall }
4714c8d110SDave Airlie 
48261ea7e2SChris Wilson static int l3_access_valid(struct drm_i915_private *i915, loff_t offset)
4984bc7581SBen Widawsky {
50261ea7e2SChris Wilson 	if (!HAS_L3_DPF(i915))
5184bc7581SBen Widawsky 		return -EPERM;
5284bc7581SBen Widawsky 
53261ea7e2SChris Wilson 	if (!IS_ALIGNED(offset, sizeof(u32)))
5484bc7581SBen Widawsky 		return -EINVAL;
5584bc7581SBen Widawsky 
5684bc7581SBen Widawsky 	if (offset >= GEN7_L3LOG_SIZE)
5784bc7581SBen Widawsky 		return -ENXIO;
5884bc7581SBen Widawsky 
5984bc7581SBen Widawsky 	return 0;
6084bc7581SBen Widawsky }
6184bc7581SBen Widawsky 
6284bc7581SBen Widawsky static ssize_t
6384bc7581SBen Widawsky i915_l3_read(struct file *filp, struct kobject *kobj,
6484bc7581SBen Widawsky 	     struct bin_attribute *attr, char *buf,
6584bc7581SBen Widawsky 	     loff_t offset, size_t count)
6684bc7581SBen Widawsky {
67c49d13eeSDavid Weinehall 	struct device *kdev = kobj_to_dev(kobj);
68261ea7e2SChris Wilson 	struct drm_i915_private *i915 = kdev_minor_to_i915(kdev);
6935a85ac6SBen Widawsky 	int slice = (int)(uintptr_t)attr->private;
703ccfd19dSBen Widawsky 	int ret;
7184bc7581SBen Widawsky 
72261ea7e2SChris Wilson 	ret = l3_access_valid(i915, offset);
7384bc7581SBen Widawsky 	if (ret)
7484bc7581SBen Widawsky 		return ret;
7584bc7581SBen Widawsky 
76261ea7e2SChris Wilson 	count = round_down(count, sizeof(u32));
77e5ad4026SDan Carpenter 	count = min_t(size_t, GEN7_L3LOG_SIZE - offset, count);
781c966dd2SBen Widawsky 	memset(buf, 0, count);
791c966dd2SBen Widawsky 
80a4e7ccdaSChris Wilson 	spin_lock(&i915->gem.contexts.lock);
81261ea7e2SChris Wilson 	if (i915->l3_parity.remap_info[slice])
82261ea7e2SChris Wilson 		memcpy(buf,
83261ea7e2SChris Wilson 		       i915->l3_parity.remap_info[slice] + offset / sizeof(u32),
84261ea7e2SChris Wilson 		       count);
85a4e7ccdaSChris Wilson 	spin_unlock(&i915->gem.contexts.lock);
8684bc7581SBen Widawsky 
871c966dd2SBen Widawsky 	return count;
8884bc7581SBen Widawsky }
8984bc7581SBen Widawsky 
9084bc7581SBen Widawsky static ssize_t
9184bc7581SBen Widawsky i915_l3_write(struct file *filp, struct kobject *kobj,
9284bc7581SBen Widawsky 	      struct bin_attribute *attr, char *buf,
9384bc7581SBen Widawsky 	      loff_t offset, size_t count)
9484bc7581SBen Widawsky {
95c49d13eeSDavid Weinehall 	struct device *kdev = kobj_to_dev(kobj);
96261ea7e2SChris Wilson 	struct drm_i915_private *i915 = kdev_minor_to_i915(kdev);
9735a85ac6SBen Widawsky 	int slice = (int)(uintptr_t)attr->private;
98a4e7ccdaSChris Wilson 	u32 *remap_info, *freeme = NULL;
99261ea7e2SChris Wilson 	struct i915_gem_context *ctx;
10084bc7581SBen Widawsky 	int ret;
10184bc7581SBen Widawsky 
102261ea7e2SChris Wilson 	ret = l3_access_valid(i915, offset);
10384bc7581SBen Widawsky 	if (ret)
10484bc7581SBen Widawsky 		return ret;
10584bc7581SBen Widawsky 
106261ea7e2SChris Wilson 	if (count < sizeof(u32))
107261ea7e2SChris Wilson 		return -EINVAL;
108261ea7e2SChris Wilson 
109a4e7ccdaSChris Wilson 	remap_info = kzalloc(GEN7_L3LOG_SIZE, GFP_KERNEL);
110a4e7ccdaSChris Wilson 	if (!remap_info)
111a4e7ccdaSChris Wilson 		return -ENOMEM;
11284bc7581SBen Widawsky 
113a4e7ccdaSChris Wilson 	spin_lock(&i915->gem.contexts.lock);
114a4e7ccdaSChris Wilson 
115a4e7ccdaSChris Wilson 	if (i915->l3_parity.remap_info[slice]) {
116a4e7ccdaSChris Wilson 		freeme = remap_info;
117a4e7ccdaSChris Wilson 		remap_info = i915->l3_parity.remap_info[slice];
118a4e7ccdaSChris Wilson 	} else {
119a4e7ccdaSChris Wilson 		i915->l3_parity.remap_info[slice] = remap_info;
12084bc7581SBen Widawsky 	}
12184bc7581SBen Widawsky 
122261ea7e2SChris Wilson 	count = round_down(count, sizeof(u32));
123a4e7ccdaSChris Wilson 	memcpy(remap_info + offset / sizeof(u32), buf, count);
124261ea7e2SChris Wilson 
125261ea7e2SChris Wilson 	/* NB: We defer the remapping until we switch to the context */
126a4e7ccdaSChris Wilson 	list_for_each_entry(ctx, &i915->gem.contexts.list, link)
127261ea7e2SChris Wilson 		ctx->remap_slice |= BIT(slice);
128261ea7e2SChris Wilson 
129a4e7ccdaSChris Wilson 	spin_unlock(&i915->gem.contexts.lock);
130a4e7ccdaSChris Wilson 	kfree(freeme);
131a4e7ccdaSChris Wilson 
132261ea7e2SChris Wilson 	/*
133261ea7e2SChris Wilson 	 * TODO: Ideally we really want a GPU reset here to make sure errors
13484bc7581SBen Widawsky 	 * aren't propagated. Since I cannot find a stable way to reset the GPU
13584bc7581SBen Widawsky 	 * at this point it is left as a TODO.
13684bc7581SBen Widawsky 	*/
13784bc7581SBen Widawsky 
138a4e7ccdaSChris Wilson 	return count;
13984bc7581SBen Widawsky }
14084bc7581SBen Widawsky 
14159f3da1eSBhumika Goyal static const struct bin_attribute dpf_attrs = {
14284bc7581SBen Widawsky 	.attr = {.name = "l3_parity", .mode = (S_IRUSR | S_IWUSR)},
14384bc7581SBen Widawsky 	.size = GEN7_L3LOG_SIZE,
14484bc7581SBen Widawsky 	.read = i915_l3_read,
14584bc7581SBen Widawsky 	.write = i915_l3_write,
14635a85ac6SBen Widawsky 	.mmap = NULL,
14735a85ac6SBen Widawsky 	.private = (void *)0
14835a85ac6SBen Widawsky };
14935a85ac6SBen Widawsky 
15059f3da1eSBhumika Goyal static const struct bin_attribute dpf_attrs_1 = {
15135a85ac6SBen Widawsky 	.attr = {.name = "l3_parity_slice_1", .mode = (S_IRUSR | S_IWUSR)},
15235a85ac6SBen Widawsky 	.size = GEN7_L3LOG_SIZE,
15335a85ac6SBen Widawsky 	.read = i915_l3_read,
15435a85ac6SBen Widawsky 	.write = i915_l3_write,
15535a85ac6SBen Widawsky 	.mmap = NULL,
15635a85ac6SBen Widawsky 	.private = (void *)1
15784bc7581SBen Widawsky };
15884bc7581SBen Widawsky 
15998a2f411SChris Wilson #if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR)
16098a2f411SChris Wilson 
161ef86ddceSMika Kuoppala static ssize_t error_state_read(struct file *filp, struct kobject *kobj,
162ef86ddceSMika Kuoppala 				struct bin_attribute *attr, char *buf,
163ef86ddceSMika Kuoppala 				loff_t off, size_t count)
164ef86ddceSMika Kuoppala {
165ef86ddceSMika Kuoppala 
166657fb5fbSGeliang Tang 	struct device *kdev = kobj_to_dev(kobj);
1670e39037bSChris Wilson 	struct drm_i915_private *i915 = kdev_minor_to_i915(kdev);
168742379c0SChris Wilson 	struct i915_gpu_coredump *gpu;
1693304033aSAlan Previn 	ssize_t ret = 0;
1703304033aSAlan Previn 
1713304033aSAlan Previn 	/*
1723304033aSAlan Previn 	 * FIXME: Concurrent clients triggering resets and reading + clearing
1733304033aSAlan Previn 	 * dumps can cause inconsistent sysfs reads when a user calls in with a
1743304033aSAlan Previn 	 * non-zero offset to complete a prior partial read but the
1753304033aSAlan Previn 	 * gpu_coredump has been cleared or replaced.
1763304033aSAlan Previn 	 */
177ef86ddceSMika Kuoppala 
1780e39037bSChris Wilson 	gpu = i915_first_error_state(i915);
179e6154e4cSChris Wilson 	if (IS_ERR(gpu)) {
180e6154e4cSChris Wilson 		ret = PTR_ERR(gpu);
181e6154e4cSChris Wilson 	} else if (gpu) {
182742379c0SChris Wilson 		ret = i915_gpu_coredump_copy_to_buffer(gpu, buf, off, count);
183742379c0SChris Wilson 		i915_gpu_coredump_put(gpu);
1840e39037bSChris Wilson 	} else {
1850e39037bSChris Wilson 		const char *str = "No error state collected\n";
1860e39037bSChris Wilson 		size_t len = strlen(str);
1870e39037bSChris Wilson 
1883304033aSAlan Previn 		if (off < len) {
1890e39037bSChris Wilson 			ret = min_t(size_t, count, len - off);
1900e39037bSChris Wilson 			memcpy(buf, str + off, ret);
1910e39037bSChris Wilson 		}
1923304033aSAlan Previn 	}
193ef86ddceSMika Kuoppala 
1945a4c6f1bSChris Wilson 	return ret;
195ef86ddceSMika Kuoppala }
196ef86ddceSMika Kuoppala 
197ef86ddceSMika Kuoppala static ssize_t error_state_write(struct file *file, struct kobject *kobj,
198ef86ddceSMika Kuoppala 				 struct bin_attribute *attr, char *buf,
199ef86ddceSMika Kuoppala 				 loff_t off, size_t count)
200ef86ddceSMika Kuoppala {
201657fb5fbSGeliang Tang 	struct device *kdev = kobj_to_dev(kobj);
202694c2828SDavid Weinehall 	struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
203ef86ddceSMika Kuoppala 
20400376ccfSWambui Karuga 	drm_dbg(&dev_priv->drm, "Resetting error state\n");
2055a4c6f1bSChris Wilson 	i915_reset_error_state(dev_priv);
206ef86ddceSMika Kuoppala 
207ef86ddceSMika Kuoppala 	return count;
208ef86ddceSMika Kuoppala }
209ef86ddceSMika Kuoppala 
21059f3da1eSBhumika Goyal static const struct bin_attribute error_state_attr = {
211ef86ddceSMika Kuoppala 	.attr.name = "error",
212ef86ddceSMika Kuoppala 	.attr.mode = S_IRUSR | S_IWUSR,
213ef86ddceSMika Kuoppala 	.size = 0,
214ef86ddceSMika Kuoppala 	.read = error_state_read,
215ef86ddceSMika Kuoppala 	.write = error_state_write,
216ef86ddceSMika Kuoppala };
217ef86ddceSMika Kuoppala 
21898a2f411SChris Wilson static void i915_setup_error_capture(struct device *kdev)
21998a2f411SChris Wilson {
22098a2f411SChris Wilson 	if (sysfs_create_bin_file(&kdev->kobj, &error_state_attr))
221*a10234fdSTvrtko Ursulin 		drm_err(&kdev_minor_to_i915(kdev)->drm,
222*a10234fdSTvrtko Ursulin 			"error_state sysfs setup failed\n");
22398a2f411SChris Wilson }
22498a2f411SChris Wilson 
22598a2f411SChris Wilson static void i915_teardown_error_capture(struct device *kdev)
22698a2f411SChris Wilson {
22798a2f411SChris Wilson 	sysfs_remove_bin_file(&kdev->kobj, &error_state_attr);
22898a2f411SChris Wilson }
22998a2f411SChris Wilson #else
23098a2f411SChris Wilson static void i915_setup_error_capture(struct device *kdev) {}
23198a2f411SChris Wilson static void i915_teardown_error_capture(struct device *kdev) {}
23298a2f411SChris Wilson #endif
23398a2f411SChris Wilson 
234694c2828SDavid Weinehall void i915_setup_sysfs(struct drm_i915_private *dev_priv)
2350136db58SBen Widawsky {
236694c2828SDavid Weinehall 	struct device *kdev = dev_priv->drm.primary->kdev;
2370136db58SBen Widawsky 	int ret;
2380136db58SBen Widawsky 
239694c2828SDavid Weinehall 	if (HAS_L3_DPF(dev_priv)) {
240694c2828SDavid Weinehall 		ret = device_create_bin_file(kdev, &dpf_attrs);
24184bc7581SBen Widawsky 		if (ret)
24200376ccfSWambui Karuga 			drm_err(&dev_priv->drm,
24300376ccfSWambui Karuga 				"l3 parity sysfs setup failed\n");
24435a85ac6SBen Widawsky 
245694c2828SDavid Weinehall 		if (NUM_L3_SLICES(dev_priv) > 1) {
246694c2828SDavid Weinehall 			ret = device_create_bin_file(kdev,
24735a85ac6SBen Widawsky 						     &dpf_attrs_1);
24835a85ac6SBen Widawsky 			if (ret)
24900376ccfSWambui Karuga 				drm_err(&dev_priv->drm,
25000376ccfSWambui Karuga 					"l3 parity slice 1 setup failed\n");
25135a85ac6SBen Widawsky 		}
2520136db58SBen Widawsky 	}
253df6eedc8SBen Widawsky 
254b770bcfaSAndi Shyti 	dev_priv->sysfs_gt = kobject_create_and_add("gt", &kdev->kobj);
255b770bcfaSAndi Shyti 	if (!dev_priv->sysfs_gt)
256b770bcfaSAndi Shyti 		drm_warn(&dev_priv->drm,
257b770bcfaSAndi Shyti 			 "failed to register GT sysfs directory\n");
258b770bcfaSAndi Shyti 
25998a2f411SChris Wilson 	i915_setup_error_capture(kdev);
2604ec76dbeSChris Wilson 
2614ec76dbeSChris Wilson 	intel_engines_add_sysfs(dev_priv);
262112abd29SDaniel Vetter }
2630136db58SBen Widawsky 
264694c2828SDavid Weinehall void i915_teardown_sysfs(struct drm_i915_private *dev_priv)
2650136db58SBen Widawsky {
266694c2828SDavid Weinehall 	struct device *kdev = dev_priv->drm.primary->kdev;
267694c2828SDavid Weinehall 
26898a2f411SChris Wilson 	i915_teardown_error_capture(kdev);
26998a2f411SChris Wilson 
270694c2828SDavid Weinehall 	device_remove_bin_file(kdev,  &dpf_attrs_1);
271694c2828SDavid Weinehall 	device_remove_bin_file(kdev,  &dpf_attrs);
27269d6bf5cSAshutosh Dixit 
27369d6bf5cSAshutosh Dixit 	kobject_put(dev_priv->sysfs_gt);
2740136db58SBen Widawsky }
275