Skip to content

Commit 75fb60e

Browse files
Jocelyn FalempeMaarten Lankhorst
authored andcommitted
drm/i915: Add intel_bo_panic_setup() and intel_bo_panic_finish()
Implement both functions for i915 and xe, they prepare the work for drm_panic support. They both use kmap_try_from_panic(), and map one page at a time, to write the panic screen on the framebuffer. Signed-off-by: Jocelyn Falempe <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Maarten Lankhorst <[email protected]>
1 parent da091af commit 75fb60e

File tree

5 files changed

+188
-0
lines changed

5 files changed

+188
-0
lines changed

drivers/gpu/drm/i915/display/intel_bo.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// SPDX-License-Identifier: MIT
22
/* Copyright © 2024 Intel Corporation */
33

4+
#include <drm/drm_panic.h>
45
#include "display/intel_display_types.h"
56
#include "gem/i915_gem_mman.h"
67
#include "gem/i915_gem_object.h"
@@ -63,3 +64,13 @@ struct intel_framebuffer *intel_bo_alloc_framebuffer(void)
6364
{
6465
return i915_gem_object_alloc_framebuffer();
6566
}
67+
68+
int intel_bo_panic_setup(struct drm_scanout_buffer *sb)
69+
{
70+
return i915_gem_object_panic_setup(sb);
71+
}
72+
73+
void intel_bo_panic_finish(struct intel_framebuffer *fb)
74+
{
75+
return i915_gem_object_panic_finish(fb);
76+
}

drivers/gpu/drm/i915/display/intel_bo.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <linux/types.h>
88

