diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 3f676f9..7d599f1 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1984,6 +1984,7 @@ void i915_driver_postclose(struct drm_device *dev, struct drm_file *file)
 {
 	struct drm_i915_file_private *file_priv = file->driver_priv;
 
+	kfree(file_priv->process_name);
 	if (file_priv && file_priv->bsd_ring)
 		file_priv->bsd_ring = NULL;
 	kfree(file_priv);
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 01de977..1c4cd6d7 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -1527,6 +1527,8 @@ static struct drm_driver driver = {
 	.debugfs_init = i915_debugfs_init,
 	.debugfs_cleanup = i915_debugfs_cleanup,
 #endif
+	.gem_open_object = i915_gem_open_object,
+	.gem_close_object = i915_gem_close_object,
 	.gem_free_object = i915_gem_free_object,
 	.gem_vm_ops = &i915_gem_vm_ops,
 
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 541fb6f..ccb3db3 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1846,6 +1846,12 @@ struct drm_i915_gem_object {
 			struct work_struct *work;
 		} userptr;
 	};
+
+#define MAX_OPEN_HANDLE 20
+	struct {
+		pid_t pid;
+		int open_handle_count;
+	} pid_array[MAX_OPEN_HANDLE];
 };
 #define to_intel_bo(x) container_of(x, struct drm_i915_gem_object, base)
 
