]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/gpu/drm/drm_framebuffer.c
Merge airlied/drm-next into drm-misc-next
[linux.git] / drivers / gpu / drm / drm_framebuffer.c
index 279c1035c12dadf30794a89209084e8617058dec..d63d4c2ac4c8126e8d38cdcc32638893cb1fcfb2 100644 (file)
@@ -25,7 +25,9 @@
 #include <drm/drm_auth.h>
 #include <drm/drm_framebuffer.h>
 #include <drm/drm_atomic.h>
+#include <drm/drm_print.h>
 
+#include "drm_internal.h"
 #include "drm_crtc_internal.h"
 
 /**
@@ -78,11 +80,12 @@ int drm_framebuffer_check_src_coords(uint32_t src_x, uint32_t src_y,
            src_h > fb_height ||
            src_y > fb_height - src_h) {
                DRM_DEBUG_KMS("Invalid source coordinates "
-                             "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n",
+                             "%u.%06ux%u.%06u+%u.%06u+%u.%06u (fb %ux%u)\n",
                              src_w >> 16, ((src_w & 0xffff) * 15625) >> 10,
                              src_h >> 16, ((src_h & 0xffff) * 15625) >> 10,
                              src_x >> 16, ((src_x & 0xffff) * 15625) >> 10,
-                             src_y >> 16, ((src_y & 0xffff) * 15625) >> 10);
+                             src_y >> 16, ((src_y & 0xffff) * 15625) >> 10,
+                             fb->width, fb->height);
                return -ENOSPC;
        }
 
@@ -766,14 +769,18 @@ static int atomic_remove_fb(struct drm_framebuffer *fb)
        struct drm_plane *plane;
        struct drm_connector *conn;
        struct drm_connector_state *conn_state;
-       int i, ret = 0;
+       int i, ret;
        unsigned plane_mask;
+       bool disable_crtcs = false;
 
-       state = drm_atomic_state_alloc(dev);
-       if (!state)
-               return -ENOMEM;
-
+retry_disable:
        drm_modeset_acquire_init(&ctx, 0);
+
+       state = drm_atomic_state_alloc(dev);
+       if (!state) {
+               ret = -ENOMEM;
+               goto out;
+       }
        state->acquire_ctx = &ctx;
 
 retry:
@@ -794,7 +801,7 @@ static int atomic_remove_fb(struct drm_framebuffer *fb)
                        goto unlock;
                }
 
-               if (plane_state->crtc->primary == plane) {
+               if (disable_crtcs && plane_state->crtc->primary == plane) {
                        struct drm_crtc_state *crtc_state;
 
                        crtc_state = drm_atomic_get_existing_crtc_state(state, plane_state->crtc);
@@ -819,6 +826,7 @@ static int atomic_remove_fb(struct drm_framebuffer *fb)
                plane->old_fb = plane->fb;
        }
 
+       /* This list is only filled when disable_crtcs is set. */
        for_each_new_connector_in_state(state, conn, conn_state, i) {
                ret = drm_atomic_set_crtc_for_connector(conn_state, NULL);
 
@@ -841,9 +849,15 @@ static int atomic_remove_fb(struct drm_framebuffer *fb)
 
        drm_atomic_state_put(state);
 
+out:
        drm_modeset_drop_locks(&ctx);
        drm_modeset_acquire_fini(&ctx);
 
+       if (ret == -EINVAL && !disable_crtcs) {
+               disable_crtcs = true;
+               goto retry_disable;
+       }
+
        return ret;
 }
 
@@ -957,3 +971,60 @@ int drm_framebuffer_plane_height(int height,
        return fb_plane_height(height, fb->format, plane);
 }
 EXPORT_SYMBOL(drm_framebuffer_plane_height);
+
+void drm_framebuffer_print_info(struct drm_printer *p, unsigned int indent,
+                               const struct drm_framebuffer *fb)
+{
+       struct drm_format_name_buf format_name;
+       unsigned int i;
+
+       drm_printf_indent(p, indent, "refcount=%u\n",
+                         drm_framebuffer_read_refcount(fb));
+       drm_printf_indent(p, indent, "format=%s\n",
+                         drm_get_format_name(fb->format->format, &format_name));
+       drm_printf_indent(p, indent, "modifier=0x%llx\n", fb->modifier);
+       drm_printf_indent(p, indent, "size=%ux%u\n", fb->width, fb->height);
+       drm_printf_indent(p, indent, "layers:\n");
+
+       for (i = 0; i < fb->format->num_planes; i++) {
+               drm_printf_indent(p, indent + 1, "size[%u]=%dx%d\n", i,
+                                 drm_framebuffer_plane_width(fb->width, fb, i),
+                                 drm_framebuffer_plane_height(fb->height, fb, i));
+               drm_printf_indent(p, indent + 1, "pitch[%u]=%u\n", i, fb->pitches[i]);
+               drm_printf_indent(p, indent + 1, "offset[%u]=%u\n", i, fb->offsets[i]);
+               drm_printf_indent(p, indent + 1, "obj[%u]:%s\n", i,
+                                 fb->obj[i] ? "" : "(null)");
+               if (fb->obj[i])
+                       drm_gem_print_info(p, indent + 2, fb->obj[i]);
+       }
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int drm_framebuffer_info(struct seq_file *m, void *data)
+{
+       struct drm_info_node *node = m->private;
+       struct drm_device *dev = node->minor->dev;
+       struct drm_printer p = drm_seq_file_printer(m);
+       struct drm_framebuffer *fb;
+
+       mutex_lock(&dev->mode_config.fb_lock);
+       drm_for_each_fb(fb, dev) {
+               drm_printf(&p, "framebuffer[%u]:\n", fb->base.id);
+               drm_framebuffer_print_info(&p, 1, fb);
+       }
+       mutex_unlock(&dev->mode_config.fb_lock);
+
+       return 0;
+}
+
+static const struct drm_info_list drm_framebuffer_debugfs_list[] = {
+       { "framebuffer", drm_framebuffer_info, 0 },
+};
+
+int drm_framebuffer_debugfs_init(struct drm_minor *minor)
+{
+       return drm_debugfs_create_files(drm_framebuffer_debugfs_list,
+                               ARRAY_SIZE(drm_framebuffer_debugfs_list),
+                               minor->debugfs_root, minor);
+}
+#endif