[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250908141152.221291-2-ryasuoka@redhat.com>
Date: Mon, 8 Sep 2025 23:11:34 +0900
From: Ryosuke Yasuoka <ryasuoka@...hat.com>
To: zack.rusin@...adcom.com,
maarten.lankhorst@...ux.intel.com,
mripard@...nel.org,
tzimmermann@...e.de,
airlied@...il.com,
simona@...ll.ch,
ian.forbes@...adcom.com,
jfalempe@...hat.com
Cc: Ryosuke Yasuoka <ryasuoka@...hat.com>,
bcm-kernel-feedback-list@...adcom.com,
linux-kernel@...r.kernel.org,
dri-devel@...ts.freedesktop.org
Subject: [PATCH drm-misc-next v2 1/1] drm/vmwgfx: add drm_panic support for stdu
Add drm_panic module for vmwgfx stdu so that panic screen can be
displayed on panic.
Signed-off-by: Ryosuke Yasuoka <ryasuoka@...hat.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
Powered by blists - more mailing lists