@@ -1896,6 +1902,7 @@ struct drm_i915_gem_request {
 struct drm_i915_file_private {
 	struct drm_i915_private *dev_priv;
 	struct drm_file *file;
+	char *process_name;
 
 	struct {
 		spinlock_t lock;
@@ -2325,6 +2332,10 @@ void i915_init_vm(struct drm_i915_private *dev_priv,
 		  struct i915_address_space *vm);
 void i915_gem_free_object(struct drm_gem_object *obj);
 void i915_gem_vma_destroy(struct i915_vma *vma);
+int i915_gem_open_object(struct drm_gem_object *gem_obj,
+			struct drm_file *file_priv);
+int i915_gem_close_object(struct drm_gem_object *gem_obj,
+			struct drm_file *file_priv);
 
 #define PIN_MAPPABLE 0x1
 #define PIN_NONBLOCK 0x2
@@ -2375,6 +2386,7 @@ int i915_gem_dumb_create(struct drm_file *file_priv,
 			 struct drm_mode_create_dumb *args);
 int i915_gem_mmap_gtt(struct drm_file *file_priv, struct drm_device *dev,
 		      uint32_t handle, uint64_t *offset);
+int i915_gem_obj_shmem_pages_alloced(struct drm_i915_gem_object *obj);
 /**
  * Returns true if seq1 is later than seq2.
  */
@@ -2643,6 +2655,10 @@ int i915_verify_lists(struct drm_device *dev);
 #else
 #define i915_verify_lists(dev) 0
 #endif
+int i915_get_drm_clients_info(struct drm_i915_error_state_buf *m,
+			struct drm_device *dev);
+int i915_gem_get_all_obj_info(struct drm_i915_error_state_buf *m,
+			struct drm_device *dev);
 
 /* i915_debugfs.c */
 int i915_debugfs_init(struct drm_minor *minor);
@@ -2656,6 +2672,8 @@ static inline void intel_display_crc_init(struct drm_device *dev) {}
 /* i915_gpu_error.c */
 __printf(2, 3)
 void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...);
+void i915_error_puts(struct drm_i915_error_state_buf *e,
+			    const char *str);
 int i915_error_state_to_str(struct drm_i915_error_state_buf *estr,
 			    const struct i915_error_state_file_priv *error);
 int i915_error_state_buf_init(struct drm_i915_error_state_buf *eb,
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 6c2f0b8..c464a75 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1819,6 +1819,25 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data,
 	return i915_gem_mmap_gtt(file, dev, args->handle, &args->offset);
 }
 
+int i915_gem_obj_shmem_pages_alloced(struct drm_i915_gem_object *obj)
+{
+	int ret;
+
+	if (obj->base.filp) {
+		struct inode *inode = file_inode(obj->base.filp);
+		struct shmem_inode_info *info = SHMEM_I(inode);
+
+		if (!inode)
+			return 0;
+		spin_lock(&info->lock);
+		ret = inode->i_mapping->nrpages;
+		spin_unlock(&info->lock);
+		return ret;
+	} else
+		return 0;
+
+}
+
 static inline int
 i915_gem_object_is_purgeable(struct drm_i915_gem_object *obj)
 {
@@ -4402,6 +4421,57 @@ static bool discard_backing_storage(struct drm_i915_gem_object *obj)
 	return atomic_long_read(&obj->base.filp->f_count) == 1;
 }
 
+int
+i915_gem_open_object(struct drm_gem_object *gem_obj, struct drm_file *file_priv)
+{
+	struct drm_i915_gem_object *obj = to_intel_bo(gem_obj);
+	pid_t current_pid = task_pid_nr(current);
+	int i, free = -1;
+
+	for (i = 0; i < MAX_OPEN_HANDLE; i++) {
+		if (obj->pid_array[i].pid == current_pid) {
+			obj->pid_array[i].open_handle_count++;
+			break;
+		} else if (obj->pid_array[i].pid == 0)
+			free = i;
+	}
+
+	if (i == MAX_OPEN_HANDLE) {
+		if (free != -1) {
+			BUG_ON(obj->pid_array[free].open_handle_count);
+			obj->pid_array[free].open_handle_count = 1;
+			obj->pid_array[free].pid = current_pid;
+		} else
+			DRM_DEBUG("Max open handle count limit: obj 0x%x\n",
+					(u32) obj);
+	}
+	return 0;
+}
+
+int
+i915_gem_close_object(struct drm_gem_object *gem_obj,
+			struct drm_file *file_priv)
+{
+	struct drm_i915_gem_object *obj = to_intel_bo(gem_obj);
+	pid_t current_pid = task_pid_nr(current);
+	int i;
+
+	for (i = 0; i < MAX_OPEN_HANDLE; i++) {
+		if (obj->pid_array[i].pid == current_pid) {
+			obj->pid_array[i].open_handle_count--;
+			if (obj->pid_array[i].open_handle_count == 0)
+				obj->pid_array[i].pid = 0;
+			break;
+		}
+	}
+	if (i == MAX_OPEN_HANDLE)
+		DRM_DEBUG("Couldn't find matching pid %d for obj 0x%x\n",
+				current_pid, (u32) obj);
+	return 0;
+
+}
+
+
 void i915_gem_free_object(struct drm_gem_object *gem_obj)
 {
 	struct drm_i915_gem_object *obj = to_intel_bo(gem_obj);
@@ -4992,6 +5062,46 @@ i915_gem_file_idle_work_handler(struct work_struct *work)
 	atomic_set(&file_priv->rps_wait_boost, false);
 }
 
+static int i915_gem_get_pid_cmdline(struct task_struct *task, char *buffer)
+{
+	int res = 0;
+	unsigned int len;
+	struct mm_struct *mm = get_task_mm(task);
+
+	if (!mm)
+		goto out;
+	if (!mm->arg_end)
+		goto out_mm;
+
+	len = mm->arg_end - mm->arg_start;
+
+	if (len > PAGE_SIZE)
+		len = PAGE_SIZE;
+
+	res = access_process_vm(task, mm->arg_start, buffer, len, 0);
+
+	/* If the null at the end of args has been overwritten, then
+	 * assume application is using setproctitle(3).
+	 */
+	if (res > 0 && buffer[res-1] != '\0' && len < PAGE_SIZE) {
+		len = strnlen(buffer, res);
+		if (len < res) {
+			res = len;
+		} else {
+			len = mm->env_end - mm->env_start;
+			if (len > PAGE_SIZE - res)
+				len = PAGE_SIZE - res;
+			res += access_process_vm(task, mm->env_start,
+					buffer+res, len, 0);
+			res = strnlen(buffer, res);
+		}
+	}
+out_mm:
+	mmput(mm);
+out:
+	return res;
+}
+
 int i915_gem_open(struct drm_device *dev, struct drm_file *file)
 {
 	struct drm_i915_file_private *file_priv;
@@ -5006,6 +5116,11 @@ int i915_gem_open(struct drm_device *dev, struct drm_file *file)
 	file->driver_priv = file_priv;
 	file_priv->dev_priv = dev->dev_private;
 	file_priv->file = file;
+	file_priv->process_name =  kzalloc(PAGE_SIZE, GFP_ATOMIC);
+	if (!file_priv->process_name)
+		return -ENOMEM;
+
+	i915_gem_get_pid_cmdline(current, file_priv->process_name);
 
 	spin_lock_init(&file_priv->mm.lock);
 	INIT_LIST_HEAD(&file_priv->mm.request_list);
diff --git a/drivers/gpu/drm/i915/i915_gem_debug.c b/drivers/gpu/drm/i915/i915_gem_debug.c
index f462d1b..36d1980 100644
--- a/drivers/gpu/drm/i915/i915_gem_debug.c
+++ b/drivers/gpu/drm/i915/i915_gem_debug.c
@@ -116,3 +116,369 @@ i915_verify_lists(struct drm_device *dev)
 	return warned = err;
 }
 #endif /* WATCH_LIST */
+
+struct per_file_obj_mem_info {
+	int NumofObjects;
+	int NumofShared;
+	int NumofPrivate;
+	int NumofGttBinded;
+	int NumofPurged;
+	int NumofPurgeable;
+	int NumofAllocated;
+	int NumFaultMappable;
+	int NumofStolen;
+	size_t GttSpaceAllocatedShared;
+	size_t GttSpaceAllocatedPriv;
+	size_t PhysicalSpaceAllocatedShared;
+	size_t PhysicalSpaceAllocatedPriv;
+	size_t PhysicalSpacePurgeable;
+	size_t PhysicalSpaceSharedProportion;
+	size_t FaultMappableSize;
+	size_t StolenSpaceAllocated;
+	char *process_name;
+};
+
+struct name_entry {
+	struct list_head head;
+	struct drm_hash_item hash_item;
+};
+
+struct pid_stat_entry {
+	struct list_head head;
+	struct list_head namefree;
+	struct drm_open_hash namelist;
+	struct per_file_obj_mem_info stats;
+	struct pid *pid;
+	int pid_nr;
+};
+
+static struct list_head per_pid_stats;
+
+#define err_printf(e, ...) i915_error_printf(e, __VA_ARGS__)
+#define err_puts(e, s) i915_error_puts(e, s)
+
+static const char *get_pin_flag(struct drm_i915_gem_object *obj)
+{
+	if (obj->user_pin_count > 0)
+		return "P";
+	else if (i915_gem_obj_is_pinned(obj))
+		return "p";
+	else
+		return " ";
+}
+
+static const char *get_tiling_flag(struct drm_i915_gem_object *obj)
+{
+	switch (obj->tiling_mode) {
+	default:
+	case I915_TILING_NONE: return " ";
+	case I915_TILING_X: return "X";
+	case I915_TILING_Y: return "Y";
+	}
+}
+
+static void i915_obj_pidarray_validate(struct drm_gem_object *gem_obj)
+{
+	struct drm_i915_gem_object *obj = to_intel_bo(gem_obj);
+	struct drm_device *dev = gem_obj->dev;
+	struct drm_file *file;
+	struct pid *pid;
+	int pid_nr, i, present;
+
+	/* Run a sanity check on pid_array. All entries in pid_array should
+	 * be subset of the the drm filelist pid entries.
+	 */
+	for (i = 0; i < MAX_OPEN_HANDLE; i++) {
+		present = 0;
+		list_for_each_entry(file, &dev->filelist, lhead) {
+			pid = file->pid;
+			pid_nr = pid->numbers[pid->level].nr;
+			if (pid_nr == obj->pid_array[i].pid) {
+				present = 1;
+				break;
+			}
+		}
+		if (present == 0) {
+			obj->pid_array[i].open_handle_count = 0;
+			obj->pid_array[i].pid = 0;
+		}
+	}
+}
+
+
+static int
+i915_describe_obj(struct drm_i915_error_state_buf *m,
+			struct drm_i915_gem_object *obj)
+{
+	int i;
+	struct i915_vma *vma;
+
+	err_printf(m, "%p: %8zdK  %s    %s     %s      %s     %s      %s       %s     ",
+		   &obj->base,
+		   obj->base.size / 1024,
+		   get_pin_flag(obj),
+		   get_tiling_flag(obj),
+		   obj->dirty ? "Y" : "N",
+		   obj->base.name ? "Y" : "N",
+		   (obj->userptr.mm != 0) ? "Y" : "N",
+		   obj->stolen ? "Y" : "N",
+		   (obj->pin_mappable || obj->fault_mappable) ? "Y" : "N");
+
+	if (obj->madv == __I915_MADV_PURGED)
+		err_printf(m, " purged    ");
+	else if (obj->madv == I915_MADV_DONTNEED)
+		err_printf(m, " purgeable   ");
+	else if (i915_gem_obj_shmem_pages_alloced(obj) != 0)
+		err_printf(m, " allocated   ");
+
+
+	list_for_each_entry(vma, &obj->vma_list, vma_link) {
+		if (!i915_is_ggtt(vma->vm))
+			err_puts(m, " PP    ");
+		else
+			err_puts(m, " G     ");
+		err_printf(m, "  %08lx ", vma->node.start);
+	}
+
+	for (i = 0; i < MAX_OPEN_HANDLE; i++) {
+		if (obj->pid_array[i].pid != 0) {
+			err_printf(m, " (%d: %d) ",
+			obj->pid_array[i].pid,
+			obj->pid_array[i].open_handle_count);
+		}
+	}
+
+	err_printf(m, "\n");
+
+	if (m->bytes == 0 && m->err)
+		return m->err;
+
+	return 0;
+}
+
+static int
+i915_drm_gem_obj_info(int id, void *ptr, void *data)
+{
+	struct drm_i915_gem_object *obj = ptr;
+	struct drm_i915_error_state_buf *m = data;
+	int ret;
+
+	i915_obj_pidarray_validate(&obj->base);
+	ret = i915_describe_obj(m, obj);
+
+	return ret;
+}
+
+static int
+i915_drm_gem_object_per_file_summary(int id, void *ptr, void *data)
+{
+	struct pid_stat_entry *pid_entry = data;
+	struct drm_i915_gem_object *obj = ptr;
+	struct per_file_obj_mem_info *stats = &pid_entry->stats;
+	struct drm_hash_item *hash_item;
+	int i, num_pages, obj_shared_count = 0;
+
+	i915_obj_pidarray_validate(&obj->base);
+
+	stats->NumofObjects++;
+
+	if (obj->base.name) {
+
+		if (drm_ht_find_item(&pid_entry->namelist,
+				(unsigned long)obj->base.name, &hash_item)) {
+			struct name_entry *entry =
+				kzalloc(sizeof(struct name_entry), GFP_KERNEL);
+			if (entry == NULL) {
+				DRM_ERROR("alloc failed\n");
+				return -ENOMEM;
+			}
+			entry->hash_item.key = obj->base.name;
+			drm_ht_insert_item(&pid_entry->namelist,
+						&entry->hash_item);
+			list_add_tail(&entry->head, &pid_entry->namefree);
+		} else {
+			DRM_DEBUG("Duplicate obj with name %d for process %s\n",
+				obj->base.name, stats->process_name);
+			return 0;
+		}
+		for (i = 0; i < MAX_OPEN_HANDLE; i++) {
+			if (obj->pid_array[i].pid != 0)
+				obj_shared_count++;
+		}
+		BUG_ON(obj_shared_count == 0);
+		DRM_DEBUG("Obj: %p, shared count =%d\n",
+				&obj->base, obj_shared_count);
+
+		if (obj_shared_count > 1)
+			stats->NumofShared++;
+		else
+			stats->NumofPrivate++;
+	} else {
+		obj_shared_count = 1;
+		stats->NumofPrivate++;
+	}
+
+	num_pages = i915_gem_obj_shmem_pages_alloced(obj);
+	if (obj->stolen) {
+		stats->NumofStolen++;
+		stats->StolenSpaceAllocated += obj->base.size;
+	} else if (obj->madv == __I915_MADV_PURGED) {
+		stats->NumofPurged++;
+	} else {
+		if (obj->madv == I915_MADV_DONTNEED) {
+			stats->NumofPurgeable++;
+			stats->PhysicalSpacePurgeable += num_pages*PAGE_SIZE;
+		}
+		if (num_pages > 0)
+			stats->NumofAllocated++;
+
+		if (obj_shared_count > 1) {
+			stats->PhysicalSpaceAllocatedShared +=
+					num_pages*PAGE_SIZE;
+			stats->PhysicalSpaceSharedProportion +=
+				(num_pages*PAGE_SIZE)/obj_shared_count;
+		} else
+			stats->PhysicalSpaceAllocatedPriv +=
+					num_pages*PAGE_SIZE;
+	}
+
+	return 0;
+}
+
+int i915_get_drm_clients_info(struct drm_i915_error_state_buf *m,
+			struct drm_device *dev)
+{
+	struct drm_file *file;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	struct name_entry *entry, *next;
+	struct pid_stat_entry *pid_entry, *temp_entry;
+	int total_shared_prop_space = 0, total_priv_space = 0;
+
+	INIT_LIST_HEAD(&per_pid_stats);
+
+	err_printf(m, "\n\n  pid   Total  Shared  Priv   Purgeable  Alloced  SharedPHYsize   SharedPHYprop    PrivPHYsize   PurgeablePHYsize   process\n");
+
+	mutex_lock(&dev->struct_mutex);
+	list_for_each_entry(file, &dev->filelist, lhead) {
+
+		struct per_file_obj_mem_info *stats;
+		struct pid_stat_entry *pid_entry;
+		struct pid *pid = file->pid;
+		int pid_nr = pid->numbers[pid->level].nr;
+		struct drm_i915_file_private *file_priv = file->driver_priv;
+		int found = 0;
+
+		list_for_each_entry(pid_entry, &per_pid_stats, head) {
+			if (pid_entry->pid_nr == pid_nr) {
+				found = 1;
+				break;
+			}
+		}
+
+		if (!found) {
+			struct pid_stat_entry *new_entry =
+			kzalloc(sizeof(struct pid_stat_entry), GFP_KERNEL);
+
+			if (new_entry == NULL) {
+				DRM_ERROR("alloc failed\n");
+				return -ENOMEM;
+			}
+			new_entry->pid = pid;
+			new_entry->pid_nr = pid_nr;
+			list_add_tail(&new_entry->head, &per_pid_stats);
+			drm_ht_create(&new_entry->namelist,
+					DRM_MAGIC_HASH_ORDER);
+			INIT_LIST_HEAD(&new_entry->namefree);
+			new_entry->stats.process_name = file_priv->process_name;
+			pid_entry = new_entry;
+		}
+
+		idr_for_each(&file->object_idr,
+			&i915_drm_gem_object_per_file_summary, pid_entry);
+	}
+
+	list_for_each_entry_safe(pid_entry, temp_entry, &per_pid_stats, head) {
+		struct task_struct *task =
+			get_pid_task(pid_entry->pid, PIDTYPE_PID);
+
+		err_printf(m, "%5d %6d %6d %6d %9d %8d %14zdK %14zdK %14zdK  %14zdK     %s",
+			   pid_entry->pid_nr,
+			   pid_entry->stats.NumofObjects,
+			   pid_entry->stats.NumofShared,
+			   pid_entry->stats.NumofPrivate,
+			   pid_entry->stats.NumofPurgeable,
+			   pid_entry->stats.NumofAllocated,
+			   pid_entry->stats.PhysicalSpaceAllocatedShared/1024,
+			   pid_entry->stats.PhysicalSpaceSharedProportion/1024,
+			   pid_entry->stats.PhysicalSpaceAllocatedPriv/1024,
+			   pid_entry->stats.PhysicalSpacePurgeable/1024,
+			   pid_entry->stats.process_name);
+
+		if (task == NULL)
+			err_printf(m, "*\n");
+		else
+			err_printf(m, "\n");
+
+		total_shared_prop_space +=
+			pid_entry->stats.PhysicalSpaceSharedProportion/1024;
+		total_priv_space +=
+			pid_entry->stats.PhysicalSpaceAllocatedPriv/1024;
+		list_del(&pid_entry->head);
+
+		list_for_each_entry_safe(entry, next,
+				&pid_entry->namefree, head) {
+			list_del(&entry->head);
+			drm_ht_remove_item(&pid_entry->namelist,
+				&entry->hash_item);
+			kfree(entry);
+		}
+		drm_ht_remove(&pid_entry->namelist);
+		kfree(pid_entry);
+	}
+
+	err_printf(m, "\t\t\t\t\t\t\t\t--------------\t-------------\t--------\n");
+	err_printf(m, "\t\t\t\t\t\t\t\t%13zdK\t%12zdK\tTotal\n",
+			total_shared_prop_space, total_priv_space);
+
+	mutex_unlock(&dev->struct_mutex);
+
+	if (m->bytes == 0 && m->err)
+		return m->err;
+
+	return 0;
+}
+
+int i915_gem_get_all_obj_info(struct drm_i915_error_state_buf *m,
+				struct drm_device *dev)
+{
+	struct drm_file *file;
+	int ret;
+
+	mutex_lock(&dev->struct_mutex);
+	list_for_each_entry(file, &dev->filelist, lhead) {
+		struct pid *pid = file->pid;
+		int pid_nr = pid->numbers[pid->level].nr;
+		struct drm_i915_file_private *file_priv = file->driver_priv;
+
+		err_printf(m, "\n\n  PID  process\n");
+
+		err_printf(m, "%5d  %s\n",
+			   pid_nr, file_priv->process_name);
+
+		err_printf(m, "\n Obj Identifier        Size Pin Tiling Dirty Shared Vmap Stolen Mappable  AllocState Global/PP  GttOffset PIDs\n");
+		ret = idr_for_each(&file->object_idr,
+				&i915_drm_gem_obj_info, m);
+		if (ret)
+			break;
+	}
+	mutex_unlock(&dev->struct_mutex);
+
+	if (ret)
+		return ret;
+	if (m->bytes == 0 && m->err)
+		return m->err;
+
+	return 0;
+}
+
diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c
index 21c025a..1650253 100644
--- a/drivers/gpu/drm/i915/i915_gem_stolen.c
+++ b/drivers/gpu/drm/i915/i915_gem_stolen.c
@@ -353,6 +353,8 @@ i915_pages_create_for_stolen(struct drm_device *dev,
 	sg_dma_address(sg) = (dma_addr_t)dev_priv->mm.stolen_base + offset;
 	sg_dma_len(sg) = size;
 
+	dev_priv->mm.stolen_phys_mem_total += size;
+
 	return st;
 }
 
diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c
index fc11ac6..fbecf96 100644
--- a/drivers/gpu/drm/i915/i915_gpu_error.c
+++ b/drivers/gpu/drm/i915/i915_gpu_error.c
@@ -161,7 +161,7 @@ static void i915_error_vprintf(struct drm_i915_error_state_buf *e,
 	__i915_error_advance(e, len);
 }
 
-static void i915_error_puts(struct drm_i915_error_state_buf *e,
+void i915_error_puts(struct drm_i915_error_state_buf *e,
 			    const char *str)
 {
 	unsigned len;
diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c
index ae7fd8f..fc17ad7 100644
--- a/drivers/gpu/drm/i915/i915_sysfs.c
+++ b/drivers/gpu/drm/i915/i915_sysfs.c
@@ -582,6 +582,86 @@ static ssize_t error_state_write(struct file *file, struct kobject *kobj,
 	return count;
 }
 
+static ssize_t i915_gem_clients_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 = dev_to_drm_minor(kdev);
+	struct drm_device *dev = minor->dev;
+	struct drm_i915_error_state_buf error_str;
+	ssize_t ret_count = 0;
+	int ret;
+
+	ret = i915_error_state_buf_init(&error_str, count, off);
+	if (ret)
+		return ret;
+
+	ret = i915_get_drm_clients_info(&error_str, dev);
+	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_buf_release(&error_str);
+
+	return ret ?: ret_count;
+}
+
+static ssize_t i915_gem_clients_state_write(struct file *file,
+				struct kobject *kobj,
+				struct bin_attribute *attr, char *buf,
+				loff_t off, size_t count)
+{
+	/* Nothing to do*/
+
+	return count;
+}
+
+static ssize_t i915_gem_objects_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 = dev_to_drm_minor(kdev);
+	struct drm_device *dev = minor->dev;
+	struct drm_i915_error_state_buf error_str;
+	ssize_t ret_count = 0;
+	int ret;
+
+	ret = i915_error_state_buf_init(&error_str, count, off);
+	if (ret)
+		return ret;
+
+	ret = i915_gem_get_all_obj_info(&error_str, dev);
+	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_buf_release(&error_str);
+
+	return ret ?: ret_count;
+}
+
+static ssize_t i915_gem_objects_state_write(struct file *file,
+				struct kobject *kobj,
+				struct bin_attribute *attr, char *buf,
+				loff_t off, size_t count)
+{
+	/* Nothing to do*/
+
+	return count;
+}
+
 static struct bin_attribute error_state_attr = {
 	.attr.name = "error",
 	.attr.mode = S_IRUSR | S_IWUSR,
@@ -590,6 +670,22 @@ static struct bin_attribute error_state_attr = {
 	.write = error_state_write,
 };
 
+static struct bin_attribute i915_gem_client_state_attr = {
+	.attr.name = "i915_gem_meminfo",
+	.attr.mode = S_IRUSR | S_IWUSR,
+	.size = 0,
+	.read = i915_gem_clients_state_read,
+	.write = i915_gem_clients_state_write,
+};
+
+static struct bin_attribute i915_gem_objects_state_attr = {
+	.attr.name = "i915_gem_objinfo",
+	.attr.mode = S_IRUSR | S_IWUSR,
+	.size = 0,
+	.read = i915_gem_objects_state_read,
+	.write = i915_gem_objects_state_write,
+};
+
 void i915_setup_sysfs(struct drm_device *dev)
 {
 	int ret;
@@ -627,6 +723,17 @@ void i915_setup_sysfs(struct drm_device *dev)
 				    &error_state_attr);
 	if (ret)
 		DRM_ERROR("error_state sysfs setup failed\n");
+
+	ret = sysfs_create_bin_file(&dev->primary->kdev->kobj,
+				    &i915_gem_client_state_attr);
+	if (ret)
+		DRM_ERROR("i915_gem_client_state sysfs setup failed\n");
+
+	ret = sysfs_create_bin_file(&dev->primary->kdev->kobj,
+				    &i915_gem_objects_state_attr);
+	if (ret)
+		DRM_ERROR("i915_gem_objects_state sysfs setup failed\n");
+
 }
 
 void i915_teardown_sysfs(struct drm_device *dev)
