Commit edc3d884 authored by Mika Kuoppala's avatar Mika Kuoppala Committed by Daniel Vetter

drm/i915: avoid big kmallocs on reading error state

Sometimes when user is trying to get error state out from
debugfs after gpu hang, the memory is low and/or fragmented
enough that kmalloc in seq_file will fail.

Prevent big kmalloc by avoiding seq_file and instead convert
error state to string in smaller chunks.

v2: better alloc flags, better truncate, correct
locking, and error handling improvements (Chris Wilson)

v3: printf annotations (Daniel Vetter)
Signed-off-by: default avatarMika Kuoppala <mika.kuoppala@intel.com>
Reviewed-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent 03973536
This diff is collapsed.
...@@ -826,6 +826,15 @@ struct i915_gem_mm { ...@@ -826,6 +826,15 @@ struct i915_gem_mm {
u32 object_count; u32 object_count;
}; };
struct drm_i915_error_state_buf {
unsigned bytes;
unsigned size;
int err;
u8 *buf;
loff_t start;
loff_t pos;
};
struct i915_gpu_error { struct i915_gpu_error {
/* For hangcheck timer */ /* For hangcheck timer */
#define DRM_I915_HANGCHECK_PERIOD 1500 /* in ms */ #define DRM_I915_HANGCHECK_PERIOD 1500 /* in ms */
...@@ -1818,6 +1827,8 @@ void i915_gem_dump_object(struct drm_i915_gem_object *obj, int len, ...@@ -1818,6 +1827,8 @@ void i915_gem_dump_object(struct drm_i915_gem_object *obj, int len,
/* i915_debugfs.c */ /* i915_debugfs.c */
int i915_debugfs_init(struct drm_minor *minor); int i915_debugfs_init(struct drm_minor *minor);
void i915_debugfs_cleanup(struct drm_minor *minor); void i915_debugfs_cleanup(struct drm_minor *minor);
__printf(2, 3)
void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...);
/* i915_suspend.c */ /* i915_suspend.c */
extern int i915_save_state(struct drm_device *dev); extern int i915_save_state(struct drm_device *dev);
...@@ -1899,10 +1910,11 @@ int i915_reg_read_ioctl(struct drm_device *dev, void *data, ...@@ -1899,10 +1910,11 @@ int i915_reg_read_ioctl(struct drm_device *dev, void *data,
/* overlay */ /* overlay */
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev); extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev);
extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_state *error); extern void intel_overlay_print_error_state(struct drm_i915_error_state_buf *e,
struct intel_overlay_error_state *error);
extern struct intel_display_error_state *intel_display_capture_error_state(struct drm_device *dev); extern struct intel_display_error_state *intel_display_capture_error_state(struct drm_device *dev);
extern void intel_display_print_error_state(struct seq_file *m, extern void intel_display_print_error_state(struct drm_i915_error_state_buf *e,
struct drm_device *dev, struct drm_device *dev,
struct intel_display_error_state *error); struct intel_display_error_state *error);
#endif #endif
......
...@@ -9858,48 +9858,50 @@ intel_display_capture_error_state(struct drm_device *dev) ...@@ -9858,48 +9858,50 @@ intel_display_capture_error_state(struct drm_device *dev)
return error; return error;
} }
#define err_printf(e, ...) i915_error_printf(e, __VA_ARGS__)
void void
intel_display_print_error_state(struct seq_file *m, intel_display_print_error_state(struct drm_i915_error_state_buf *m,
struct drm_device *dev, struct drm_device *dev,
struct intel_display_error_state *error) struct intel_display_error_state *error)
{ {
int i; int i;
seq_printf(m, "Num Pipes: %d\n", INTEL_INFO(dev)->num_pipes); err_printf(m, "Num Pipes: %d\n", INTEL_INFO(dev)->num_pipes);
if (HAS_POWER_WELL(dev)) if (HAS_POWER_WELL(dev))
seq_printf(m, "PWR_WELL_CTL2: %08x\n", err_printf(m, "PWR_WELL_CTL2: %08x\n",
error->power_well_driver); error->power_well_driver);
for_each_pipe(i) { for_each_pipe(i) {
seq_printf(m, "Pipe [%d]:\n", i); err_printf(m, "Pipe [%d]:\n", i);
seq_printf(m, " CPU transcoder: %c\n", err_printf(m, " CPU transcoder: %c\n",
transcoder_name(error->pipe[i].cpu_transcoder)); transcoder_name(error->pipe[i].cpu_transcoder));
seq_printf(m, " CONF: %08x\n", error->pipe[i].conf); err_printf(m, " CONF: %08x\n", error->pipe[i].conf);
seq_printf(m, " SRC: %08x\n", error->pipe[i].source); err_printf(m, " SRC: %08x\n", error->pipe[i].source);
seq_printf(m, " HTOTAL: %08x\n", error->pipe[i].htotal); err_printf(m, " HTOTAL: %08x\n", error->pipe[i].htotal);
seq_printf(m, " HBLANK: %08x\n", error->pipe[i].hblank); err_printf(m, " HBLANK: %08x\n", error->pipe[i].hblank);
seq_printf(m, " HSYNC: %08x\n", error->pipe[i].hsync); err_printf(m, " HSYNC: %08x\n", error->pipe[i].hsync);
seq_printf(m, " VTOTAL: %08x\n", error->pipe[i].vtotal); err_printf(m, " VTOTAL: %08x\n", error->pipe[i].vtotal);
seq_printf(m, " VBLANK: %08x\n", error->pipe[i].vblank); err_printf(m, " VBLANK: %08x\n", error->pipe[i].vblank);
seq_printf(m, " VSYNC: %08x\n", error->pipe[i].vsync); err_printf(m, " VSYNC: %08x\n", error->pipe[i].vsync);
seq_printf(m, "Plane [%d]:\n", i); err_printf(m, "Plane [%d]:\n", i);
seq_printf(m, " CNTR: %08x\n", error->plane[i].control); err_printf(m, " CNTR: %08x\n", error->plane[i].control);
seq_printf(m, " STRIDE: %08x\n", error->plane[i].stride); err_printf(m, " STRIDE: %08x\n", error->plane[i].stride);
if (INTEL_INFO(dev)->gen <= 3) { if (INTEL_INFO(dev)->gen <= 3) {
seq_printf(m, " SIZE: %08x\n", error->plane[i].size); err_printf(m, " SIZE: %08x\n", error->plane[i].size);
seq_printf(m, " POS: %08x\n", error->plane[i].pos); err_printf(m, " POS: %08x\n", error->plane[i].pos);
} }
if (INTEL_INFO(dev)->gen <= 7 && !IS_HASWELL(dev)) if (INTEL_INFO(dev)->gen <= 7 && !IS_HASWELL(dev))
seq_printf(m, " ADDR: %08x\n", error->plane[i].addr); err_printf(m, " ADDR: %08x\n", error->plane[i].addr);
if (INTEL_INFO(dev)->gen >= 4) { if (INTEL_INFO(dev)->gen >= 4) {
seq_printf(m, " SURF: %08x\n", error->plane[i].surface); err_printf(m, " SURF: %08x\n", error->plane[i].surface);
seq_printf(m, " TILEOFF: %08x\n", error->plane[i].tile_offset); err_printf(m, " TILEOFF: %08x\n", error->plane[i].tile_offset);
} }
seq_printf(m, "Cursor [%d]:\n", i); err_printf(m, "Cursor [%d]:\n", i);
seq_printf(m, " CNTR: %08x\n", error->cursor[i].control); err_printf(m, " CNTR: %08x\n", error->cursor[i].control);
seq_printf(m, " POS: %08x\n", error->cursor[i].position); err_printf(m, " POS: %08x\n", error->cursor[i].position);
seq_printf(m, " BASE: %08x\n", error->cursor[i].base); err_printf(m, " BASE: %08x\n", error->cursor[i].base);
} }
} }
#endif #endif
...@@ -1485,14 +1485,15 @@ intel_overlay_capture_error_state(struct drm_device *dev) ...@@ -1485,14 +1485,15 @@ intel_overlay_capture_error_state(struct drm_device *dev)
} }
void void
intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_state *error) intel_overlay_print_error_state(struct drm_i915_error_state_buf *m,
struct intel_overlay_error_state *error)
{ {
seq_printf(m, "Overlay, status: 0x%08x, interrupt: 0x%08x\n", i915_error_printf(m, "Overlay, status: 0x%08x, interrupt: 0x%08x\n",
error->dovsta, error->isr); error->dovsta, error->isr);
seq_printf(m, " Register file at 0x%08lx:\n", i915_error_printf(m, " Register file at 0x%08lx:\n",
error->base); error->base);
#define P(x) seq_printf(m, " " #x ": 0x%08x\n", error->regs.x) #define P(x) i915_error_printf(m, " " #x ": 0x%08x\n", error->regs.x)
P(OBUF_0Y); P(OBUF_0Y);
P(OBUF_1Y); P(OBUF_1Y);
P(OBUF_0U); P(OBUF_0U);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment