mirror of
https://github.com/torvalds/linux.git
synced 2026-10-16 12:50:02 +02:00
Store tiling function pointer in struct intel_panic instead of struct intel_framebuffer, and store struct intel_panic pointer instead of struct intel_framebuffer pointer in struct drm_scanout_buffer private member. To make this happen, pass the tiling function pointer to panic setup hook, and initialize sb->private in the hook for clarity. This allows us to drop the dependency on struct intel_framebuffer from i915 and xe panic code. Note: It would be less verbose to have a typedef for the tiling function pointer. However, there isn't a nice location for it that wouldn't also increase header interdependencies. Cc: Jocelyn Falempe <jfalempe@redhat.com> Reviewed-by: Jocelyn Falempe <jfalempe@redhat.com> Link: https://patch.msgid.link/d97abae79db3437c617cd4cb6193ba017b3a8d78.1780394867.git.jani.nikula@intel.com Signed-off-by: Jani Nikula <jani.nikula@intel.com>
148 lines
3.7 KiB
C
148 lines
3.7 KiB
C
// SPDX-License-Identifier: MIT
|
|
/* Copyright © 2026 Intel Corporation */
|
|
|
|
#include <drm/drm_cache.h>
|
|
#include <drm/drm_panic.h>
|
|
#include <drm/intel/display_parent_interface.h>
|
|
|
|
#include "i915_gem_object.h"
|
|
#include "i915_gem_panic.h"
|
|
|
|
struct intel_panic {
|
|
struct page **pages;
|
|
int page;
|
|
void *vaddr;
|
|
|
|
unsigned int (*tiling)(unsigned int x, unsigned int y, unsigned int width);
|
|
};
|
|
|
|
static void i915_panic_kunmap(struct intel_panic *panic)
|
|
{
|
|
if (panic->vaddr) {
|
|
drm_clflush_virt_range(panic->vaddr, PAGE_SIZE);
|
|
kunmap_local(panic->vaddr);
|
|
panic->vaddr = NULL;
|
|
}
|
|
}
|
|
|
|
static struct page **i915_gem_object_panic_pages(struct drm_i915_gem_object *obj)
|
|
{
|
|
unsigned long n_pages = obj->base.size >> PAGE_SHIFT, i;
|
|
struct page *page;
|
|
struct page **pages;
|
|
struct sgt_iter iter;
|
|
|
|
/* For a 3840x2160 32 bits Framebuffer, this should require ~64K */
|
|
pages = kmalloc_objs(*pages, n_pages, GFP_ATOMIC);
|
|
if (!pages)
|
|
return NULL;
|
|
|
|
i = 0;
|
|
for_each_sgt_page(page, iter, obj->mm.pages)
|
|
pages[i++] = page;
|
|
return pages;
|
|
}
|
|
|
|
static void i915_gem_object_panic_map_set_pixel(struct drm_scanout_buffer *sb, unsigned int x,
|
|
unsigned int y, u32 color)
|
|
{
|
|
struct intel_panic *panic = sb->private;
|
|
unsigned int offset = panic->tiling(sb->width, x, y);
|
|
|
|
iosys_map_wr(&sb->map[0], offset, u32, color);
|
|
}
|
|
|
|
/*
|
|
* The scanout buffer pages are not mapped, so for each pixel,
|
|
* use kmap_local_page_try_from_panic() to map the page, and write the pixel.
|
|
* Try to keep the map from the previous pixel, to avoid too much map/unmap.
|
|
*/
|
|
static void i915_gem_object_panic_page_set_pixel(struct drm_scanout_buffer *sb, unsigned int x,
|
|
unsigned int y, u32 color)
|
|
{
|
|
struct intel_panic *panic = sb->private;
|
|
unsigned int new_page;
|
|
unsigned int offset;
|
|
|
|
if (panic->tiling)
|
|
offset = panic->tiling(sb->width, x, y);
|
|
else
|
|
offset = y * sb->pitch[0] + x * sb->format->cpp[0];
|
|
|
|
new_page = offset >> PAGE_SHIFT;
|
|
offset = offset % PAGE_SIZE;
|
|
if (new_page != panic->page) {
|
|
i915_panic_kunmap(panic);
|
|
panic->page = new_page;
|
|
panic->vaddr =
|
|
kmap_local_page_try_from_panic(panic->pages[panic->page]);
|
|
}
|
|
if (panic->vaddr) {
|
|
u32 *pix = panic->vaddr + offset;
|
|
*pix = color;
|
|
}
|
|
}
|
|
|
|
static struct intel_panic *i915_gem_object_alloc_panic(void)
|
|
{
|
|
struct intel_panic *panic;
|
|
|
|
panic = kzalloc_obj(*panic);
|
|
|
|
return panic;
|
|
}
|
|
|
|
/*
|
|
* Setup the gem framebuffer for drm_panic access.
|
|
* Use current vaddr if it exists, or setup a list of pages.
|
|
* pfn is not supported yet.
|
|
*/
|
|
static int i915_gem_object_panic_setup(struct intel_panic *panic, struct drm_scanout_buffer *sb,
|
|
struct drm_gem_object *_obj,
|
|
unsigned int (*tiling)(unsigned int x, unsigned int y, unsigned int width))
|
|
{
|
|
enum i915_map_type has_type;
|
|
struct drm_i915_gem_object *obj = to_intel_bo(_obj);
|
|
void *ptr;
|
|
|
|
sb->private = panic;
|
|
|
|
ptr = page_unpack_bits(obj->mm.mapping, &has_type);
|
|
if (ptr) {
|
|
if (i915_gem_object_has_iomem(obj))
|
|
iosys_map_set_vaddr_iomem(&sb->map[0], (void __iomem *)ptr);
|
|
else
|
|
iosys_map_set_vaddr(&sb->map[0], ptr);
|
|
|
|
if (tiling) {
|
|
panic->tiling = tiling;
|
|
sb->set_pixel = i915_gem_object_panic_map_set_pixel;
|
|
}
|
|
return 0;
|
|
}
|
|
if (i915_gem_object_has_struct_page(obj)) {
|
|
panic->pages = i915_gem_object_panic_pages(obj);
|
|
if (!panic->pages)
|
|
return -ENOMEM;
|
|
panic->page = -1;
|
|
panic->tiling = tiling;
|
|
sb->set_pixel = i915_gem_object_panic_page_set_pixel;
|
|
return 0;
|
|
}
|
|
return -EOPNOTSUPP;
|
|
}
|
|
|
|
static void i915_gem_object_panic_finish(struct intel_panic *panic)
|
|
{
|
|
i915_panic_kunmap(panic);
|
|
panic->page = -1;
|
|
kfree(panic->pages);
|
|
panic->pages = NULL;
|
|
}
|
|
|
|
const struct intel_display_panic_interface i915_display_panic_interface = {
|
|
.alloc = i915_gem_object_alloc_panic,
|
|
.setup = i915_gem_object_panic_setup,
|
|
.finish = i915_gem_object_panic_finish,
|
|
};
|