Add drm_panic module for vmwgfx stdu so that panic screen can be
displayed on panic.

Signed-off-by: Ryosuke Yasuoka <ryasu...@redhat.com>
---
 drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c  | 73 ++++++++++++++++++++++++++++
 drivers/gpu/drm/vmwgfx/vmwgfx_drv.h  | 18 +++++++
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.c  |  9 ++++
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.h  |  1 +
 drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c  | 43 ++++++++++++++++
 drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 34 +++++++++++++
 6 files changed, 178 insertions(+)

diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c 
b/drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c
index 8fe02131a6c4..fe6275a6cc31 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c
@@ -156,6 +156,16 @@ struct vmw_fifo_state *vmw_fifo_create(struct vmw_private 
*dev_priv)
        return fifo;
 }
 
+/* For drm_panic */
+void vmw_panic_fifo_ping_host(struct vmw_private *dev_priv, uint32_t reason)
+{
+       u32 *fifo_mem = dev_priv->fifo_mem;
+
+       if (fifo_mem && cmpxchg(fifo_mem + SVGA_FIFO_BUSY, 0, 1) == 0)
+               vmw_panic_write(dev_priv, SVGA_REG_SYNC, reason);
+
+}
+
 void vmw_fifo_ping_host(struct vmw_private *dev_priv, uint32_t reason)
 {
        u32 *fifo_mem = dev_priv->fifo_mem;
@@ -264,6 +274,46 @@ static int vmw_fifo_wait(struct vmw_private *dev_priv,
        return ret;
 }
 
+/* For drm_panic */
+void *vmw_panic_fifo_reserve(struct vmw_private *dev_priv, uint32_t bytes)
+{
+       struct vmw_fifo_state *fifo_state = dev_priv->fifo;
+       u32  *fifo_mem = dev_priv->fifo_mem;
+       uint32_t reserveable = fifo_state->capabilities & SVGA_FIFO_CAP_RESERVE;
+
+       /*
+        * Access to fifo registers without mutex lock because it is only 
called is
+        * panic handler
+        */
+       uint32_t max = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_MAX);
+       uint32_t min = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_MIN);
+       uint32_t stop = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_STOP);
+       uint32_t next_cmd = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_NEXT_CMD);
+
+       if (unlikely(bytes >= (max - min)))
+               return NULL;
+
+       bool has_space;
+
+       if (next_cmd >= stop) {
+               has_space = (next_cmd + bytes < max ||
+                            (next_cmd + bytes == max && stop > min));
+       } else {
+               has_space = (next_cmd + bytes < stop);
+       }
+
+       if (unlikely(!has_space || (!reserveable && bytes > sizeof(uint32_t))))
+               return NULL;
+
+       fifo_state->reserved_size = bytes;
+       fifo_state->using_bounce_buffer = false;
+
+       if (reserveable)
+               vmw_fifo_mem_write(dev_priv, SVGA_FIFO_RESERVED, bytes);
+
+       return (void __force *) (fifo_mem + (next_cmd >> 2));
+}
+
 /*
  * Reserve @bytes number of bytes in the fifo.
  *
@@ -424,6 +474,29 @@ static void vmw_fifo_slow_copy(struct vmw_fifo_state 
*fifo_state,
        }
 }
 
+/* For drm_panic */
+void vmw_panic_fifo_commit(struct vmw_private *dev_priv, uint32_t bytes)
+{
+       struct vmw_fifo_state *fifo_state = dev_priv->fifo;
+       uint32_t next_cmd = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_NEXT_CMD);
+       uint32_t max = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_MAX);
+       uint32_t min = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_MIN);
+       bool reserveable = fifo_state->capabilities & SVGA_FIFO_CAP_RESERVE;
+
+       fifo_state->reserved_size = 0;
+
+       if (reserveable) {
+               next_cmd += bytes;
+               if (next_cmd >= max)
+                       next_cmd -= max - min;
+               mb();
+               vmw_fifo_mem_write(dev_priv, SVGA_FIFO_NEXT_CMD, next_cmd);
+               vmw_fifo_mem_write(dev_priv, SVGA_FIFO_RESERVED, 0);
+       }
+       mb();
+       vmw_panic_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC);
+}
+
 static void vmw_local_fifo_commit(struct vmw_private *dev_priv, uint32_t bytes)
 {
        struct vmw_fifo_state *fifo_state = dev_priv->fifo;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h 
b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index eda5b6f8f4c4..a1dc6d63c079 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -635,6 +635,17 @@ static inline bool vmw_is_svga_v3(const struct vmw_private 
*dev)
        return dev->pci_id == VMWGFX_PCI_ID_SVGA3;
 }
 