99
struct drm_gem_object;
10+
struct drm_scanout_buffer;
1011
struct intel_framebuffer;
1112
struct seq_file;
1213
struct vm_area_struct;
@@ -25,5 +26,7 @@ struct intel_frontbuffer *intel_bo_set_frontbuffer(struct drm_gem_object *obj,
2526

2627
void intel_bo_describe(struct seq_file *m, struct drm_gem_object *obj);
2728
struct intel_framebuffer *intel_bo_alloc_framebuffer(void);
29+
int intel_bo_panic_setup(struct drm_scanout_buffer *sb);
30+
void intel_bo_panic_finish(struct intel_framebuffer *fb);
2831

2932
#endif /* __INTEL_BO__ */

drivers/gpu/drm/i915/gem/i915_gem_object.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "i915_gem_ww.h"
1717
#include "i915_vma_types.h"
1818

19+
struct drm_scanout_buffer;
1920
enum intel_region_id;
2021
struct intel_framebuffer;
2122

@@ -693,6 +694,9 @@ int __i915_gem_object_put_pages(struct drm_i915_gem_object *obj);
693694
int i915_gem_object_truncate(struct drm_i915_gem_object *obj);
694695

695696
struct intel_framebuffer *i915_gem_object_alloc_framebuffer(void);
697+
int i915_gem_object_panic_setup(struct drm_scanout_buffer *sb);
698+
void i915_gem_object_panic_finish(struct intel_framebuffer *fb);
699+
696700
/**
697701
* i915_gem_object_pin_map - return a contiguous mapping of the entire object
698702
* @obj: the object to map into kernel address space

drivers/gpu/drm/i915/gem/i915_gem_pages.c

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44
*/
55

66
#include <drm/drm_cache.h>
7+
#include <drm/drm_panic.h>
78
#include <linux/vmalloc.h>
89

10+
#include "display/intel_fb.h"
911
#include "display/intel_display_types.h"
1012
#include "gt/intel_gt.h"
1113
#include "gt/intel_tlb.h"
@@ -366,6 +368,67 @@ struct i915_framebuffer {
366368
struct i915_panic_data panic;
367369
};
368370

371+
static inline struct i915_panic_data *to_i915_panic_data(struct intel_framebuffer *fb)
372+
{
373+
return &container_of_const(fb, struct i915_framebuffer, base)->panic;
374+
}
375+
376+
static void i915_panic_kunmap(struct i915_panic_data *panic)
377+
{
378+
if (panic->vaddr) {
379+
drm_clflush_virt_range(panic->vaddr, PAGE_SIZE);
380+
kunmap_local(panic->vaddr);
381+
panic->vaddr = NULL;
382+
}
383+
}
384+
385+
static struct page **i915_gem_object_panic_pages(struct drm_i915_gem_object *obj)
386+
{
387+
unsigned long n_pages = obj->base.size >> PAGE_SHIFT, i;
388+
struct page *page;
389+
struct page **pages;
390+
struct sgt_iter iter;
391+
392+
/* For a 3840x2160 32 bits Framebuffer, this should require ~64K */
393+
pages = kmalloc_array(n_pages, sizeof(*pages), GFP_ATOMIC);
394+
if (!pages)
395+
return NULL;
396+
397+
i = 0;
398+
for_each_sgt_page(page, iter, obj->mm.pages)
399+
pages[i++] = page;
400+
return pages;
401+
}
402+
403+
/*
404+
* The scanout buffer pages are not mapped, so for each pixel,
405+
* use kmap_local_page_try_from_panic() to map the page, and write the pixel.
406+
* Try to keep the map from the previous pixel, to avoid too much map/unmap.
407+
*/
408+
static void i915_gem_object_panic_page_set_pixel(struct drm_scanout_buffer *sb, unsigned int x,
409+
unsigned int y, u32 color)
410+
{
411+
unsigned int new_page;
412+
unsigned int offset;
413+
struct intel_framebuffer *fb = (struct intel_framebuffer *)sb->private;
414+
struct i915_panic_data *panic = to_i915_panic_data(fb);
415+
416+
offset = y * sb->pitch[0] + x * sb->format->cpp[0];
417+
418+
new_page = offset >> PAGE_SHIFT;
419+
offset = offset % PAGE_SIZE;
420+
if (new_page != panic->page) {
421+
i915_panic_kunmap(panic);
422+
panic->page = new_page;
423+
panic->vaddr =
424+
kmap_local_page_try_from_panic(panic->pages[panic->page]);
425+
}
426+
if (panic->vaddr) {
427+
u32 *pix = panic->vaddr + offset;
428+
*pix = color;
429+
}
430+
}
431+
369432
struct intel_framebuffer *i915_gem_object_alloc_framebuffer(void)
370433
{
371434
struct i915_framebuffer *i915_fb;
@@ -376,6 +439,49 @@ struct intel_framebuffer *i915_gem_object_alloc_framebuffer(void)
376439
return NULL;
377440
}
378441

442+
/*
443+
* Setup the gem framebuffer for drm_panic access.
444+
* Use current vaddr if it exists, or setup a list of pages.
445+
* pfn is not supported yet.
446+
*/
447+
int i915_gem_object_panic_setup(struct drm_scanout_buffer *sb)
448+
{
449+
enum i915_map_type has_type;
450+
struct intel_framebuffer *fb = (struct intel_framebuffer *)sb->private;
451+
struct i915_panic_data *panic = to_i915_panic_data(fb);
452+
struct drm_i915_gem_object *obj = to_intel_bo(intel_fb_bo(&fb->base));
453+
void *ptr;
454+
455+
ptr = page_unpack_bits(obj->mm.mapping, &has_type);
456+
if (ptr) {
457+
if (i915_gem_object_has_iomem(obj))
458+
iosys_map_set_vaddr_iomem(&sb->map[0], (void __iomem *)ptr);
459+
else
460+
iosys_map_set_vaddr(&sb->map[0], ptr);
461+
462+
return 0;
463+
}
464+
if (i915_gem_object_has_struct_page(obj)) {
465+
panic->pages = i915_gem_object_panic_pages(obj);
466+
if (!panic->pages)
467+
return -ENOMEM;
468+
panic->page = -1;
469+
sb->set_pixel = i915_gem_object_panic_page_set_pixel;
470+
return 0;
471+
}
472+
return -EOPNOTSUPP;
473+
}
474+
475+
void i915_gem_object_panic_finish(struct intel_framebuffer *fb)
476+
{
477+
struct i915_panic_data *panic = to_i915_panic_data(fb);
478+
479+
i915_panic_kunmap(panic);
480+
panic->page = -1;
481+
kfree(panic->pages);
482+
panic->pages = NULL;
483+
}
484+
379485
/* get, pin, and map the pages of the object into kernel space */
380486
void *i915_gem_object_pin_map(struct drm_i915_gem_object *obj,
381487
enum i915_map_type type)

drivers/gpu/drm/xe/display/intel_bo.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
// SPDX-License-Identifier: MIT
22
/* Copyright © 2024 Intel Corporation */
33

4+
#include <drm/drm_cache.h>
45
#include <drm/drm_gem.h>
6+
#include <drm/drm_panic.h>
57

8+
#include "intel_fb.h"
69
#include "intel_display_types.h"
710

811
#include "xe_bo.h"
@@ -73,6 +76,50 @@ struct xe_framebuffer {
7376
struct xe_panic_data panic;
7477
};
7578

79+
static inline struct xe_panic_data *to_xe_panic_data(struct intel_framebuffer *fb)
80+
{
81+
return &container_of_const(fb, struct xe_framebuffer, base)->panic;
82+
}
83+
84+
static void xe_panic_kunmap(struct xe_panic_data *panic)
85+
{
86+
if (panic->vaddr) {
87+
drm_clflush_virt_range(panic->vaddr, PAGE_SIZE);
88+
kunmap_local(panic->vaddr);
89+
panic->vaddr = NULL;
90+
}
91+
}
92+
93+
/*
94+
* The scanout buffer pages are not mapped, so for each pixel,
95+
* use kmap_local_page_try_from_panic() to map the page, and write the pixel.
96+
* Try to keep the map from the previous pixel, to avoid too much map/unmap.
97+
*/
98+
static void xe_panic_page_set_pixel(struct drm_scanout_buffer *sb, unsigned int x,
99+
unsigned int y, u32 color)
100+
{
101+
struct intel_framebuffer *fb = (struct intel_framebuffer *)sb->private;
102+
struct xe_panic_data *panic = to_xe_panic_data(fb);
103+
struct xe_bo *bo = gem_to_xe_bo(intel_fb_bo(&fb->base));
104+
unsigned int new_page;
105+
unsigned int offset;
106+
107+
offset = y * sb->pitch[0] + x * sb->format->cpp[0];
108+
109+
new_page = offset >> PAGE_SHIFT;
110+
offset = offset % PAGE_SIZE;
111+
if (new_page != panic->page) {
112+
xe_panic_kunmap(panic);
113+
panic->page = new_page;
114+
panic->vaddr = ttm_bo_kmap_try_from_panic(&bo->ttm,
115+
panic->page);
116+
}
117+
if (panic->vaddr) {
118+
u32 *pix = panic->vaddr + offset;
119+
*pix = color;
120+
}
121+
}
122+
76123
struct intel_framebuffer *intel_bo_alloc_framebuffer(void)
77124
{
78125
struct xe_framebuffer *xe_fb;
@@ -83,3 +130,20 @@ struct intel_framebuffer *intel_bo_alloc_framebuffer(void)
83130
return NULL;
84131
}
85132

133+
int intel_bo_panic_setup(struct drm_scanout_buffer *sb)
134+
{
135+
struct intel_framebuffer *fb = (struct intel_framebuffer *)sb->private;
136+
struct xe_panic_data *panic = to_xe_panic_data(fb);
137+
138+
panic->page = -1;
139+
sb->set_pixel = xe_panic_page_set_pixel;
140+
return 0;
141+
}
142+
143+
void intel_bo_panic_finish(struct intel_framebuffer *fb)
144+
{
145+
struct xe_panic_data *panic = to_xe_panic_data(fb);
146+
147+
xe_panic_kunmap(panic);
148+
panic->page = -1;
149+
}

0 commit comments

Comments
 (0)