Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ef86ddce authored by Mika Kuoppala's avatar Mika Kuoppala Committed by Daniel Vetter
Browse files

drm/i915: add error_state sysfs entry



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: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: default avatarMika Kuoppala <mika.kuoppala@intel.com>
Reviewed-by: default avatarChris 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: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent 4dc955f7
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -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);
+71 −0
Original line number Diff line number Diff line
@@ -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