+/*
+ * For drm_panic
+ * Lockless vmw_write() because drm_panic calls this in panic handler
+ */
+static inline void vmw_panic_write(struct vmw_private *dev_priv,
+                                  unsigned int offset, uint32_t value)
+{
+       outl(offset, dev_priv->io_start + SVGA_INDEX_PORT);
+       outl(value, dev_priv->io_start + SVGA_VALUE_PORT);
+}
+
 /*
  * The locking here is fine-grained, so that it is performed once
  * for every read- and write operation. This is of course costly, but we
@@ -854,16 +865,19 @@ extern void vmw_fifo_destroy(struct vmw_private 
*dev_priv);
 extern bool vmw_cmd_supported(struct vmw_private *vmw);
 extern void *
 vmw_cmd_ctx_reserve(struct vmw_private *dev_priv, uint32_t bytes, int ctx_id);
+extern void vmw_panic_fifo_commit(struct vmw_private *dev_priv, uint32_t 
bytes);
 extern void vmw_cmd_commit(struct vmw_private *dev_priv, uint32_t bytes);
 extern void vmw_cmd_commit_flush(struct vmw_private *dev_priv, uint32_t bytes);
 extern int vmw_cmd_send_fence(struct vmw_private *dev_priv, uint32_t *seqno);
 extern bool vmw_supports_3d(struct vmw_private *dev_priv);
+extern void vmw_panic_fifo_ping_host(struct vmw_private *dev_priv, uint32_t 
reason);
 extern void vmw_fifo_ping_host(struct vmw_private *dev_priv, uint32_t reason);
 extern bool vmw_fifo_have_pitchlock(struct vmw_private *dev_priv);
 extern int vmw_cmd_emit_dummy_query(struct vmw_private *dev_priv,
                                    uint32_t cid);
 extern int vmw_cmd_flush(struct vmw_private *dev_priv,
                         bool interruptible);
+extern void *vmw_panic_fifo_reserve(struct vmw_private *dev_priv, uint32_t 
bytes);
 
 #define VMW_CMD_CTX_RESERVE(__priv, __bytes, __ctx_id)                        \
 ({                                                                            \
@@ -1027,6 +1041,8 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
                          struct ttm_object_file *tfile,
                          struct ttm_buffer_object *bo,
                          SVGA3dCmdHeader *header);
+void vmw_kms_panic_write_svga(struct vmw_private *vmw_priv,
+                             unsigned int width, unsigned int height, unsigned 
int pitch);
 int vmw_kms_write_svga(struct vmw_private *vmw_priv,
                       unsigned width, unsigned height, unsigned pitch,
                       unsigned bpp, unsigned depth);
@@ -1349,6 +1365,8 @@ int vmw_mksstat_remove_ioctl(struct drm_device *dev, void 
*data,
                      struct drm_file *file_priv);
 int vmw_mksstat_remove_all(struct vmw_private *dev_priv);
 
+void vmw_ldu_primary_plane_panic_flush(struct drm_plane *plane);
+
 /* VMW logging */
 
 /**
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c 
b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 54ea1b513950..89d04d6be83e 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -1203,6 +1203,15 @@ int vmw_kms_close(struct vmw_private *dev_priv)
        return ret;
 }
 
+/* For drm_panic */
+void vmw_kms_panic_write_svga(struct vmw_private *vmw_priv,
+                             unsigned int width, unsigned int height, unsigned 
int pitch)
+{
+       vmw_panic_write(vmw_priv, SVGA_REG_PITCHLOCK, pitch);
+       vmw_panic_write(vmw_priv, SVGA_REG_WIDTH, width);
+       vmw_panic_write(vmw_priv, SVGA_REG_HEIGHT, height);
+}
+
 int vmw_kms_write_svga(struct vmw_private *vmw_priv,
                        unsigned width, unsigned height, unsigned pitch,
                        unsigned bpp, unsigned depth)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h 
b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
index 445471fe9be6..e6299390ffea 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
@@ -499,6 +499,7 @@ int vmw_kms_stdu_readback(struct vmw_private *dev_priv,
                          struct drm_crtc *crtc);
 
 int vmw_du_helper_plane_update(struct vmw_du_update_plane *update);
