drm/i915: add error_state sysfs entry
authorMika Kuoppala <mika.kuoppala@linux.intel.com>
Thu, 6 Jun 2013 14:38:54 +0000 (17:38 +0300)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Mon, 1 Jul 2013 17:39:31 +0000 (19:39 +0200)
As getting error state doesn't anymore require big kmallocs,
make error state accessible also from sysfs.

v2: - error state clearing (Chris Wilson)
    - user hint, proper access mode bits and name (Daniel Vetter)

v3: release resources in proper order (Chris Wilson)

Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Mika Kuoppala <mika.kuoppala@intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
[danvet: Apply Chris' s/error_state/error/ bikeshed on the sysfs
name. Also update the dmesg message, spotted by Chris.]
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_sysfs.c

index 6ca6097aa48fedc708c0e7fffef6ebbcdf96251e..4c1b1e3dbf79a0104e28480e5a52918460c385ca 100644 (file)
@@ -1921,8 +1921,7 @@ static void i915_capture_error_state(struct drm_device *dev)
        }
 
        DRM_INFO("capturing error event; look for more information in "
-                "/sys/kernel/debug/dri/%d/i915_error_state\n",
-                dev->primary->index);
+                "/sys/class/drm/card%d/error\n", dev->primary->index);
 
        kref_init(&error->ref);
        error->eir = I915_READ(EIR);
index 6875b5654c63d55a65dcf639734e0de101f1f037..a777e7f3b0df924c7e7d2401b3994f6b8e963f3c 100644 (file)
@@ -409,6 +409,71 @@ static const struct attribute *gen6_attrs[] = {
        NULL,
 };
 
+static ssize_t error_state_read(struct file *filp, struct kobject *kobj,
+                               struct bin_attribute *attr, char *buf,
+                               loff_t off, size_t count)
+{
+
+       struct device *kdev = container_of(kobj, struct device, kobj);
+       struct drm_minor *minor = container_of(kdev, struct drm_minor, kdev);
+       struct drm_device *dev = minor->dev;
+       struct i915_error_state_file_priv error_priv;
+       struct drm_i915_error_state_buf error_str;
+       ssize_t ret_count = 0;
+       int ret;
+
+       memset(&error_priv, 0, sizeof(error_priv));
+
+       ret = i915_error_state_buf_init(&error_str, count, off);
+       if (ret)
+               return ret;
+
+       error_priv.dev = dev;
+       i915_error_state_get(dev, &error_priv);
+
+       ret = i915_error_state_to_str(&error_str, &error_priv);
+       if (ret)
+               goto out;
+
+       ret_count = count < error_str.bytes ? count : error_str.bytes;
+
+       memcpy(buf, error_str.buf, ret_count);
+out:
+       i915_error_state_put(&error_priv);
+       i915_error_state_buf_release(&error_str);
+
+       return ret ?: ret_count;
+}
+
+static ssize_t error_state_write(struct file *file, struct kobject *kobj,
+                                struct bin_attribute *attr, char *buf,
+                                loff_t off, size_t count)
+{
+       struct device *kdev = container_of(kobj, struct device, kobj);
+       struct drm_minor *minor = container_of(kdev, struct drm_minor, kdev);
+       struct drm_device *dev = minor->dev;
+       int ret;
+
+       DRM_DEBUG_DRIVER("Resetting error state\n");
+
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
+
+       i915_destroy_error_state(dev);
+       mutex_unlock(&dev->struct_mutex);
+
+       return count;
+}
+
+static struct bin_attribute error_state_attr = {
+       .attr.name = "error",
+       .attr.mode = S_IRUSR | S_IWUSR,
+       .size = 0,
+       .read = error_state_read,
+       .write = error_state_write,
+};
+
 void i915_setup_sysfs(struct drm_device *dev)
 {
        int ret;
@@ -432,10 +497,16 @@ void i915_setup_sysfs(struct drm_device *dev)
                if (ret)
                        DRM_ERROR("gen6 sysfs setup failed\n");
        }
+
+       ret = sysfs_create_bin_file(&dev->primary->kdev.kobj,
+                                   &error_state_attr);
+       if (ret)
+               DRM_ERROR("error_state sysfs setup failed\n");
 }
 
 void i915_teardown_sysfs(struct drm_device *dev)
 {
+       sysfs_remove_bin_file(&dev->primary->kdev.kobj, &error_state_attr);
        sysfs_remove_files(&dev->primary->kdev.kobj, gen6_attrs);
        device_remove_bin_file(&dev->primary->kdev,  &dpf_attrs);
 #ifdef CONFIG_PM