summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/qxl/qxl_debugfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/qxl/qxl_debugfs.c')
-rw-r--r--drivers/gpu/drm/qxl/qxl_debugfs.c439
1 files changed, 439 insertions, 0 deletions
diff --git a/drivers/gpu/drm/qxl/qxl_debugfs.c b/drivers/gpu/drm/qxl/qxl_debugfs.c
new file mode 100644
index 00000000000..6b71e7aec93
--- /dev/null
+++ b/drivers/gpu/drm/qxl/qxl_debugfs.c
@@ -0,0 +1,439 @@
+/*
+ * Copyright (C) 2009 Red Hat <bskeggs@redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/*
+ * Authors:
+ * Alon Levy <alevy@redhat.com>
+ */
+
+#include <linux/debugfs.h>
+
+#include "drmP.h"
+#include "qxl_drv.h"
+#include "qxl_object.h"
+
+int qxl_log_level;
+int qxl_debug_disable_fb;
+
+static void ppm_save(int width, int height, int bytes_per_pixel, int line_size,
+ int bits_per_pixel, uint8_t *d1, struct seq_file *m)
+{
+ uint8_t *d;
+ uint32_t v;
+ int y, x;
+ uint8_t r, g, b;
+ int ret;
+ char *linebuf, *pbuf;
+ int rshift = 16;
+ int gshift = 8;
+ int bshift = 0;
+ int rmax = 255;
+ int gmax = 255;
+ int bmax = 255;
+
+ DRM_INFO("%s: hwd %d,%d,%d bpp %d line %d\n", __func__,
+ height, width, bytes_per_pixel, bits_per_pixel, line_size);
+ seq_printf(m, "P6\n%d %d\n%d\n", width, height, 255);
+ linebuf = kmalloc(width * 3, GFP_KERNEL);
+ for (y = 0; y < height; y++) {
+ d = d1;
+ pbuf = linebuf;
+ for (x = 0; x < width; x++) {
+ if (bits_per_pixel == 32)
+ v = *(uint32_t *)d;
+ else
+ v = (uint32_t) (*(uint16_t *)d);
+ r = ((v >> rshift) & rmax) * 256 / (rmax + 1);
+ g = ((v >> gshift) & gmax) * 256 / (gmax + 1);
+ b = ((v >> bshift) & bmax) * 256 / (bmax + 1);
+ *pbuf++ = r;
+ *pbuf++ = g;
+ *pbuf++ = b;
+ d += bytes_per_pixel;
+ }
+ d1 += line_size;
+ ret = seq_write(m, linebuf, pbuf - linebuf);
+ }
+ kfree(linebuf);
+}
+
+static void ppm_save_qxl_fb(struct qxl_framebuffer *qxl_fb, struct seq_file *m)
+{
+ struct qxl_bo *qobj = gem_to_qxl_bo(qxl_fb->obj);
+ int width = qxl_fb->base.width;
+ int height = qxl_fb->base.height;
+ int bytes_per_pixel = qxl_fb->base.bits_per_pixel / 8;
+ int line_size = qxl_fb->base.pitches[0];
+ int bits_per_pixel = qxl_fb->base.bits_per_pixel;
+ uint8_t *d1 = qobj->kptr;
+
+ ppm_save(width, height, bytes_per_pixel, line_size, bits_per_pixel,
+ d1, m);
+}
+
+static int
+qxl_debugfs_dumbppm(struct seq_file *m, void *data)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct qxl_device *qdev = node->minor->dev->dev_private;
+ struct qxl_rect area;
+
+ if (qdev->active_user_framebuffer) {
+ ppm_save_qxl_fb(qdev->active_user_framebuffer, m);
+ } else if (qdev->fbdev_qfb) {
+ area.top = area.left = 0;
+ area.right = qdev->fbdev_qfb->base.width;
+ area.bottom = qdev->fbdev_qfb->base.height;
+ qxl_io_update_area(qdev, 0, &area);
+ ppm_save_qxl_fb(qdev->fbdev_qfb, m);
+ }
+ return 0;
+}
+
+struct release_idr_data {
+ struct seq_file *m;
+ int total_bo;
+};
+
+static int idr_iter_fn(int id, void *p, void *data)
+{
+ struct release_idr_data *release_data = data;
+ struct seq_file *m = release_data->m;
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct qxl_device *qdev = node->minor->dev->dev_private;
+ struct drm_qxl_release *release = qxl_release_from_id_locked(qdev, id);
+
+ seq_printf(m, "%d, type %d bo %d\n", id, release->type,
+ release->bo_count);
+ release_data->total_bo += release->bo_count;
+ return 0;
+}
+
+static int
+qxl_debugfs_release(struct seq_file *m, void *data)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct qxl_device *qdev = node->minor->dev->dev_private;
+ struct qxl_ring_header *r = &qdev->ram_header->release_ring_hdr;
+ struct release_idr_data idr_data;
+
+ idr_data.m = m;
+ idr_data.total_bo = 0;
+ mutex_lock(&qdev->release_idr_mutex);
+ idr_for_each(&qdev->release_idr, idr_iter_fn, &idr_data);
+ mutex_unlock(&qdev->release_idr_mutex);
+ seq_printf(m, "ring %d [%d,%d] (%d,%d)\n", r->num_items, r->prod,
+ r->cons, r->notify_on_prod, r->notify_on_cons);
+ seq_printf(m, "collected %d, release bo's %d / %d ttm\n",
+ qxl_garbage_collect(qdev),
+ idr_data.total_bo,
+ atomic_read(&qdev->mman.bdev.glob->bo_count));
+ return 0;
+}
+
+#define DRAW_WIDTH 256
+#define DRAW_HEIGHT 96
+static uint32_t draw_data[DRAW_WIDTH * DRAW_HEIGHT];
+static int draw_line;
+
+static void
+qxl_debugfs_draw_depth(struct seq_file *m, void *data, int depth,
+ uint32_t *palette, int workqueue)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct qxl_device *qdev = node->minor->dev->dev_private;
+ struct qxl_fb_image qxl_fb_image;
+ struct fb_image *image = &qxl_fb_image.fb_image;
+ uint32_t stride = DRAW_WIDTH * depth / 32;
+ uint32_t *p = &draw_data[draw_line * stride];
+ int i;
+ static int color_ind;
+ int fg[] = {0xaaaaaa, 0xff55ff, 0xddff33};
+
+ draw_line = (draw_line + 1) % DRAW_HEIGHT;
+
+ for (i = 0 ; i < stride; ++i, ++p)
+ *p = ~*p;
+ qxl_fb_image.qdev = qdev;
+ qxl_fb_image.visual = FB_VISUAL_DIRECTCOLOR;
+ image->dx = 300;
+ image->dy = 100;
+ image->width = DRAW_WIDTH;
+ image->height = DRAW_HEIGHT;
+ image->depth = depth;
+ image->data = (char *)draw_data;
+ if (depth == 1) {
+ if (palette) {
+ memcpy(qxl_fb_image.pseudo_palette, palette,
+ sizeof(qxl_fb_image.pseudo_palette));
+ image->fg_color = 1;
+ image->bg_color = 0;
+ } else {
+ qxl_fb_image.visual = FB_VISUAL_MONO10;
+ image->fg_color = fg[color_ind];
+ image->bg_color = 0;
+ }
+ color_ind = (color_ind + 1) % (sizeof(fg) / sizeof(fg[0]));
+ }
+ if (workqueue)
+ qxl_fb_queue_imageblit(qdev, &qxl_fb_image, NULL, NULL);
+ else
+ qxl_draw_opaque_fb(&qxl_fb_image, 0);
+}
+
+static int
+qxl_debugfs_draw_32(struct seq_file *m, void *data)
+{
+ qxl_debugfs_draw_depth(m, data, 32, NULL, 0);
+ return 0;
+}
+
+static int
+qxl_debugfs_draw_1(struct seq_file *m, void *data)
+{
+ qxl_debugfs_draw_depth(m, data, 1, NULL, 0);
+ return 0;
+}
+
+static int
+qxl_debugfs_oom(struct seq_file *m, void *data)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct qxl_device *qdev = node->minor->dev->dev_private;
+
+ qxl_io_notify_oom(qdev);
+ return 0;
+}
+
+static int
+qxl_debugfs_debug_enable(struct seq_file *m, void *data)
+{
+ qxl_log_level = 2;
+ return 0;
+}
+
+static int
+qxl_debugfs_debug_disable(struct seq_file *m, void *data)
+{
+ qxl_log_level = 0;
+ return 0;
+}
+
+static int gem_idr_iter_fn(int id, void *p, void *data)
+{
+ ++*(int *)data;
+ return 0;
+}
+
+static int
+qxl_debugfs_mem(struct seq_file *m, void *data)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct qxl_device *qdev = node->minor->dev->dev_private;
+ int gem_count = 0;
+
+ seq_printf(m, "ttm bo count %d\n",
+ atomic_read(&qdev->mman.bdev.glob->bo_count));
+ gem_count = 0;
+ spin_lock(&qdev->ddev->object_name_lock);
+ idr_for_each(&qdev->ddev->object_name_idr, gem_idr_iter_fn, &gem_count);
+ spin_unlock(&qdev->ddev->object_name_lock);
+ seq_printf(m, "gem object_name count %d\n", gem_count);
+ return 0;
+}
+
+/* test new bo and free of bo */
+static int
+qxl_debugfs_bo_test(struct seq_file *m, void *data)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct qxl_device *qdev = node->minor->dev->dev_private;
+ struct qxl_bo *bo;
+ int ret;
+
+ ret = qxl_bo_create(qdev, 8192, false /* not kernel, device */,
+ QXL_GEM_DOMAIN_VRAM, &bo);
+ if (unlikely(ret != 0)) {
+ seq_printf(m, "failed to create bo of 8192 bytes\n");
+ return 0;
+ }
+ /* TODO - pin test as well. qxl_allocnf test generally. */
+ qxl_bo_free(bo);
+ return 0;
+}
+
+/* test new idr and release of idr */
+static int
+qxl_debugfs_alloc_test(struct seq_file *m, void *data)
+{
+ seq_printf(m, "implement me\n");
+ return 0;
+}
+
+static int
+qxl_debugfs_fb_wq_image(struct seq_file *m, void *data)
+{
+ uint32_t palette[16] = {0, 0xffffff, 0};
+ qxl_debugfs_draw_depth(m, data, 1, palette, 1);
+ return 0;
+}
+
+static void
+set_rect(struct qxl_rect *r, int top, int left, int bottom, int right)
+{
+ r->top = top;
+ r->left = left;
+ r->bottom = bottom;
+ r->right = right;
+}
+
+static int
+qxl_debugfs_fb_wq_fill(struct seq_file *m, void *data)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct qxl_device *qdev = node->minor->dev->dev_private;
+ struct qxl_draw_fill qxl_draw_fill_rec;
+
+ qxl_draw_fill_rec.qdev = qdev;
+ set_rect(&qxl_draw_fill_rec.rect, 100, 100, 200, 400);
+ qxl_draw_fill_rec.color = 0x00ff0000;
+ qxl_draw_fill_rec.rop = SPICE_ROPD_OP_PUT;
+ qxl_fb_queue_draw_fill(&qxl_draw_fill_rec);
+ return 0;
+}
+
+
+static int
+qxl_debugfs_fb_enable(struct seq_file *m, void *data)
+{
+ qxl_debug_disable_fb = 0;
+ return 0;
+}
+
+static int
+qxl_debugfs_fb_disable(struct seq_file *m, void *data)
+{
+ qxl_debug_disable_fb = 1;
+ return 0;
+}
+
+static int
+qxl_debugfs_irq_received(struct seq_file *m, void *data)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct qxl_device *qdev = node->minor->dev->dev_private;
+
+ seq_printf(m, "%d\n", atomic_read(&qdev->irq_received));
+ seq_printf(m, "%d\n", atomic_read(&qdev->irq_received_display));
+ seq_printf(m, "%d\n", atomic_read(&qdev->irq_received_cursor));
+ seq_printf(m, "%d\n", atomic_read(&qdev->irq_received_io_cmd));
+ seq_printf(m, "%d\n", qdev->irq_received_error);
+ return 0;
+}
+
+static int
+qxl_debugfs_read_client_monitors_config(struct seq_file *m, void *data)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct qxl_device *qdev = node->minor->dev->dev_private;
+
+ qxl_display_read_client_monitors_config(qdev);
+ return 0;
+}
+
+static int
+qxl_debugfs_set_monitors_config(struct seq_file *m, int width, int height)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct qxl_device *qdev = node->minor->dev->dev_private;
+
+ qxl_alloc_client_monitors_config(qdev, 1);
+ if (!qdev->client_monitors_config) {
+ qxl_io_log(qdev, "%s: no memory\n", __func__);
+ return 0;
+ }
+
+ qdev->monitors_config->count = 1;
+ qdev->monitors_config->heads[0].width = width;
+ qdev->monitors_config->heads[0].height = height;
+ qdev->monitors_config->heads[0].x = 0;
+ qdev->monitors_config->heads[0].y = 0;
+ qxl_crtc_set_from_monitors_config(qdev);
+ qxl_send_monitors_config(qdev);
+ drm_sysfs_hotplug_event(qdev->ddev);
+ return 0;
+}
+
+static int
+qxl_debugfs_set_monitor_924_668(struct seq_file *m, void *data)
+{
+ return qxl_debugfs_set_monitors_config(m, 924, 668);
+}
+
+static int
+qxl_debugfs_set_monitor_820_620(struct seq_file *m, void *data)
+{
+ return qxl_debugfs_set_monitors_config(m, 820, 620);
+}
+
+static struct drm_info_list qxl_debugfs_list[] = {
+ { "dumbppm", qxl_debugfs_dumbppm, 0, NULL },
+ { "release", qxl_debugfs_release, 0, NULL },
+ { "draw32", qxl_debugfs_draw_32, 0, NULL },
+ { "draw1", qxl_debugfs_draw_1, 0, NULL },
+ { "oom", qxl_debugfs_oom, 0, NULL },
+ { "mem", qxl_debugfs_mem, 0, NULL },
+ { "bo_test", qxl_debugfs_bo_test, 0, NULL },
+ { "alloc_test", qxl_debugfs_alloc_test, 0, NULL },
+ { "fb_wq_image", qxl_debugfs_fb_wq_image, 0, NULL },
+ { "fb_wq_fill", qxl_debugfs_fb_wq_fill, 0, NULL },
+ { "read_client_monitors_config",
+ qxl_debugfs_read_client_monitors_config, 0, NULL },
+ { "mon_924_668", qxl_debugfs_set_monitor_924_668, 0, NULL },
+ { "mon_820_620", qxl_debugfs_set_monitor_820_620, 0, NULL },
+ /* TODO: read int from user; echo debug_level > *
+ * /sys/kernel/debugfs/dri/0/debug */
+ { "debug_enable", qxl_debugfs_debug_enable, 0, NULL },
+ { "debug_disable", qxl_debugfs_debug_disable, 0, NULL },
+ { "fb_enable", qxl_debugfs_fb_enable, 0, NULL },
+ { "fb_disable", qxl_debugfs_fb_disable, 0, NULL },
+ { "irq_received", qxl_debugfs_irq_received, 0, NULL },
+};
+#define NOUVEAU_DEBUGFS_ENTRIES ARRAY_SIZE(qxl_debugfs_list)
+
+int
+qxl_debugfs_init(struct drm_minor *minor)
+{
+ drm_debugfs_create_files(qxl_debugfs_list, NOUVEAU_DEBUGFS_ENTRIES,
+ minor->debugfs_root, minor);
+ return 0;
+}
+
+void
+qxl_debugfs_takedown(struct drm_minor *minor)
+{
+ drm_debugfs_remove_files(qxl_debugfs_list, NOUVEAU_DEBUGFS_ENTRIES,
+ minor);
+}