xref: /openbsd-src/sys/dev/pci/drm/i915/i915_sysfs.c (revision f005ef32267c16bdb134f0e9fa4477dbe07c263a)
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 
33 #include "gt/intel_gt_regs.h"
34 #include "gt/intel_rc6.h"
35 #include "gt/intel_rps.h"
36 #include "gt/sysfs_engines.h"
37 
38 #include "i915_drv.h"
39 #include "i915_sysfs.h"
40 
41 #ifdef __linux__
42 
kdev_minor_to_i915(struct device * kdev)43 struct drm_i915_private *kdev_minor_to_i915(struct device *kdev)
44 {
45 	struct drm_minor *minor = dev_get_drvdata(kdev);
46 	return to_i915(minor->dev);
47 }
48 
l3_access_valid(struct drm_i915_private * i915,loff_t offset)49 static int l3_access_valid(struct drm_i915_private *i915, loff_t offset)
50 {
51 	if (!HAS_L3_DPF(i915))
52 		return -EPERM;
53 
54 	if (!IS_ALIGNED(offset, sizeof(u32)))
55 		return -EINVAL;
56 
57 	if (offset >= GEN7_L3LOG_SIZE)
58 		return -ENXIO;
59 
60 	return 0;
61 }
62 
63 static ssize_t
i915_l3_read(struct file * filp,struct kobject * kobj,struct bin_attribute * attr,char * buf,loff_t offset,size_t count)64 i915_l3_read(struct file *filp, struct kobject *kobj,
65 	     struct bin_attribute *attr, char *buf,
66 	     loff_t offset, size_t count)
67 {
68 	struct device *kdev = kobj_to_dev(kobj);
69 	struct drm_i915_private *i915 = kdev_minor_to_i915(kdev);
70 	int slice = (int)(uintptr_t)attr->private;
71 	int ret;
72 
73 	ret = l3_access_valid(i915, offset);
74 	if (ret)
75 		return ret;
76 
77 	count = round_down(count, sizeof(u32));
78 	count = min_t(size_t, GEN7_L3LOG_SIZE - offset, count);
79 	memset(buf, 0, count);
80 
81 	spin_lock(&i915->gem.contexts.lock);
82 	if (i915->l3_parity.remap_info[slice])
83 		memcpy(buf,
84 		       i915->l3_parity.remap_info[slice] + offset / sizeof(u32),
85 		       count);
86 	spin_unlock(&i915->gem.contexts.lock);
87 
88 	return count;
89 }
90 
91 static ssize_t
i915_l3_write(struct file * filp,struct kobject * kobj,struct bin_attribute * attr,char * buf,loff_t offset,size_t count)92 i915_l3_write(struct file *filp, struct kobject *kobj,
93 	      struct bin_attribute *attr, char *buf,
94 	      loff_t offset, size_t count)
95 {
96 	struct device *kdev = kobj_to_dev(kobj);
97 	struct drm_i915_private *i915 = kdev_minor_to_i915(kdev);
98 	int slice = (int)(uintptr_t)attr->private;
99 	u32 *remap_info, *freeme = NULL;
100 	struct i915_gem_context *ctx;
101 	int ret;
102 
103 	ret = l3_access_valid(i915, offset);
104 	if (ret)
105 		return ret;
106 
107 	if (count < sizeof(u32))
108 		return -EINVAL;
109 
110 	remap_info = kzalloc(GEN7_L3LOG_SIZE, GFP_KERNEL);
111 	if (!remap_info)
112 		return -ENOMEM;
113 
114 	spin_lock(&i915->gem.contexts.lock);
115 
116 	if (i915->l3_parity.remap_info[slice]) {
117 		freeme = remap_info;
118 		remap_info = i915->l3_parity.remap_info[slice];
119 	} else {
120 		i915->l3_parity.remap_info[slice] = remap_info;
121 	}
122 
123 	count = round_down(count, sizeof(u32));
124 	memcpy(remap_info + offset / sizeof(u32), buf, count);
125 
126 	/* NB: We defer the remapping until we switch to the context */
127 	list_for_each_entry(ctx, &i915->gem.contexts.list, link)
128 		ctx->remap_slice |= BIT(slice);
129 
130 	spin_unlock(&i915->gem.contexts.lock);
131 	kfree(freeme);
132 
133 	/*
134 	 * TODO: Ideally we really want a GPU reset here to make sure errors
135 	 * aren't propagated. Since I cannot find a stable way to reset the GPU
136 	 * at this point it is left as a TODO.
137 	*/
138 
139 	return count;
140 }
141 
142 static const struct bin_attribute dpf_attrs = {
143 	.attr = {.name = "l3_parity", .mode = (S_IRUSR | S_IWUSR)},
144 	.size = GEN7_L3LOG_SIZE,
145 	.read = i915_l3_read,
146 	.write = i915_l3_write,
147 	.mmap = NULL,
148 	.private = (void *)0
149 };
150 
151 static const struct bin_attribute dpf_attrs_1 = {
152 	.attr = {.name = "l3_parity_slice_1", .mode = (S_IRUSR | S_IWUSR)},
153 	.size = GEN7_L3LOG_SIZE,
154 	.read = i915_l3_read,
155 	.write = i915_l3_write,
156 	.mmap = NULL,
157 	.private = (void *)1
158 };
159 
160 #if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR)
161 
error_state_read(struct file * filp,struct kobject * kobj,struct bin_attribute * attr,char * buf,loff_t off,size_t count)162 static ssize_t error_state_read(struct file *filp, struct kobject *kobj,
163 				struct bin_attribute *attr, char *buf,
164 				loff_t off, size_t count)
165 {
166 
167 	struct device *kdev = kobj_to_dev(kobj);
168 	struct drm_i915_private *i915 = kdev_minor_to_i915(kdev);
169 	struct i915_gpu_coredump *gpu;
170 	ssize_t ret = 0;
171 
172 	/*
173 	 * FIXME: Concurrent clients triggering resets and reading + clearing
174 	 * dumps can cause inconsistent sysfs reads when a user calls in with a
175 	 * non-zero offset to complete a prior partial read but the
176 	 * gpu_coredump has been cleared or replaced.
177 	 */
178 
179 	gpu = i915_first_error_state(i915);
180 	if (IS_ERR(gpu)) {
181 		ret = PTR_ERR(gpu);
182 	} else if (gpu) {
183 		ret = i915_gpu_coredump_copy_to_buffer(gpu, buf, off, count);
184 		i915_gpu_coredump_put(gpu);
185 	} else {
186 		const char *str = "No error state collected\n";
187 		size_t len = strlen(str);
188 
189 		if (off < len) {
190 			ret = min_t(size_t, count, len - off);
191 			memcpy(buf, str + off, ret);
192 		}
193 	}
194 
195 	return ret;
196 }
197 
error_state_write(struct file * file,struct kobject * kobj,struct bin_attribute * attr,char * buf,loff_t off,size_t count)198 static ssize_t error_state_write(struct file *file, struct kobject *kobj,
199 				 struct bin_attribute *attr, char *buf,
200 				 loff_t off, size_t count)
201 {
202 	struct device *kdev = kobj_to_dev(kobj);
203 	struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
204 
205 	drm_dbg(&dev_priv->drm, "Resetting error state\n");
206 	i915_reset_error_state(dev_priv);
207 
208 	return count;
209 }
210 
211 static const struct bin_attribute error_state_attr = {
212 	.attr.name = "error",
213 	.attr.mode = S_IRUSR | S_IWUSR,
214 	.size = 0,
215 	.read = error_state_read,
216 	.write = error_state_write,
217 };
218 
i915_setup_error_capture(struct device * kdev)219 static void i915_setup_error_capture(struct device *kdev)
220 {
221 	if (sysfs_create_bin_file(&kdev->kobj, &error_state_attr))
222 		drm_err(&kdev_minor_to_i915(kdev)->drm,
223 			"error_state sysfs setup failed\n");
224 }
225 
i915_teardown_error_capture(struct device * kdev)226 static void i915_teardown_error_capture(struct device *kdev)
227 {
228 	sysfs_remove_bin_file(&kdev->kobj, &error_state_attr);
229 }
230 #else
i915_setup_error_capture(struct device * kdev)231 static void i915_setup_error_capture(struct device *kdev) {}
i915_teardown_error_capture(struct device * kdev)232 static void i915_teardown_error_capture(struct device *kdev) {}
233 #endif
234 
235 #endif /* __linux__ */
236 
i915_setup_sysfs(struct drm_i915_private * dev_priv)237 void i915_setup_sysfs(struct drm_i915_private *dev_priv)
238 {
239 #ifdef __linux__
240 	struct device *kdev = dev_priv->drm.primary->kdev;
241 	int ret;
242 
243 	if (HAS_L3_DPF(dev_priv)) {
244 		ret = device_create_bin_file(kdev, &dpf_attrs);
245 		if (ret)
246 			drm_err(&dev_priv->drm,
247 				"l3 parity sysfs setup failed\n");
248 
249 		if (NUM_L3_SLICES(dev_priv) > 1) {
250 			ret = device_create_bin_file(kdev,
251 						     &dpf_attrs_1);
252 			if (ret)
253 				drm_err(&dev_priv->drm,
254 					"l3 parity slice 1 setup failed\n");
255 		}
256 	}
257 
258 	dev_priv->sysfs_gt = kobject_create_and_add("gt", &kdev->kobj);
259 	if (!dev_priv->sysfs_gt)
260 		drm_warn(&dev_priv->drm,
261 			 "failed to register GT sysfs directory\n");
262 
263 	i915_setup_error_capture(kdev);
264 
265 	intel_engines_add_sysfs(dev_priv);
266 #endif /* __linux__ */
267 }
268 
i915_teardown_sysfs(struct drm_i915_private * dev_priv)269 void i915_teardown_sysfs(struct drm_i915_private *dev_priv)
270 {
271 #ifdef __linux__
272 	struct device *kdev = dev_priv->drm.primary->kdev;
273 
274 	i915_teardown_error_capture(kdev);
275 
276 	device_remove_bin_file(kdev,  &dpf_attrs_1);
277 	device_remove_bin_file(kdev,  &dpf_attrs);
278 #endif /* __linux__ */
279 
280 	kobject_put(dev_priv->sysfs_gt);
281 }
282