+int vmw_du_panic_helper_plane_update(struct vmw_du_update_plane *update);
 
 /**
  * vmw_du_translate_to_crtc - Translate a rect from framebuffer to crtc
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c 
b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
index c23c9195f0dc..b7c3dfbab541 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
@@ -304,6 +304,49 @@ static int vmw_kms_ldu_do_bo_dirty(struct vmw_private 
*dev_priv,
                                   struct drm_mode_rect *clips,
                                   unsigned int num_clips);
 
+/* For drm_panic */
+static int vmw_kms_ldu_panic_do_bo_dirty(struct vmw_private *dev_priv,
+                                        struct drm_framebuffer *fb)
+{
+       size_t fifo_size;
+       struct {
+               uint32_t header;
+               SVGAFifoCmdUpdate body;
+       } *cmd;
+
+       fifo_size = sizeof(*cmd);
+       cmd = vmw_panic_fifo_reserve(dev_priv, fifo_size);
+       if (IS_ERR_OR_NULL(cmd))
+               return -ENOMEM;
+
+       memset(cmd, 0, fifo_size);
+
+       cmd[0].header = SVGA_CMD_UPDATE;
+       cmd[0].body.x = 0;
+       cmd[0].body.y = 0;
+       cmd[0].body.width = fb->width;
+       cmd[0].body.height = fb->height;
+
+       vmw_panic_fifo_commit(dev_priv, fifo_size);
+       return 0;
+}
+
+/* For drm_panic */
+void vmw_ldu_primary_plane_panic_flush(struct drm_plane *plane)
+{
+       struct drm_plane_state *state = plane->state;
+       struct drm_crtc *crtc = state->crtc;
+       struct vmw_private *dev_priv = vmw_priv(crtc->dev);
+       struct drm_framebuffer *fb = state->fb;
+       int ret;
+
+       vmw_kms_panic_write_svga(dev_priv, fb->width, fb->height, 
fb->pitches[0]);
+
+       ret = vmw_kms_ldu_panic_do_bo_dirty(dev_priv, fb);
+       if (ret)
+               pr_warn("Failed to vmw_kms_ldu_panic_do_bo_dirty\n");
+}
+
 /*
  * Legacy Display Plane Functions
  */
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c 
b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
index 20aab725e53a..faa7135bd699 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
@@ -36,6 +36,7 @@
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_damage_helper.h>
 #include <drm/drm_fourcc.h>
+#include <drm/drm_panic.h>
 #include <drm/drm_vblank.h>
 
 #define vmw_crtc_to_stdu(x) \
@@ -1458,6 +1459,37 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane 
*plane,
                vmw_fence_obj_unreference(&fence);
 }
 
+static int
+vmw_stdu_primary_plane_get_scanout_buffer(struct drm_plane *plane,
+                                         struct drm_scanout_buffer *sb)
+{
+       struct drm_plane_state *state = plane->state;
+       struct drm_crtc *crtc = state->crtc;
+       struct vmw_private *dev_priv = vmw_priv(crtc->dev);
+
+       if (!plane->state || !plane->state->fb || !plane->state->visible)
+               return -ENODEV;
+
+       sb->format = plane->state->fb->format;
+       sb->width = plane->state->fb->width;
+       sb->height = plane->state->fb->height;
+       sb->pitch[0] = plane->state->fb->pitches[0];
+
+       u64 size = sb->height * sb->pitch[0];
+
+       sb->map[0].vaddr = memremap(dev_priv->vram_start, size, MEMREMAP_WT);
+
+       if (!sb->map[0].vaddr)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static void vmw_stdu_primary_plane_panic_flush(struct drm_plane *plane)
+{
+       vmw_ldu_primary_plane_panic_flush(plane);
+}
+
 static void
 vmw_stdu_crtc_atomic_flush(struct drm_crtc *crtc,
                           struct drm_atomic_state *state)
@@ -1506,6 +1538,8 @@ drm_plane_helper_funcs 
vmw_stdu_primary_plane_helper_funcs = {
        .atomic_update = vmw_stdu_primary_plane_atomic_update,
        .prepare_fb = vmw_stdu_primary_plane_prepare_fb,
        .cleanup_fb = vmw_stdu_primary_plane_cleanup_fb,
+       .get_scanout_buffer = vmw_stdu_primary_plane_get_scanout_buffer,
+       .panic_flush = vmw_stdu_primary_plane_panic_flush,
 };
 
 static const struct drm_crtc_helper_funcs vmw_stdu_crtc_helper_funcs = {
-- 
2.51.0

Reply via email to